#include "info.h"
#include "error.h"
#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/stream/file.h>
#include <util/generic/yexception.h>
#if defined(_linux_)
static inline size_t CgroupCpus() {
try {
auto q = FromString<ssize_t>(StripString(TFileInput("/sys/fs/cgroup/cpu/cpu.cfs_quota_us").ReadAll()));
if (q <= 0) {
return 0;
}
auto p = FromString<ssize_t>(StripString(TFileInput("/sys/fs/cgroup/cpu/cpu.cfs_period_us").ReadAll()));
if (p <= 0) {
return 0;
}
return Max<ssize_t>(1, (q + p / 2) / p);
} catch (...) {
return 0;
}
}
#endif
size_t NSystemInfo::NumberOfCpus() {
#if defined(_linux_)
if (auto res = CgroupCpus(); res) {
return 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;
size_t NSystemInfo::CachedNumberOfCpus() {
if (!NCpus) {
NCpus = NumberOfCpus();
}
return NCpus;
}
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
}