123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- #include "info.h"
- #include "error.h"
- #include "fs.h"
- #include <cmath>
- #include <cstdlib>
- #if defined(_linux_) || defined(_cygwin_)
- #include <fcntl.h>
- #include <sys/sysinfo.h>
- #endif
- #if defined(_win_)
- #include "winint.h"
- #include <stdio.h>
- #else
- #include <unistd.h>
- #endif
- #if defined(_bionic_)
- // TODO
- #elif defined(_cygwin_)
- static int getloadavg(double* loadavg, int nelem) {
- for (int i = 0; i < nelem; ++i) {
- loadavg[i] = 0.0;
- }
- return nelem;
- }
- #elif defined(_unix_) || defined(_darwin_)
- #include <sys/types.h>
- #endif
- #if defined(_freebsd_) || defined(_darwin_)
- #include <sys/sysctl.h>
- #endif
- #include <util/string/ascii.h>
- #include <util/string/cast.h>
- #include <util/string/strip.h>
- #include <util/string/split.h>
- #include <util/stream/file.h>
- #include <util/generic/yexception.h>
- #if defined(_linux_)
- /*
- This function olny works properly if you apply correct setting to your nanny/deploy project
- In nanny - Runtime -> Instance spec -> Advanced settings -> Cgroupfs settings: Mount mode = Read only
- In deploy - Stage - Edit stage - Box - Cgroupfs settings: Mount mode = Read only
- */
- static inline double CgroupV1Cpus(const TString& cpuCfsQuotaUsPath, const TString& cfsPeriodUsPath) {
- try {
- double q = FromString<int32_t>(StripString(TFileInput(cpuCfsQuotaUsPath).ReadAll()));
- if (q <= 0) {
- return 0;
- }
- double p = FromString<int32_t>(StripString(TFileInput(cfsPeriodUsPath).ReadAll()));
- if (p <= 0) {
- return 0;
- }
- return q / p;
- } catch (...) {
- return 0;
- }
- }
- /*
- In cgroups v2 there isn't a dedicated "cpu" directory under /sys/fs/cgroup,
- so the approximation of the number of CPUs may use the cpu.max file.
- The format is the following:
- $MAX $PERIOD
- Which indicates that the group may consume up to $MAX in each $PERIOD duration.
- The "max" value could be either the string "max" or a number. In the first case
- our approximation doesn't work so we can bail out earlier.
- */
- static inline double CgroupV2Cpus(const TString& cpuMaxPath) {
- try {
- TVector<TString> cgroupCpuMax = StringSplitter(TFileInput(cpuMaxPath).ReadAll()).Split(' ').Take(2);
- double max = FromString<int32_t>(StripString(cgroupCpuMax[0]));
- double period = FromString<int32_t>(StripString(cgroupCpuMax[1]));
- if (max <= 0 || period <= 0) {
- return 0;
- }
- return max / period;
- } catch (...) {
- return 0;
- }
- }
- static inline double CgroupCpus() {
- static const TString cpuMaxPath("/sys/fs/cgroup/cpu.max");
- static const TString cpuCfsQuotaUsPath("/sys/fs/cgroup/cpu/cpu.cfs_quota_us");
- static const TString cfsPeriodUsPath("/sys/fs/cgroup/cpu/cpu.cfs_period_us");
- if (NFs::Exists(cpuMaxPath)) {
- auto cgroup2Cpus = CgroupV2Cpus(cpuMaxPath);
- if (cgroup2Cpus > 0) {
- return cgroup2Cpus;
- }
- }
- if (NFs::Exists(cpuCfsQuotaUsPath) && NFs::Exists(cfsPeriodUsPath)) {
- auto cgroups1Cpus = CgroupV1Cpus(cpuCfsQuotaUsPath, cfsPeriodUsPath);
- if (cgroups1Cpus > 0) {
- return cgroups1Cpus;
- }
- }
- return 0;
- }
- #endif
- size_t NSystemInfo::NumberOfMillicores() {
- #if defined(_linux_)
- return CgroupCpus() * 1000;
- #else
- // fallback behaviour if cgroupfs is not available
- // returns number of millicores which is a multiple of an integer number of cpus
- return NSystemInfo::NumberOfCpus() * 1000;
- #endif
- }
- size_t NSystemInfo::NumberOfCpus() {
- #if defined(_linux_)
- if (auto res = CgroupCpus(); res) {
- return Max<ssize_t>(1, std::llround(res));
- }
- #endif
- #if defined(_win_)
- SYSTEM_INFO info;
- GetSystemInfo(&info);
- return info.dwNumberOfProcessors;
- #elif defined(_SC_NPROCESSORS_ONLN)
- return sysconf(_SC_NPROCESSORS_ONLN);
- #elif defined(_linux_)
- unsigned ret;
- int fd, nread, column;
- char buf[512];
- static const char matchstr[] = "processor\t:";
- fd = open("/proc/cpuinfo", O_RDONLY);
- if (fd == -1) {
- abort();
- }
- column = 0;
- ret = 0;
- while (true) {
- nread = read(fd, buf, sizeof(buf));
- if (nread <= 0) {
- break;
- }
- for (int i = 0; i < nread; ++i) {
- const char ch = buf[i];
- if (ch == '\n') {
- column = 0;
- } else if (column != -1) {
- if (AsciiToLower(ch) == matchstr[column]) {
- ++column;
- if (column == sizeof(matchstr) - 1) {
- column = -1;
- ++ret;
- }
- } else {
- column = -1;
- }
- }
- }
- }
- if (ret == 0) {
- abort();
- }
- close(fd);
- return ret;
- #elif defined(_freebsd_) || defined(_darwin_)
- int mib[2];
- size_t len;
- unsigned ncpus = 1;
- mib[0] = CTL_HW;
- mib[1] = HW_NCPU;
- len = sizeof(ncpus);
- if (sysctl(mib, 2, &ncpus, &len, nullptr, 0) == -1) {
- abort();
- }
- return ncpus;
- #else
- #error todo
- #endif
- }
- size_t NSystemInfo::LoadAverage(double* la, size_t len) {
- #if defined(_win_) || defined(_musl_) || defined(_bionic_)
- int ret = -1;
- #else
- for (size_t i = 0; i < len; ++i) {
- la[i] = 0;
- }
- int ret = getloadavg(la, len);
- #endif
- if (ret < 0) {
- for (size_t i = 0; i < len; ++i) {
- la[i] = 0;
- }
- ret = len;
- }
- return (size_t)ret;
- }
- static size_t NCpus;
- static size_t NMillicores;
- size_t NSystemInfo::CachedNumberOfCpus() {
- if (!NCpus) {
- NCpus = NumberOfCpus();
- }
- return NCpus;
- }
- size_t NSystemInfo::CachedNumberOfMillicores() {
- if (!NMillicores) {
- NMillicores = NumberOfMillicores();
- }
- return NMillicores;
- }
- size_t NSystemInfo::GetPageSize() noexcept {
- #if defined(_win_)
- SYSTEM_INFO sysInfo;
- GetSystemInfo(&sysInfo);
- return sysInfo.dwPageSize;
- #else
- return sysconf(_SC_PAGESIZE);
- #endif
- }
- size_t NSystemInfo::TotalMemorySize() {
- #if defined(_linux_) && defined(_64_)
- try {
- auto q = FromString<size_t>(StripString(TFileInput("/sys/fs/cgroup/memory/memory.limit_in_bytes").ReadAll()));
- if (q < (((size_t)1) << 60)) {
- return q;
- }
- } catch (...) {
- }
- #endif
- #if defined(_linux_) || defined(_cygwin_)
- struct sysinfo info;
- sysinfo(&info);
- return info.totalram;
- #elif defined(_darwin_)
- int mib[2];
- int64_t memSize;
- size_t length;
- // Get the Physical memory size
- mib[0] = CTL_HW;
- mib[1] = HW_MEMSIZE;
- length = sizeof(int64_t);
- if (sysctl(mib, 2, &memSize, &length, NULL, 0) != 0) {
- ythrow yexception() << "sysctl failed: " << LastSystemErrorText();
- }
- return (size_t)memSize;
- #elif defined(_win_)
- MEMORYSTATUSEX memoryStatusEx;
- memoryStatusEx.dwLength = sizeof(memoryStatusEx);
- if (!GlobalMemoryStatusEx(&memoryStatusEx)) {
- ythrow yexception() << "GlobalMemoryStatusEx failed: " << LastSystemErrorText();
- }
- return (size_t)memoryStatusEx.ullTotalPhys;
- #else
- return 0;
- #endif
- }
- size_t NSystemInfo::MaxOpenFiles() {
- #if defined(ANDROID) || defined(__ANDROID__)
- return sysconf(_SC_OPEN_MAX);
- #elif defined(_win_)
- return _getmaxstdio();
- #else
- return getdtablesize();
- #endif
- }
|