Platform.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  1. /*
  2. htop - linux/Platform.c
  3. (C) 2014 Hisham H. Muhammad
  4. (C) 2020-2022 htop dev team
  5. (C) 2020-2022 Red Hat, Inc.
  6. Released under the GNU GPLv2+, see the COPYING file
  7. in the source distribution for its full text.
  8. */
  9. #include "config.h" // IWYU pragma: keep
  10. #include "pcp/Platform.h"
  11. #include <math.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <unistd.h>
  16. #include "BatteryMeter.h"
  17. #include "CPUMeter.h"
  18. #include "ClockMeter.h"
  19. #include "DateMeter.h"
  20. #include "DateTimeMeter.h"
  21. #include "DiskIOMeter.h"
  22. #include "DynamicColumn.h"
  23. #include "DynamicMeter.h"
  24. #include "DynamicScreen.h"
  25. #include "FileDescriptorMeter.h"
  26. #include "HostnameMeter.h"
  27. #include "LoadAverageMeter.h"
  28. #include "Macros.h"
  29. #include "MemoryMeter.h"
  30. #include "MemorySwapMeter.h"
  31. #include "Meter.h"
  32. #include "NetworkIOMeter.h"
  33. #include "ProcessTable.h"
  34. #include "Settings.h"
  35. #include "SwapMeter.h"
  36. #include "SysArchMeter.h"
  37. #include "TasksMeter.h"
  38. #include "UptimeMeter.h"
  39. #include "XUtils.h"
  40. #include "linux/PressureStallMeter.h"
  41. #include "linux/ZramMeter.h"
  42. #include "linux/ZramStats.h"
  43. #include "pcp/Metric.h"
  44. #include "pcp/PCPDynamicColumn.h"
  45. #include "pcp/PCPDynamicMeter.h"
  46. #include "pcp/PCPDynamicScreen.h"
  47. #include "pcp/PCPMachine.h"
  48. #include "pcp/PCPProcessTable.h"
  49. #include "zfs/ZfsArcMeter.h"
  50. #include "zfs/ZfsArcStats.h"
  51. #include "zfs/ZfsCompressedArcMeter.h"
  52. Platform* pcp;
  53. const ScreenDefaults Platform_defaultScreens[] = {
  54. {
  55. .name = "Main",
  56. .columns = "PID USER PRIORITY NICE M_VIRT M_RESIDENT M_SHARE STATE PERCENT_CPU PERCENT_MEM TIME Command",
  57. .sortKey = "PERCENT_CPU",
  58. },
  59. {
  60. .name = "I/O",
  61. .columns = "PID USER IO_PRIORITY IO_RATE IO_READ_RATE IO_WRITE_RATE PERCENT_SWAP_DELAY PERCENT_IO_DELAY Command",
  62. .sortKey = "IO_RATE",
  63. },
  64. };
  65. const unsigned int Platform_numberOfDefaultScreens = ARRAYSIZE(Platform_defaultScreens);
  66. const SignalItem Platform_signals[] = {
  67. { .name = " 0 Cancel", .number = 0 },
  68. };
  69. const unsigned int Platform_numberOfSignals = ARRAYSIZE(Platform_signals);
  70. const MeterClass* const Platform_meterTypes[] = {
  71. &CPUMeter_class,
  72. &ClockMeter_class,
  73. &DateMeter_class,
  74. &DateTimeMeter_class,
  75. &LoadAverageMeter_class,
  76. &LoadMeter_class,
  77. &MemoryMeter_class,
  78. &SwapMeter_class,
  79. &MemorySwapMeter_class,
  80. &TasksMeter_class,
  81. &UptimeMeter_class,
  82. &BatteryMeter_class,
  83. &HostnameMeter_class,
  84. &AllCPUsMeter_class,
  85. &AllCPUs2Meter_class,
  86. &AllCPUs4Meter_class,
  87. &AllCPUs8Meter_class,
  88. &LeftCPUsMeter_class,
  89. &RightCPUsMeter_class,
  90. &LeftCPUs2Meter_class,
  91. &RightCPUs2Meter_class,
  92. &LeftCPUs4Meter_class,
  93. &RightCPUs4Meter_class,
  94. &LeftCPUs8Meter_class,
  95. &RightCPUs8Meter_class,
  96. &PressureStallCPUSomeMeter_class,
  97. &PressureStallIOSomeMeter_class,
  98. &PressureStallIOFullMeter_class,
  99. &PressureStallIRQFullMeter_class,
  100. &PressureStallMemorySomeMeter_class,
  101. &PressureStallMemoryFullMeter_class,
  102. &ZfsArcMeter_class,
  103. &ZfsCompressedArcMeter_class,
  104. &ZramMeter_class,
  105. &DiskIOMeter_class,
  106. &NetworkIOMeter_class,
  107. &SysArchMeter_class,
  108. &FileDescriptorMeter_class,
  109. &BlankMeter_class,
  110. &DynamicMeter_class,
  111. NULL
  112. };
  113. static const char* Platform_metricNames[] = {
  114. [PCP_CONTROL_THREADS] = "proc.control.perclient.threads",
  115. [PCP_HINV_NCPU] = "hinv.ncpu",
  116. [PCP_HINV_NDISK] = "hinv.ndisk",
  117. [PCP_HINV_CPUCLOCK] = "hinv.cpu.clock",
  118. [PCP_UNAME_SYSNAME] = "kernel.uname.sysname",
  119. [PCP_UNAME_RELEASE] = "kernel.uname.release",
  120. [PCP_UNAME_MACHINE] = "kernel.uname.machine",
  121. [PCP_UNAME_DISTRO] = "kernel.uname.distro",
  122. [PCP_LOAD_AVERAGE] = "kernel.all.load",
  123. [PCP_PID_MAX] = "kernel.all.pid_max",
  124. [PCP_UPTIME] = "kernel.all.uptime",
  125. [PCP_BOOTTIME] = "kernel.all.boottime",
  126. [PCP_CPU_USER] = "kernel.all.cpu.user",
  127. [PCP_CPU_NICE] = "kernel.all.cpu.nice",
  128. [PCP_CPU_SYSTEM] = "kernel.all.cpu.sys",
  129. [PCP_CPU_IDLE] = "kernel.all.cpu.idle",
  130. [PCP_CPU_IOWAIT] = "kernel.all.cpu.wait.total",
  131. [PCP_CPU_IRQ] = "kernel.all.cpu.intr",
  132. [PCP_CPU_SOFTIRQ] = "kernel.all.cpu.irq.soft",
  133. [PCP_CPU_STEAL] = "kernel.all.cpu.steal",
  134. [PCP_CPU_GUEST] = "kernel.all.cpu.guest",
  135. [PCP_CPU_GUESTNICE] = "kernel.all.cpu.guest_nice",
  136. [PCP_PERCPU_USER] = "kernel.percpu.cpu.user",
  137. [PCP_PERCPU_NICE] = "kernel.percpu.cpu.nice",
  138. [PCP_PERCPU_SYSTEM] = "kernel.percpu.cpu.sys",
  139. [PCP_PERCPU_IDLE] = "kernel.percpu.cpu.idle",
  140. [PCP_PERCPU_IOWAIT] = "kernel.percpu.cpu.wait.total",
  141. [PCP_PERCPU_IRQ] = "kernel.percpu.cpu.intr",
  142. [PCP_PERCPU_SOFTIRQ] = "kernel.percpu.cpu.irq.soft",
  143. [PCP_PERCPU_STEAL] = "kernel.percpu.cpu.steal",
  144. [PCP_PERCPU_GUEST] = "kernel.percpu.cpu.guest",
  145. [PCP_PERCPU_GUESTNICE] = "kernel.percpu.cpu.guest_nice",
  146. [PCP_MEM_TOTAL] = "mem.physmem",
  147. [PCP_MEM_FREE] = "mem.util.free",
  148. [PCP_MEM_AVAILABLE] = "mem.util.available",
  149. [PCP_MEM_BUFFERS] = "mem.util.bufmem",
  150. [PCP_MEM_CACHED] = "mem.util.cached",
  151. [PCP_MEM_SHARED] = "mem.util.shmem",
  152. [PCP_MEM_SRECLAIM] = "mem.util.slabReclaimable",
  153. [PCP_MEM_SWAPCACHED] = "mem.util.swapCached",
  154. [PCP_MEM_SWAPTOTAL] = "mem.util.swapTotal",
  155. [PCP_MEM_SWAPFREE] = "mem.util.swapFree",
  156. [PCP_DISK_READB] = "disk.all.read_bytes",
  157. [PCP_DISK_WRITEB] = "disk.all.write_bytes",
  158. [PCP_DISK_ACTIVE] = "disk.all.avactive",
  159. [PCP_NET_RECVB] = "network.all.in.bytes",
  160. [PCP_NET_SENDB] = "network.all.out.bytes",
  161. [PCP_NET_RECVP] = "network.all.in.packets",
  162. [PCP_NET_SENDP] = "network.all.out.packets",
  163. [PCP_PSI_CPUSOME] = "kernel.all.pressure.cpu.some.avg",
  164. [PCP_PSI_IOSOME] = "kernel.all.pressure.io.some.avg",
  165. [PCP_PSI_IOFULL] = "kernel.all.pressure.io.full.avg",
  166. [PCP_PSI_IRQFULL] = "kernel.all.pressure.irq.full.avg",
  167. [PCP_PSI_MEMSOME] = "kernel.all.pressure.memory.some.avg",
  168. [PCP_PSI_MEMFULL] = "kernel.all.pressure.memory.full.avg",
  169. [PCP_ZFS_ARC_ANON_SIZE] = "zfs.arc.anon_size",
  170. [PCP_ZFS_ARC_BONUS_SIZE] = "zfs.arc.bonus_size",
  171. [PCP_ZFS_ARC_COMPRESSED_SIZE] = "zfs.arc.compressed_size",
  172. [PCP_ZFS_ARC_UNCOMPRESSED_SIZE] = "zfs.arc.uncompressed_size",
  173. [PCP_ZFS_ARC_C_MIN] = "zfs.arc.c_min",
  174. [PCP_ZFS_ARC_C_MAX] = "zfs.arc.c_max",
  175. [PCP_ZFS_ARC_DBUF_SIZE] = "zfs.arc.dbuf_size",
  176. [PCP_ZFS_ARC_DNODE_SIZE] = "zfs.arc.dnode_size",
  177. [PCP_ZFS_ARC_HDR_SIZE] = "zfs.arc.hdr_size",
  178. [PCP_ZFS_ARC_MFU_SIZE] = "zfs.arc.mfu.size",
  179. [PCP_ZFS_ARC_MRU_SIZE] = "zfs.arc.mru.size",
  180. [PCP_ZFS_ARC_SIZE] = "zfs.arc.size",
  181. [PCP_ZRAM_CAPACITY] = "zram.capacity",
  182. [PCP_ZRAM_ORIGINAL] = "zram.mm_stat.data_size.original",
  183. [PCP_ZRAM_COMPRESSED] = "zram.mm_stat.data_size.compressed",
  184. [PCP_MEM_ZSWAP] = "mem.util.zswap",
  185. [PCP_MEM_ZSWAPPED] = "mem.util.zswapped",
  186. [PCP_VFS_FILES_COUNT] = "vfs.files.count",
  187. [PCP_VFS_FILES_MAX] = "vfs.files.max",
  188. [PCP_PROC_PID] = "proc.psinfo.pid",
  189. [PCP_PROC_PPID] = "proc.psinfo.ppid",
  190. [PCP_PROC_TGID] = "proc.psinfo.tgid",
  191. [PCP_PROC_PGRP] = "proc.psinfo.pgrp",
  192. [PCP_PROC_SESSION] = "proc.psinfo.session",
  193. [PCP_PROC_STATE] = "proc.psinfo.sname",
  194. [PCP_PROC_TTY] = "proc.psinfo.tty",
  195. [PCP_PROC_TTYPGRP] = "proc.psinfo.tty_pgrp",
  196. [PCP_PROC_MINFLT] = "proc.psinfo.minflt",
  197. [PCP_PROC_MAJFLT] = "proc.psinfo.maj_flt",
  198. [PCP_PROC_CMINFLT] = "proc.psinfo.cmin_flt",
  199. [PCP_PROC_CMAJFLT] = "proc.psinfo.cmaj_flt",
  200. [PCP_PROC_UTIME] = "proc.psinfo.utime",
  201. [PCP_PROC_STIME] = "proc.psinfo.stime",
  202. [PCP_PROC_CUTIME] = "proc.psinfo.cutime",
  203. [PCP_PROC_CSTIME] = "proc.psinfo.cstime",
  204. [PCP_PROC_PRIORITY] = "proc.psinfo.priority",
  205. [PCP_PROC_NICE] = "proc.psinfo.nice",
  206. [PCP_PROC_THREADS] = "proc.psinfo.threads",
  207. [PCP_PROC_STARTTIME] = "proc.psinfo.start_time",
  208. [PCP_PROC_PROCESSOR] = "proc.psinfo.processor",
  209. [PCP_PROC_CMD] = "proc.psinfo.cmd",
  210. [PCP_PROC_PSARGS] = "proc.psinfo.psargs",
  211. [PCP_PROC_CGROUPS] = "proc.psinfo.cgroups",
  212. [PCP_PROC_OOMSCORE] = "proc.psinfo.oom_score",
  213. [PCP_PROC_VCTXSW] = "proc.psinfo.vctxsw",
  214. [PCP_PROC_NVCTXSW] = "proc.psinfo.nvctxsw",
  215. [PCP_PROC_LABELS] = "proc.psinfo.labels",
  216. [PCP_PROC_ENVIRON] = "proc.psinfo.environ",
  217. [PCP_PROC_TTYNAME] = "proc.psinfo.ttyname",
  218. [PCP_PROC_EXE] = "proc.psinfo.exe",
  219. [PCP_PROC_CWD] = "proc.psinfo.cwd",
  220. [PCP_PROC_AUTOGROUP_ID] = "proc.autogroup.id",
  221. [PCP_PROC_AUTOGROUP_NICE] = "proc.autogroup.nice",
  222. [PCP_PROC_ID_UID] = "proc.id.uid",
  223. [PCP_PROC_ID_USER] = "proc.id.uid_nm",
  224. [PCP_PROC_IO_RCHAR] = "proc.io.rchar",
  225. [PCP_PROC_IO_WCHAR] = "proc.io.wchar",
  226. [PCP_PROC_IO_SYSCR] = "proc.io.syscr",
  227. [PCP_PROC_IO_SYSCW] = "proc.io.syscw",
  228. [PCP_PROC_IO_READB] = "proc.io.read_bytes",
  229. [PCP_PROC_IO_WRITEB] = "proc.io.write_bytes",
  230. [PCP_PROC_IO_CANCELLED] = "proc.io.cancelled_write_bytes",
  231. [PCP_PROC_MEM_SIZE] = "proc.memory.size",
  232. [PCP_PROC_MEM_RSS] = "proc.memory.rss",
  233. [PCP_PROC_MEM_SHARE] = "proc.memory.share",
  234. [PCP_PROC_MEM_TEXTRS] = "proc.memory.textrss",
  235. [PCP_PROC_MEM_LIBRS] = "proc.memory.librss",
  236. [PCP_PROC_MEM_DATRS] = "proc.memory.datrss",
  237. [PCP_PROC_MEM_DIRTY] = "proc.memory.dirty",
  238. [PCP_PROC_SMAPS_PSS] = "proc.smaps.pss",
  239. [PCP_PROC_SMAPS_SWAP] = "proc.smaps.swap",
  240. [PCP_PROC_SMAPS_SWAPPSS] = "proc.smaps.swappss",
  241. [PCP_METRIC_COUNT] = NULL
  242. };
  243. #ifndef HAVE_PMLOOKUPDESCS
  244. /*
  245. * pmLookupDescs(3) exists in latest versions of libpcp (5.3.6+),
  246. * but for older versions we provide an implementation here. This
  247. * involves multiple round trips to pmcd though, which the latest
  248. * libpcp version avoids by using a protocol extension. In time,
  249. * perhaps in a few years, we could remove this back-compat code.
  250. */
  251. int pmLookupDescs(int numpmid, pmID* pmids, pmDesc* descs) {
  252. int count = 0;
  253. for (int i = 0; i < numpmid; i++) {
  254. /* expect some metrics to be missing - e.g. PMDA not available */
  255. if (pmids[i] == PM_ID_NULL)
  256. continue;
  257. int sts = pmLookupDesc(pmids[i], &descs[i]);
  258. if (sts < 0) {
  259. if (pmDebugOptions.appl0)
  260. fprintf(stderr, "Error: cannot lookup metric %s(%s): %s\n",
  261. pcp->names[i], pmIDStr(pcp->pmids[i]), pmErrStr(sts));
  262. pmids[i] = PM_ID_NULL;
  263. continue;
  264. }
  265. count++;
  266. }
  267. return count;
  268. }
  269. #endif
  270. size_t Platform_addMetric(Metric id, const char* name) {
  271. unsigned int i = (unsigned int)id;
  272. if (i >= PCP_METRIC_COUNT && i >= pcp->totalMetrics) {
  273. /* added via configuration files */
  274. size_t j = pcp->totalMetrics + 1;
  275. pcp->fetch = xRealloc(pcp->fetch, j * sizeof(pmID));
  276. pcp->pmids = xRealloc(pcp->pmids, j * sizeof(pmID));
  277. pcp->names = xRealloc(pcp->names, j * sizeof(char*));
  278. pcp->descs = xRealloc(pcp->descs, j * sizeof(pmDesc));
  279. memset(&pcp->descs[i], 0, sizeof(pmDesc));
  280. }
  281. pcp->pmids[i] = pcp->fetch[i] = PM_ID_NULL;
  282. pcp->names[i] = name;
  283. return ++pcp->totalMetrics;
  284. }
  285. /* global state from the environment and command line arguments */
  286. pmOptions opts;
  287. bool Platform_init(void) {
  288. const char* source;
  289. if (opts.context == PM_CONTEXT_ARCHIVE) {
  290. source = opts.archives[0];
  291. } else if (opts.context == PM_CONTEXT_HOST) {
  292. source = opts.nhosts > 0 ? opts.hosts[0] : "local:";
  293. } else {
  294. opts.context = PM_CONTEXT_HOST;
  295. source = "local:";
  296. }
  297. int sts;
  298. sts = pmNewContext(opts.context, source);
  299. /* with no host requested, fallback to PM_CONTEXT_LOCAL shared libraries */
  300. if (sts < 0 && opts.context == PM_CONTEXT_HOST && opts.nhosts == 0) {
  301. opts.context = PM_CONTEXT_LOCAL;
  302. sts = pmNewContext(opts.context, NULL);
  303. }
  304. if (sts < 0) {
  305. fprintf(stderr, "Cannot setup PCP metric source: %s\n", pmErrStr(sts));
  306. return false;
  307. }
  308. /* setup timezones and other general startup preparation completion */
  309. if (pmGetContextOptions(sts, &opts) < 0 || opts.errors) {
  310. pmflush();
  311. return false;
  312. }
  313. pcp = xCalloc(1, sizeof(Platform));
  314. pcp->context = sts;
  315. pcp->fetch = xCalloc(PCP_METRIC_COUNT, sizeof(pmID));
  316. pcp->pmids = xCalloc(PCP_METRIC_COUNT, sizeof(pmID));
  317. pcp->names = xCalloc(PCP_METRIC_COUNT, sizeof(char*));
  318. pcp->descs = xCalloc(PCP_METRIC_COUNT, sizeof(pmDesc));
  319. if (opts.context == PM_CONTEXT_ARCHIVE) {
  320. gettimeofday(&pcp->offset, NULL);
  321. pmtimevalDec(&pcp->offset, &opts.start);
  322. }
  323. for (unsigned int i = 0; i < PCP_METRIC_COUNT; i++)
  324. Platform_addMetric(i, Platform_metricNames[i]);
  325. pcp->meters.offset = PCP_METRIC_COUNT;
  326. PCPDynamicMeters_init(&pcp->meters);
  327. pcp->columns.offset = PCP_METRIC_COUNT + pcp->meters.cursor;
  328. PCPDynamicColumns_init(&pcp->columns);
  329. PCPDynamicScreens_init(&pcp->screens, &pcp->columns);
  330. sts = pmLookupName(pcp->totalMetrics, pcp->names, pcp->pmids);
  331. if (sts < 0) {
  332. fprintf(stderr, "Error: cannot lookup metric names: %s\n", pmErrStr(sts));
  333. Platform_done();
  334. return false;
  335. }
  336. sts = pmLookupDescs(pcp->totalMetrics, pcp->pmids, pcp->descs);
  337. if (sts < 1) {
  338. if (sts < 0)
  339. fprintf(stderr, "Error: cannot lookup descriptors: %s\n", pmErrStr(sts));
  340. else /* ensure we have at least one valid metric to work with */
  341. fprintf(stderr, "Error: cannot find a single valid metric, exiting\n");
  342. Platform_done();
  343. return false;
  344. }
  345. /* set proc.control.perclient.threads to 1 for live contexts */
  346. Metric_enableThreads();
  347. /* extract values needed for setup - e.g. cpu count, pid_max */
  348. Metric_enable(PCP_PID_MAX, true);
  349. Metric_enable(PCP_BOOTTIME, true);
  350. Metric_enable(PCP_HINV_NCPU, true);
  351. Metric_enable(PCP_HINV_NDISK, true);
  352. Metric_enable(PCP_PERCPU_SYSTEM, true);
  353. Metric_enable(PCP_UNAME_SYSNAME, true);
  354. Metric_enable(PCP_UNAME_RELEASE, true);
  355. Metric_enable(PCP_UNAME_MACHINE, true);
  356. Metric_enable(PCP_UNAME_DISTRO, true);
  357. /* enable metrics for all dynamic columns (including those from dynamic screens) */
  358. for (size_t i = pcp->columns.offset; i < pcp->columns.offset + pcp->columns.count; i++)
  359. Metric_enable(i, true);
  360. Metric_fetch(NULL);
  361. for (Metric metric = 0; metric < PCP_PROC_PID; metric++)
  362. Metric_enable(metric, true);
  363. Metric_enable(PCP_PID_MAX, false); /* needed one time only */
  364. Metric_enable(PCP_BOOTTIME, false);
  365. Metric_enable(PCP_UNAME_SYSNAME, false);
  366. Metric_enable(PCP_UNAME_RELEASE, false);
  367. Metric_enable(PCP_UNAME_MACHINE, false);
  368. Metric_enable(PCP_UNAME_DISTRO, false);
  369. /* first sample (fetch) performed above, save constants */
  370. Platform_getBootTime();
  371. Platform_getRelease(0);
  372. Platform_getMaxCPU();
  373. Platform_getMaxPid();
  374. return true;
  375. }
  376. void Platform_dynamicColumnsDone(Hashtable* columns) {
  377. PCPDynamicColumns_done(columns);
  378. }
  379. void Platform_dynamicMetersDone(Hashtable* meters) {
  380. PCPDynamicMeters_done(meters);
  381. }
  382. void Platform_dynamicScreensDone(Hashtable* screens) {
  383. PCPDynamicScreens_done(screens);
  384. }
  385. void Platform_done(void) {
  386. pmDestroyContext(pcp->context);
  387. if (pcp->result)
  388. pmFreeResult(pcp->result);
  389. free(pcp->release);
  390. free(pcp->fetch);
  391. free(pcp->pmids);
  392. free(pcp->names);
  393. free(pcp->descs);
  394. free(pcp);
  395. }
  396. void Platform_setBindings(Htop_Action* keys) {
  397. /* no platform-specific key bindings */
  398. (void)keys;
  399. }
  400. int Platform_getUptime(void) {
  401. pmAtomValue value;
  402. if (Metric_values(PCP_UPTIME, &value, 1, PM_TYPE_32) == NULL)
  403. return 0;
  404. return value.l;
  405. }
  406. void Platform_getLoadAverage(double* one, double* five, double* fifteen) {
  407. *one = *five = *fifteen = 0.0;
  408. pmAtomValue values[3] = {0};
  409. if (Metric_values(PCP_LOAD_AVERAGE, values, 3, PM_TYPE_DOUBLE) != NULL) {
  410. *one = values[0].d;
  411. *five = values[1].d;
  412. *fifteen = values[2].d;
  413. }
  414. }
  415. unsigned int Platform_getMaxCPU(void) {
  416. if (pcp->ncpu)
  417. return pcp->ncpu;
  418. pmAtomValue value;
  419. if (Metric_values(PCP_HINV_NCPU, &value, 1, PM_TYPE_U32) != NULL)
  420. pcp->ncpu = value.ul;
  421. else
  422. pcp->ncpu = 1;
  423. return pcp->ncpu;
  424. }
  425. pid_t Platform_getMaxPid(void) {
  426. if (pcp->pidmax)
  427. return pcp->pidmax;
  428. pmAtomValue value;
  429. if (Metric_values(PCP_PID_MAX, &value, 1, PM_TYPE_32) == NULL)
  430. return INT_MAX;
  431. pcp->pidmax = value.l;
  432. return pcp->pidmax;
  433. }
  434. long long Platform_getBootTime(void) {
  435. if (pcp->btime)
  436. return pcp->btime;
  437. pmAtomValue value;
  438. if (Metric_values(PCP_BOOTTIME, &value, 1, PM_TYPE_64) != NULL)
  439. pcp->btime = value.ll;
  440. return pcp->btime;
  441. }
  442. static double Platform_setOneCPUValues(Meter* this, const Settings* settings, pmAtomValue* values) {
  443. unsigned long long value = values[CPU_TOTAL_PERIOD].ull;
  444. double total = (double) (value == 0 ? 1 : value);
  445. double percent;
  446. double* v = this->values;
  447. v[CPU_METER_NICE] = values[CPU_NICE_PERIOD].ull / total * 100.0;
  448. v[CPU_METER_NORMAL] = values[CPU_USER_PERIOD].ull / total * 100.0;
  449. if (settings->detailedCPUTime) {
  450. v[CPU_METER_KERNEL] = values[CPU_SYSTEM_PERIOD].ull / total * 100.0;
  451. v[CPU_METER_IRQ] = values[CPU_IRQ_PERIOD].ull / total * 100.0;
  452. v[CPU_METER_SOFTIRQ] = values[CPU_SOFTIRQ_PERIOD].ull / total * 100.0;
  453. this->curItems = 5;
  454. v[CPU_METER_STEAL] = values[CPU_STEAL_PERIOD].ull / total * 100.0;
  455. v[CPU_METER_GUEST] = values[CPU_GUEST_PERIOD].ull / total * 100.0;
  456. if (settings->accountGuestInCPUMeter) {
  457. this->curItems = 7;
  458. }
  459. v[CPU_METER_IOWAIT] = values[CPU_IOWAIT_PERIOD].ull / total * 100.0;
  460. } else {
  461. v[CPU_METER_KERNEL] = values[CPU_SYSTEM_ALL_PERIOD].ull / total * 100.0;
  462. value = values[CPU_STEAL_PERIOD].ull + values[CPU_GUEST_PERIOD].ull;
  463. v[CPU_METER_IRQ] = value / total * 100.0;
  464. this->curItems = 4;
  465. }
  466. percent = sumPositiveValues(v, this->curItems);
  467. percent = MINIMUM(percent, 100.0);
  468. if (settings->detailedCPUTime) {
  469. this->curItems = 8;
  470. }
  471. v[CPU_METER_FREQUENCY] = values[CPU_FREQUENCY].d;
  472. v[CPU_METER_TEMPERATURE] = NAN;
  473. return percent;
  474. }
  475. double Platform_setCPUValues(Meter* this, int cpu) {
  476. const PCPMachine* phost = (const PCPMachine*) this->host;
  477. const Settings* settings = this->host->settings;
  478. if (cpu <= 0) /* use aggregate values */
  479. return Platform_setOneCPUValues(this, settings, phost->cpu);
  480. return Platform_setOneCPUValues(this, settings, phost->percpu[cpu - 1]);
  481. }
  482. void Platform_setMemoryValues(Meter* this) {
  483. const Machine* host = this->host;
  484. const PCPMachine* phost = (const PCPMachine*) host;
  485. this->total = host->totalMem;
  486. this->values[MEMORY_METER_USED] = host->usedMem;
  487. this->values[MEMORY_METER_SHARED] = host->sharedMem;
  488. this->values[MEMORY_METER_COMPRESSED] = 0;
  489. this->values[MEMORY_METER_BUFFERS] = host->buffersMem;
  490. this->values[MEMORY_METER_CACHE] = host->cachedMem;
  491. this->values[MEMORY_METER_AVAILABLE] = host->availableMem;
  492. if (phost->zfs.enabled != 0) {
  493. // ZFS does not shrink below the value of zfs_arc_min.
  494. unsigned long long int shrinkableSize = 0;
  495. if (phost->zfs.size > phost->zfs.min)
  496. shrinkableSize = phost->zfs.size - phost->zfs.min;
  497. this->values[MEMORY_METER_USED] -= shrinkableSize;
  498. this->values[MEMORY_METER_CACHE] += shrinkableSize;
  499. this->values[MEMORY_METER_AVAILABLE] += shrinkableSize;
  500. }
  501. if (phost->zswap.usedZswapOrig > 0 || phost->zswap.usedZswapComp > 0) {
  502. this->values[MEMORY_METER_USED] -= phost->zswap.usedZswapComp;
  503. this->values[MEMORY_METER_COMPRESSED] += phost->zswap.usedZswapComp;
  504. }
  505. }
  506. void Platform_setSwapValues(Meter* this) {
  507. const Machine* host = this->host;
  508. const PCPMachine* phost = (const PCPMachine*) host;
  509. this->total = host->totalSwap;
  510. this->values[SWAP_METER_USED] = host->usedSwap;
  511. this->values[SWAP_METER_CACHE] = host->cachedSwap;
  512. this->values[SWAP_METER_FRONTSWAP] = 0; /* frontswap -- memory that is accounted to swap but resides elsewhere */
  513. if (phost->zswap.usedZswapOrig > 0 || phost->zswap.usedZswapComp > 0) {
  514. /* refer to linux/Platform.c::Platform_setSwapValues for details */
  515. this->values[SWAP_METER_USED] -= phost->zswap.usedZswapOrig;
  516. if (this->values[SWAP_METER_USED] < 0) {
  517. /* subtract the overflow from SwapCached */
  518. this->values[SWAP_METER_CACHE] += this->values[SWAP_METER_USED];
  519. this->values[SWAP_METER_USED] = 0;
  520. }
  521. this->values[SWAP_METER_FRONTSWAP] += phost->zswap.usedZswapOrig;
  522. }
  523. }
  524. void Platform_setZramValues(Meter* this) {
  525. int i, count = Metric_instanceCount(PCP_ZRAM_CAPACITY);
  526. if (!count) {
  527. this->total = 0;
  528. this->values[0] = 0;
  529. this->values[1] = 0;
  530. return;
  531. }
  532. pmAtomValue* values = xCalloc(count, sizeof(pmAtomValue));
  533. ZramStats stats = {0};
  534. if (Metric_values(PCP_ZRAM_CAPACITY, values, count, PM_TYPE_U64)) {
  535. for (i = 0; i < count; i++)
  536. stats.totalZram += values[i].ull;
  537. }
  538. if (Metric_values(PCP_ZRAM_ORIGINAL, values, count, PM_TYPE_U64)) {
  539. for (i = 0; i < count; i++)
  540. stats.usedZramOrig += values[i].ull;
  541. }
  542. if (Metric_values(PCP_ZRAM_COMPRESSED, values, count, PM_TYPE_U64)) {
  543. for (i = 0; i < count; i++)
  544. stats.usedZramComp += values[i].ull;
  545. }
  546. free(values);
  547. if (stats.usedZramComp > stats.usedZramOrig) {
  548. stats.usedZramComp = stats.usedZramOrig;
  549. }
  550. this->total = stats.totalZram;
  551. this->values[0] = stats.usedZramComp;
  552. this->values[1] = stats.usedZramOrig - stats.usedZramComp;
  553. }
  554. void Platform_setZfsArcValues(Meter* this) {
  555. const PCPMachine* phost = (const PCPMachine*) this->host;
  556. ZfsArcMeter_readStats(this, &phost->zfs);
  557. }
  558. void Platform_setZfsCompressedArcValues(Meter* this) {
  559. const PCPMachine* phost = (const PCPMachine*) this->host;
  560. ZfsCompressedArcMeter_readStats(this, &phost->zfs);
  561. }
  562. void Platform_getHostname(char* buffer, size_t size) {
  563. const char* hostname = pmGetContextHostName(pcp->context);
  564. String_safeStrncpy(buffer, hostname, size);
  565. }
  566. void Platform_getRelease(char** string) {
  567. /* fast-path - previously-formatted string */
  568. if (string) {
  569. *string = pcp->release;
  570. return;
  571. }
  572. /* first call, extract just-sampled values */
  573. pmAtomValue sysname, release, machine, distro;
  574. if (!Metric_values(PCP_UNAME_SYSNAME, &sysname, 1, PM_TYPE_STRING))
  575. sysname.cp = NULL;
  576. if (!Metric_values(PCP_UNAME_RELEASE, &release, 1, PM_TYPE_STRING))
  577. release.cp = NULL;
  578. if (!Metric_values(PCP_UNAME_MACHINE, &machine, 1, PM_TYPE_STRING))
  579. machine.cp = NULL;
  580. if (!Metric_values(PCP_UNAME_DISTRO, &distro, 1, PM_TYPE_STRING))
  581. distro.cp = NULL;
  582. size_t length = 16; /* padded for formatting characters */
  583. if (sysname.cp)
  584. length += strlen(sysname.cp);
  585. if (release.cp)
  586. length += strlen(release.cp);
  587. if (machine.cp)
  588. length += strlen(machine.cp);
  589. if (distro.cp)
  590. length += strlen(distro.cp);
  591. pcp->release = xCalloc(1, length);
  592. if (sysname.cp) {
  593. strcat(pcp->release, sysname.cp);
  594. strcat(pcp->release, " ");
  595. }
  596. if (release.cp) {
  597. strcat(pcp->release, release.cp);
  598. strcat(pcp->release, " ");
  599. }
  600. if (machine.cp) {
  601. strcat(pcp->release, "[");
  602. strcat(pcp->release, machine.cp);
  603. strcat(pcp->release, "] ");
  604. }
  605. if (distro.cp) {
  606. if (pcp->release[0] != '\0') {
  607. strcat(pcp->release, "@ ");
  608. strcat(pcp->release, distro.cp);
  609. } else {
  610. strcat(pcp->release, distro.cp);
  611. }
  612. strcat(pcp->release, " ");
  613. }
  614. if (pcp->release) /* cull trailing space */
  615. pcp->release[strlen(pcp->release)] = '\0';
  616. free(distro.cp);
  617. free(machine.cp);
  618. free(release.cp);
  619. free(sysname.cp);
  620. }
  621. char* Platform_getProcessEnv(pid_t pid) {
  622. pmAtomValue value;
  623. if (!Metric_instance(PCP_PROC_ENVIRON, pid, 0, &value, PM_TYPE_STRING))
  624. return NULL;
  625. return value.cp;
  626. }
  627. FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid) {
  628. (void)pid;
  629. return NULL;
  630. }
  631. void Platform_getPressureStall(const char* file, bool some, double* ten, double* sixty, double* threehundred) {
  632. *ten = *sixty = *threehundred = 0;
  633. Metric metric;
  634. if (String_eq(file, "cpu"))
  635. metric = PCP_PSI_CPUSOME;
  636. else if (String_eq(file, "io"))
  637. metric = some ? PCP_PSI_IOSOME : PCP_PSI_IOFULL;
  638. else if (String_eq(file, "irq"))
  639. metric = PCP_PSI_IRQFULL;
  640. else if (String_eq(file, "mem"))
  641. metric = some ? PCP_PSI_MEMSOME : PCP_PSI_MEMFULL;
  642. else
  643. return;
  644. pmAtomValue values[3] = {0};
  645. if (Metric_values(metric, values, 3, PM_TYPE_DOUBLE) != NULL) {
  646. *ten = values[0].d;
  647. *sixty = values[1].d;
  648. *threehundred = values[2].d;
  649. }
  650. }
  651. bool Platform_getDiskIO(DiskIOData* data) {
  652. memset(data, 0, sizeof(*data));
  653. pmAtomValue value;
  654. if (Metric_values(PCP_DISK_READB, &value, 1, PM_TYPE_U64) != NULL)
  655. data->totalBytesRead = value.ull;
  656. if (Metric_values(PCP_DISK_WRITEB, &value, 1, PM_TYPE_U64) != NULL)
  657. data->totalBytesWritten = value.ull;
  658. if (Metric_values(PCP_DISK_ACTIVE, &value, 1, PM_TYPE_U64) != NULL)
  659. data->totalMsTimeSpend = value.ull;
  660. if (Metric_values(PCP_HINV_NDISK, &value, 1, PM_TYPE_U64) != NULL)
  661. data->numDisks = value.ull;
  662. return true;
  663. }
  664. bool Platform_getNetworkIO(NetworkIOData* data) {
  665. memset(data, 0, sizeof(*data));
  666. pmAtomValue value;
  667. if (Metric_values(PCP_NET_RECVB, &value, 1, PM_TYPE_U64) != NULL)
  668. data->bytesReceived = value.ull;
  669. if (Metric_values(PCP_NET_SENDB, &value, 1, PM_TYPE_U64) != NULL)
  670. data->bytesTransmitted = value.ull;
  671. if (Metric_values(PCP_NET_RECVP, &value, 1, PM_TYPE_U64) != NULL)
  672. data->packetsReceived = value.ull;
  673. if (Metric_values(PCP_NET_SENDP, &value, 1, PM_TYPE_U64) != NULL)
  674. data->packetsTransmitted = value.ull;
  675. return true;
  676. }
  677. void Platform_getFileDescriptors(double* used, double* max) {
  678. *used = NAN;
  679. *max = 65536;
  680. pmAtomValue value;
  681. if (Metric_values(PCP_VFS_FILES_COUNT, &value, 1, PM_TYPE_32) != NULL)
  682. *used = value.l;
  683. if (Metric_values(PCP_VFS_FILES_MAX, &value, 1, PM_TYPE_32) != NULL)
  684. *max = value.l;
  685. }
  686. void Platform_getBattery(double* level, ACPresence* isOnAC) {
  687. *level = NAN;
  688. *isOnAC = AC_ERROR;
  689. }
  690. void Platform_longOptionsUsage(ATTR_UNUSED const char* name) {
  691. printf(
  692. " --host=HOSTSPEC metrics source is PMCD at HOSTSPEC [see PCPIntro(1)]\n"
  693. " --hostzone set reporting timezone to local time of metrics source\n"
  694. " --timezone=TZ set reporting timezone\n");
  695. }
  696. CommandLineStatus Platform_getLongOption(int opt, ATTR_UNUSED int argc, char** argv) {
  697. /* libpcp export without a header definition */
  698. extern void __pmAddOptHost(pmOptions*, char*);
  699. switch (opt) {
  700. case PLATFORM_LONGOPT_HOST: /* --host=HOSTSPEC */
  701. if (argv[optind][0] == '\0')
  702. return STATUS_ERROR_EXIT;
  703. __pmAddOptHost(&opts, optarg);
  704. return STATUS_OK;
  705. case PLATFORM_LONGOPT_HOSTZONE: /* --hostzone */
  706. if (opts.timezone) {
  707. pmprintf("%s: at most one of -Z and -z allowed\n", pmGetProgname());
  708. opts.errors++;
  709. } else {
  710. opts.tzflag = 1;
  711. }
  712. return STATUS_OK;
  713. case PLATFORM_LONGOPT_TIMEZONE: /* --timezone=TZ */
  714. if (argv[optind][0] == '\0')
  715. return STATUS_ERROR_EXIT;
  716. if (opts.tzflag) {
  717. pmprintf("%s: at most one of -Z and -z allowed\n", pmGetProgname());
  718. opts.errors++;
  719. } else {
  720. opts.timezone = optarg;
  721. }
  722. return STATUS_OK;
  723. default:
  724. break;
  725. }
  726. return STATUS_ERROR_EXIT;
  727. }
  728. void Platform_gettime_realtime(struct timeval* tv, uint64_t* msec) {
  729. if (gettimeofday(tv, NULL) == 0) {
  730. /* shift by start offset to stay in lock-step with realtime (archives) */
  731. if (pcp->offset.tv_sec || pcp->offset.tv_usec)
  732. pmtimevalDec(tv, &pcp->offset);
  733. *msec = ((uint64_t)tv->tv_sec * 1000) + ((uint64_t)tv->tv_usec / 1000);
  734. } else {
  735. memset(tv, 0, sizeof(struct timeval));
  736. *msec = 0;
  737. }
  738. }
  739. void Platform_gettime_monotonic(uint64_t* msec) {
  740. if (pcp->result) {
  741. struct timeval* tv = &pcp->result->timestamp;
  742. *msec = ((uint64_t)tv->tv_sec * 1000) + ((uint64_t)tv->tv_usec / 1000);
  743. } else {
  744. *msec = 0;
  745. }
  746. }
  747. Hashtable* Platform_dynamicMeters(void) {
  748. return pcp->meters.table;
  749. }
  750. void Platform_dynamicMeterInit(Meter* meter) {
  751. PCPDynamicMeter* this = Hashtable_get(pcp->meters.table, meter->param);
  752. if (this)
  753. PCPDynamicMeter_enable(this);
  754. }
  755. void Platform_dynamicMeterUpdateValues(Meter* meter) {
  756. PCPDynamicMeter* this = Hashtable_get(pcp->meters.table, meter->param);
  757. if (this)
  758. PCPDynamicMeter_updateValues(this, meter);
  759. }
  760. void Platform_dynamicMeterDisplay(const Meter* meter, RichString* out) {
  761. PCPDynamicMeter* this = Hashtable_get(pcp->meters.table, meter->param);
  762. if (this)
  763. PCPDynamicMeter_display(this, meter, out);
  764. }
  765. Hashtable* Platform_dynamicColumns(void) {
  766. return pcp->columns.table;
  767. }
  768. const char* Platform_dynamicColumnName(unsigned int key) {
  769. PCPDynamicColumn* this = Hashtable_get(pcp->columns.table, key);
  770. if (this) {
  771. Metric_enable(this->id, true);
  772. if (this->super.caption)
  773. return this->super.caption;
  774. if (this->super.heading)
  775. return this->super.heading;
  776. return this->super.name;
  777. }
  778. return NULL;
  779. }
  780. bool Platform_dynamicColumnWriteField(const Process* proc, RichString* str, unsigned int key) {
  781. PCPDynamicColumn* this = Hashtable_get(pcp->columns.table, key);
  782. if (this) {
  783. PCPDynamicColumn_writeField(this, proc, str);
  784. return true;
  785. }
  786. return false;
  787. }
  788. Hashtable* Platform_dynamicScreens(void) {
  789. return pcp->screens.table;
  790. }
  791. void Platform_defaultDynamicScreens(Settings* settings) {
  792. PCPDynamicScreen_appendScreens(&pcp->screens, settings);
  793. }
  794. void Platform_addDynamicScreen(ScreenSettings* ss) {
  795. PCPDynamicScreen_addDynamicScreen(&pcp->screens, ss);
  796. }
  797. void Platform_addDynamicScreenAvailableColumns(Panel* availableColumns, const char* screen) {
  798. Hashtable* screens = pcp->screens.table;
  799. PCPDynamicScreens_addAvailableColumns(availableColumns, screens, screen);
  800. }
  801. void Platform_updateTables(Machine* host) {
  802. PCPDynamicScreen_appendTables(&pcp->screens, host);
  803. PCPDynamicColumns_setupWidths(&pcp->columns);
  804. }