Platform.c 29 KB

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