1
#if !defined(__linux__)
2
#error "Linux platform file is part of non-Linux build."
3
#endif
4

            
5
#include "source/server/options_impl_platform_linux.h"
6

            
7
#include <sched.h>
8

            
9
#include <thread>
10

            
11
#include "source/common/api/os_sys_calls_impl_linux.h"
12
#include "source/common/filesystem/filesystem_impl.h"
13
#include "source/server/cgroup_cpu_util.h"
14
#include "source/server/options_impl_platform.h"
15

            
16
#include "absl/strings/ascii.h"
17

            
18
namespace Envoy {
19

            
20
14
uint32_t OptionsImplPlatformLinux::getCpuAffinityCount(unsigned int hw_threads) {
21
14
  unsigned int threads = 0;
22
14
  pid_t pid = getpid();
23
14
  cpu_set_t mask;
24
14
  auto& linux_os_syscalls = Api::LinuxOsSysCallsSingleton::get();
25

            
26
14
  CPU_ZERO(&mask);
27
14
  const Api::SysCallIntResult result =
28
14
      linux_os_syscalls.sched_getaffinity(pid, sizeof(cpu_set_t), &mask);
29
14
  if (result.return_value_ == -1) {
30
    // Fall back to number of hardware threads.
31
1
    return hw_threads;
32
1
  }
33

            
34
13
  threads = CPU_COUNT(&mask);
35

            
36
  // Sanity check.
37
13
  if (threads > 0 && threads <= hw_threads) {
38
12
    return threads;
39
12
  }
40

            
41
1
  return hw_threads;
42
13
}
43

            
44
10
uint32_t OptionsImplPlatform::getCpuCount() {
45
10
  unsigned int hw_threads = std::max(1U, std::thread::hardware_concurrency());
46
10
  uint32_t affinity_count = OptionsImplPlatformLinux::getCpuAffinityCount(hw_threads);
47

            
48
10
  uint32_t cgroup_limit = hw_threads; // Fallback to hardware threads if `cgroup` detection fails
49

            
50
  // Check environment variable for cgroup detection (safe during early startup)
51
10
  const char* env_value = std::getenv("ENVOY_CGROUP_CPU_DETECTION");
52
10
  bool enable_cgroup_detection = true; // Default: enabled
53

            
54
10
  if (env_value != nullptr) {
55
3
    std::string value = absl::AsciiStrToLower(env_value);
56
3
    enable_cgroup_detection = (value != "false");
57
3
  }
58

            
59
10
  if (enable_cgroup_detection) {
60
9
    Filesystem::InstanceImpl fs;
61
9
    auto& detector = CgroupDetectorSingleton::get();
62
9
    absl::optional<uint32_t> detected_limit = detector.getCpuLimit(fs);
63
9
    if (detected_limit.has_value()) {
64
6
      cgroup_limit = detected_limit.value();
65
6
    }
66
9
  }
67

            
68
10
  uint32_t effective_count = std::min({hw_threads, affinity_count, cgroup_limit});
69
10
  return std::max(1U, effective_count);
70
10
}
71

            
72
} // namespace Envoy