| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "../libnetdata.h" |
| 4 | |
| 5 | size_t os_get_system_cpus_cached(bool cache) { |
| 6 | static size_t processors = 0; |
| 7 | |
| 8 | if(likely(cache && processors > 0)) |
| 9 | return processors; |
| 10 | |
| 11 | SPINLOCK spinlock = SPINLOCK_INITIALIZER; |
| 12 | spinlock_lock(&spinlock); |
| 13 | |
| 14 | long p = 0; |
| 15 | |
| 16 | #if defined(_SC_NPROCESSORS_ONLN) |
| 17 | // currently online processors |
| 18 | p = sysconf(_SC_NPROCESSORS_ONLN); |
| 19 | if(p > 1) goto done; // if it is 1, we will try harder below |
| 20 | #endif |
| 21 | |
| 22 | #if defined(_SC_NPROCESSORS_CONF) |
| 23 | // all configured processors (online and offline) |
| 24 | p = sysconf(_SC_NPROCESSORS_CONF); |
| 25 | if(p > 1) goto done; // if it is 1, we will try harder below |
| 26 | #endif |
| 27 | |
| 28 | #if defined(OS_FREEBSD) || defined(OS_MACOS) |
| 29 | #if defined(OS_MACOS) |
| 30 | #define HW_CPU_NAME "hw.logicalcpu" |
| 31 | #else |
| 32 | #define HW_CPU_NAME "kern.smp.cpus" |
| 33 | #endif |
| 34 | |
| 35 | if (unlikely(GETSYSCTL_BY_NAME(HW_CPU_NAME, p) || p < 1)) |
| 36 | goto error; |
| 37 | |
| 38 | #elif defined(OS_LINUX) |
| 39 | // we will count the number of cpus in /proc/stat |
| 40 | |
| 41 | char filename[FILENAME_MAX + 1]; |
| 42 | snprintfz(filename, FILENAME_MAX, "%s/proc/stat", |
| 43 | (netdata_configured_host_prefix) ? netdata_configured_host_prefix : ""); |
| 44 | |
| 45 | procfile *ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT); |
| 46 | if(!ff || !(ff = procfile_readall(ff))) goto error; |
| 47 | |
| 48 | p = 0; |
| 49 | unsigned int i; |
| 50 | for(i = 0; i < procfile_lines(ff); i++) { |
| 51 | if(!procfile_linewords(ff, i)) continue; |
| 52 | |
| 53 | const char *starting = procfile_lineword(ff, i, 0); |
| 54 | if(strncmp(starting, "cpu", 3) == 0 && isdigit((uint8_t)starting[3])) |
| 55 | p++; |
| 56 | } |
| 57 | procfile_close(ff); |
| 58 | if(p < 1) goto error; |
| 59 | |
| 60 | #elif defined(OS_WINDOWS) |
| 61 | |
| 62 | SYSTEM_INFO sysInfo; |
| 63 | GetSystemInfo(&sysInfo); |
| 64 | p = sysInfo.dwNumberOfProcessors; |
| 65 | if(p < 1) goto error; |
| 66 | |
| 67 | #else |
| 68 | |
| 69 | p = 1; |
| 70 | |
| 71 | #endif |
| 72 | |
| 73 | done: |
| 74 | processors = (size_t)p; |
| 75 | spinlock_unlock(&spinlock); |
| 76 | return processors; |
| 77 | |
| 78 | error: |
| 79 | spinlock_unlock(&spinlock); |
| 80 | processors = 1; |
| 81 | netdata_log_error("Cannot detect number of CPU cores. Assuming the system has %zu processors.", processors); |
| 82 | return processors; |
| 83 | } |
| 84 | |
| 85 | // -------------------------------------------------------------------------------------------------------------------- |
| 86 | // cpuset cpus |
| 87 | |
| 88 | static inline unsigned long cpuset_str2ul(char **s) { |
| 89 | unsigned long n = 0; |
| 90 | char c; |
| 91 | for(c = **s; c >= '0' && c <= '9' ; c = *(++*s)) { |
| 92 | n *= 10; |
| 93 | n += c - '0'; |
| 94 | } |
| 95 | return n; |
| 96 | } |
| 97 | |
| 98 | #if defined(OS_LINUX) |
| 99 | size_t os_read_cpuset_cpus(const char *filename, size_t system_cpus) { |
| 100 | static char *buf = NULL; |
| 101 | static size_t buf_size = 0; |
| 102 | |
| 103 | if(unlikely(!system_cpus)) |
| 104 | system_cpus = os_get_system_cpus_uncached(); |
| 105 | |
| 106 | size_t required_buf_size = 100U + 6 * system_cpus + 1; // taken from kernel/cgroup/cpuset.c |
| 107 | if(unlikely(buf_size < required_buf_size)) { |
| 108 | buf_size = required_buf_size; |
| 109 | buf = reallocz(buf, buf_size); |
| 110 | } |
| 111 | |
| 112 | int ret = read_txt_file(filename, buf, buf_size); |
| 113 | |
| 114 | if(!ret) { |
| 115 | char *s = buf; |
| 116 | unsigned long ncpus = 0; |
| 117 | |
| 118 | // parse the cpuset string and calculate the number of cpus the cgroup is allowed to use |
| 119 | while (*s) { |
| 120 | if (isspace((uint8_t)*s)) { |
| 121 | s++; |
| 122 | continue; |
| 123 | } |
| 124 | unsigned long n = cpuset_str2ul(&s); |
| 125 | ncpus++; |
| 126 | if(*s == ',') { |
| 127 | s++; |
| 128 | continue; |
| 129 | } |
| 130 | if(*s == '-') { |
| 131 | s++; |
| 132 | unsigned long m = cpuset_str2ul(&s); |
| 133 | ncpus += m - n; // calculate the number of cpus in the region |
| 134 | } |
| 135 | s++; |
| 136 | } |
| 137 | |
| 138 | if(!ncpus) |
| 139 | return 0; |
| 140 | |
| 141 | return ncpus; |
| 142 | } |
| 143 | |
| 144 | return 0; |
| 145 | } |
| 146 | #endif |