NetBSDMachine.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /*
  2. htop - NetBSDMachine.c
  3. (C) 2014 Hisham H. Muhammad
  4. (C) 2015 Michael McConville
  5. (C) 2021 Santhosh Raju
  6. (C) 2021 htop dev team
  7. Released under the GNU GPLv2+, see the COPYING file
  8. in the source distribution for its full text.
  9. */
  10. #include "config.h" // IWYU pragma: keep
  11. #include "netbsd/NetBSDMachine.h"
  12. #include <kvm.h>
  13. #include <math.h>
  14. #include <limits.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <unistd.h>
  18. #include <sys/mount.h>
  19. #include <sys/param.h>
  20. #include <sys/proc.h>
  21. #include <sys/sched.h>
  22. #include <sys/swap.h>
  23. #include <sys/sysctl.h>
  24. #include <sys/types.h>
  25. #include <uvm/uvm_extern.h>
  26. #include "CRT.h"
  27. #include "Machine.h"
  28. #include "Macros.h"
  29. #include "Object.h"
  30. #include "Settings.h"
  31. #include "XUtils.h"
  32. static const struct {
  33. const char* name;
  34. long int scale;
  35. } freqSysctls[] = {
  36. { "machdep.est.frequency.current", 1 },
  37. { "machdep.powernow.frequency.current", 1 },
  38. { "machdep.intrepid.frequency.current", 1 },
  39. { "machdep.loongson.frequency.current", 1 },
  40. { "machdep.cpu.frequency.current", 1 },
  41. { "machdep.frequency.current", 1 },
  42. { "machdep.tsc_freq", 1000000 },
  43. };
  44. static void NetBSDMachine_updateCPUcount(NetBSDMachine* this) {
  45. Machine* super = &this->super;
  46. // Definitions for sysctl(3), cf. https://nxr.netbsd.org/xref/src/sys/sys/sysctl.h#813
  47. const int mib_ncpu_existing[] = { CTL_HW, HW_NCPU }; // Number of existing CPUs
  48. const int mib_ncpu_online[] = { CTL_HW, HW_NCPUONLINE }; // Number of online/active CPUs
  49. int r;
  50. unsigned int value;
  51. size_t size;
  52. bool change = false;
  53. // Query the number of active/online CPUs.
  54. size = sizeof(value);
  55. r = sysctl(mib_ncpu_online, 2, &value, &size, NULL, 0);
  56. if (r < 0 || value < 1) {
  57. value = 1;
  58. }
  59. if (value != super->activeCPUs) {
  60. super->activeCPUs = value;
  61. change = true;
  62. }
  63. // Query the total number of CPUs.
  64. size = sizeof(value);
  65. r = sysctl(mib_ncpu_existing, 2, &value, &size, NULL, 0);
  66. if (r < 0 || value < 1) {
  67. value = super->activeCPUs;
  68. }
  69. if (value != super->existingCPUs) {
  70. this->cpuData = xReallocArray(this->cpuData, value + 1, sizeof(CPUData));
  71. super->existingCPUs = value;
  72. change = true;
  73. }
  74. // Reset CPU stats when number of online/existing CPU cores changed
  75. if (change) {
  76. CPUData* dAvg = &this->cpuData[0];
  77. memset(dAvg, '\0', sizeof(CPUData));
  78. dAvg->totalTime = 1;
  79. dAvg->totalPeriod = 1;
  80. for (unsigned int i = 0; i < super->existingCPUs; i++) {
  81. CPUData* d = &this->cpuData[i + 1];
  82. memset(d, '\0', sizeof(CPUData));
  83. d->totalTime = 1;
  84. d->totalPeriod = 1;
  85. }
  86. }
  87. }
  88. Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
  89. const int fmib[] = { CTL_KERN, KERN_FSCALE };
  90. size_t size;
  91. char errbuf[_POSIX2_LINE_MAX];
  92. NetBSDMachine* this = xCalloc(1, sizeof(NetBSDMachine));
  93. Machine* super = &this->super;
  94. Machine_init(super, usersTable, userId);
  95. NetBSDMachine_updateCPUcount(this);
  96. size = sizeof(this->fscale);
  97. if (sysctl(fmib, 2, &this->fscale, &size, NULL, 0) < 0 || this->fscale <= 0) {
  98. CRT_fatalError("fscale sysctl call failed");
  99. }
  100. if ((this->pageSize = sysconf(_SC_PAGESIZE)) == -1)
  101. CRT_fatalError("pagesize sysconf call failed");
  102. this->pageSizeKB = this->pageSize / ONE_K;
  103. this->kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
  104. if (this->kd == NULL) {
  105. CRT_fatalError("kvm_openfiles() failed");
  106. }
  107. return super;
  108. }
  109. void Machine_delete(Machine* super) {
  110. NetBSDMachine* this = (NetBSDMachine*) super;
  111. Machine_done(super);
  112. if (this->kd) {
  113. kvm_close(this->kd);
  114. }
  115. free(this->cpuData);
  116. free(this);
  117. }
  118. static void NetBSDMachine_scanMemoryInfo(NetBSDMachine* this) {
  119. Machine* super = &this->super;
  120. static int uvmexp_mib[] = {CTL_VM, VM_UVMEXP2};
  121. struct uvmexp_sysctl uvmexp;
  122. size_t size_uvmexp = sizeof(uvmexp);
  123. if (sysctl(uvmexp_mib, 2, &uvmexp, &size_uvmexp, NULL, 0) < 0) {
  124. CRT_fatalError("uvmexp sysctl call failed");
  125. }
  126. super->totalMem = uvmexp.npages * this->pageSizeKB;
  127. super->buffersMem = 0;
  128. super->cachedMem = (uvmexp.filepages + uvmexp.execpages) * this->pageSizeKB;
  129. super->usedMem = (uvmexp.active + uvmexp.wired) * this->pageSizeKB;
  130. super->totalSwap = uvmexp.swpages * this->pageSizeKB;
  131. super->usedSwap = uvmexp.swpginuse * this->pageSizeKB;
  132. }
  133. static void getKernelCPUTimes(int cpuId, u_int64_t* times) {
  134. const int mib[] = { CTL_KERN, KERN_CP_TIME, cpuId };
  135. size_t length = sizeof(*times) * CPUSTATES;
  136. if (sysctl(mib, 3, times, &length, NULL, 0) == -1 || length != sizeof(*times) * CPUSTATES) {
  137. CRT_fatalError("sysctl kern.cp_time2 failed");
  138. }
  139. }
  140. static void kernelCPUTimesToHtop(const u_int64_t* times, CPUData* cpu) {
  141. unsigned long long totalTime = 0;
  142. for (int i = 0; i < CPUSTATES; i++) {
  143. totalTime += times[i];
  144. }
  145. unsigned long long sysAllTime = times[CP_INTR] + times[CP_SYS];
  146. cpu->totalPeriod = saturatingSub(totalTime, cpu->totalTime);
  147. cpu->userPeriod = saturatingSub(times[CP_USER], cpu->userTime);
  148. cpu->nicePeriod = saturatingSub(times[CP_NICE], cpu->niceTime);
  149. cpu->sysPeriod = saturatingSub(times[CP_SYS], cpu->sysTime);
  150. cpu->sysAllPeriod = saturatingSub(sysAllTime, cpu->sysAllTime);
  151. cpu->intrPeriod = saturatingSub(times[CP_INTR], cpu->intrTime);
  152. cpu->idlePeriod = saturatingSub(times[CP_IDLE], cpu->idleTime);
  153. cpu->totalTime = totalTime;
  154. cpu->userTime = times[CP_USER];
  155. cpu->niceTime = times[CP_NICE];
  156. cpu->sysTime = times[CP_SYS];
  157. cpu->sysAllTime = sysAllTime;
  158. cpu->intrTime = times[CP_INTR];
  159. cpu->idleTime = times[CP_IDLE];
  160. }
  161. static void NetBSDMachine_scanCPUTime(NetBSDMachine* this) {
  162. const Machine* super = &this->super;
  163. u_int64_t kernelTimes[CPUSTATES] = {0};
  164. u_int64_t avg[CPUSTATES] = {0};
  165. for (unsigned int i = 0; i < super->existingCPUs; i++) {
  166. getKernelCPUTimes(i, kernelTimes);
  167. CPUData* cpu = &this->cpuData[i + 1];
  168. kernelCPUTimesToHtop(kernelTimes, cpu);
  169. avg[CP_USER] += cpu->userTime;
  170. avg[CP_NICE] += cpu->niceTime;
  171. avg[CP_SYS] += cpu->sysTime;
  172. avg[CP_INTR] += cpu->intrTime;
  173. avg[CP_IDLE] += cpu->idleTime;
  174. }
  175. for (int i = 0; i < CPUSTATES; i++) {
  176. avg[i] /= super->activeCPUs;
  177. }
  178. kernelCPUTimesToHtop(avg, &this->cpuData[0]);
  179. }
  180. static void NetBSDMachine_scanCPUFrequency(NetBSDMachine* this) {
  181. const Machine* super = &this->super;
  182. unsigned int cpus = super->existingCPUs;
  183. bool match = false;
  184. char name[64];
  185. long int freq = 0;
  186. size_t freqSize;
  187. for (unsigned int i = 0; i < cpus; i++) {
  188. this->cpuData[i + 1].frequency = NAN;
  189. }
  190. /* newer hardware supports per-core frequency, for e.g. ARM big.LITTLE */
  191. for (unsigned int i = 0; i < cpus; i++) {
  192. xSnprintf(name, sizeof(name), "machdep.cpufreq.cpu%u.current", i);
  193. freqSize = sizeof(freq);
  194. if (sysctlbyname(name, &freq, &freqSize, NULL, 0) != -1) {
  195. this->cpuData[i + 1].frequency = freq; /* already in MHz */
  196. match = true;
  197. }
  198. }
  199. if (match) {
  200. return;
  201. }
  202. /*
  203. * Iterate through legacy sysctl nodes for single-core frequency until
  204. * we find a match...
  205. */
  206. for (size_t i = 0; i < ARRAYSIZE(freqSysctls); i++) {
  207. freqSize = sizeof(freq);
  208. if (sysctlbyname(freqSysctls[i].name, &freq, &freqSize, NULL, 0) != -1) {
  209. freq /= freqSysctls[i].scale; /* scale to MHz */
  210. match = true;
  211. break;
  212. }
  213. }
  214. if (match) {
  215. for (unsigned int i = 0; i < cpus; i++) {
  216. this->cpuData[i + 1].frequency = freq;
  217. }
  218. }
  219. }
  220. void Machine_scan(Machine* super) {
  221. NetBSDMachine* this = (NetBSDMachine*) super;
  222. NetBSDMachine_scanMemoryInfo(this);
  223. NetBSDMachine_scanCPUTime(this);
  224. if (super->settings->showCPUFrequency) {
  225. NetBSDMachine_scanCPUFrequency(this);
  226. }
  227. }
  228. bool Machine_isCPUonline(const Machine* host, unsigned int id) {
  229. assert(id < host->existingCPUs);
  230. (void)host; (void)id;
  231. // TODO: Support detecting online / offline CPUs.
  232. return true;
  233. }