aboutsummaryrefslogblamecommitdiffstats
path: root/util/system/info.cpp
blob: 9b0fbced8581512358a33344a017a11461e52b36 (plain) (tree)
1
2
3
4
5
                 
                  
                








                                         
     











                                                   
                                          
                          

                                           





                              
                                    
                    


                                                                                                     
                                                                                
  
                                   
         
                                                                                                                 



                     
                                                                                                                  



                     
                     




                   








                                                                                    

                                       
                                                  







                                     
                                         



























                                                           
                             

                                                         
                              





















                                             
                                                         









                                                          
                 

                                      
                                  
      











                                          
                          






                                          
 






                                                
                                            

                            
 
                              
                                 
      
 
 
                                       










                                                                                                                      

                         
                       










                                                                          
                    




                                                                                        


             








                                            
#include "info.h"

#include "error.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/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 CgroupCpus() {
    try {
        double q = FromString<int32_t>(StripString(TFileInput("/sys/fs/cgroup/cpu/cpu.cfs_quota_us").ReadAll()));

        if (q <= 0) {
            return 0;
        }

        double p = FromString<int32_t>(StripString(TFileInput("/sys/fs/cgroup/cpu/cpu.cfs_period_us").ReadAll()));

        if (p <= 0) {
            return 0;
        }

        return q / p;
    } catch (...) {
        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
}