omni/extras/ContainerHelper.h
File members: omni/extras/ContainerHelper.h
// Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//
#pragma once
#include "../../carb/Defines.h"
#if CARB_PLATFORM_LINUX
#    include <fcntl.h>
#    include <unistd.h>
#endif
namespace omni
{
namespace extras
{
#if CARB_PLATFORM_LINUX || defined(DOXYGEN_BUILD)
#    ifndef DOXYGEN_SHOULD_SKIP_THIS
namespace detail
{
inline int readIntFromFile(const char* file) noexcept
{
    auto fd = ::open(file, O_RDONLY, 0);
    if (fd == -1)
    {
        return -1;
    }
    char buffer[64];
    auto size = CARB_RETRY_EINTR(::read(fd, buffer, sizeof(buffer) - 1));
    ::close(fd);
    if (size <= 0)
    {
        return -1;
    }
    buffer[size] = '\0';
    return std::atoi(buffer);
}
inline bool isRunningInContainer() noexcept
{
    FILE* fp;
    // first (and easiest) check is to check whether the `/.dockerenv` file exists.  This file
    // is not necessarily always present though.
    if (access("/.dockerenv", F_OK) == 0)
    {
        return true;
    }
    // a more reliable but more expensive check is to verify the control group of `init`.  If
    // running under docker, all of the entries will have a path that starts with `/docker` or
    // `/lxc` instead of just `/`.
    fp = fopen("/proc/1/cgroup", "r");
    if (fp != nullptr)
    {
        char line[256];
        while (fgets(line, CARB_COUNTOF(line), fp) != nullptr)
        {
            if (feof(fp) || ferror(fp))
                break;
            if (strstr(line, ":/docker") != nullptr || strstr(line, ":/lxc") != nullptr)
            {
                return true;
            }
        }
        fclose(fp);
    }
    return false;
}
} // namespace detail
#    endif
inline int getDockerCpuLimit() noexcept
{
    // See:
    // https://docs.docker.com/config/containers/resource_constraints/#cpu
    // https://engineering.squarespace.com/blog/2017/understanding-linux-container-scheduling
    const auto cfsQuota = detail::readIntFromFile("/sys/fs/cgroup/cpu/cpu.cfs_quota_us");
    const auto cfsPeriod = detail::readIntFromFile("/sys/fs/cgroup/cpu/cpu.cfs_period_us");
    if (cfsQuota > 0 && cfsPeriod > 0)
    {
        // Since we can have fractional CPUs, round up half a CPU to a whole CPU, but make sure we have an even number.
        return ::carb_max(1, (cfsQuota + (cfsPeriod / 2)) / cfsPeriod);
    }
    return -1;
}
inline bool isRunningInContainer()
{
    static bool s_inContainer = detail::isRunningInContainer();
    return s_inContainer;
}
#else
inline int getDockerCpuLimit() noexcept
{
    return -1;
}
inline bool isRunningInContainer() noexcept
{
    return false;
}
#endif
} // namespace extras
} // namespace omni