PCPProcessTable.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. /*
  2. htop - PCPProcessTable.c
  3. (C) 2014 Hisham H. Muhammad
  4. (C) 2020-2021 htop dev team
  5. (C) 2020-2021 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/PCPProcessTable.h"
  11. #include <assert.h>
  12. #include <limits.h>
  13. #include <math.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <sys/time.h>
  17. #include "Machine.h"
  18. #include "Macros.h"
  19. #include "Object.h"
  20. #include "Platform.h"
  21. #include "Process.h"
  22. #include "Settings.h"
  23. #include "XUtils.h"
  24. #include "linux/CGroupUtils.h"
  25. #include "pcp/Metric.h"
  26. #include "pcp/PCPMachine.h"
  27. #include "pcp/PCPProcess.h"
  28. ProcessTable* ProcessTable_new(Machine* host, Hashtable* pidMatchList) {
  29. PCPProcessTable* this = xCalloc(1, sizeof(PCPProcessTable));
  30. Object_setClass(this, Class(ProcessTable));
  31. ProcessTable* super = &this->super;
  32. ProcessTable_init(super, Class(PCPProcess), host, pidMatchList);
  33. return super;
  34. }
  35. void ProcessTable_delete(Object* cast) {
  36. PCPProcessTable* this = (PCPProcessTable*) cast;
  37. ProcessTable_done(&this->super);
  38. free(this);
  39. }
  40. static inline long Metric_instance_s32(int metric, int pid, int offset, long fallback) {
  41. pmAtomValue value;
  42. if (Metric_instance(metric, pid, offset, &value, PM_TYPE_32))
  43. return value.l;
  44. return fallback;
  45. }
  46. static inline long long Metric_instance_s64(int metric, int pid, int offset, long long fallback) {
  47. pmAtomValue value;
  48. if (Metric_instance(metric, pid, offset, &value, PM_TYPE_64))
  49. return value.l;
  50. return fallback;
  51. }
  52. static inline unsigned long Metric_instance_u32(int metric, int pid, int offset, unsigned long fallback) {
  53. pmAtomValue value;
  54. if (Metric_instance(metric, pid, offset, &value, PM_TYPE_U32))
  55. return value.ul;
  56. return fallback;
  57. }
  58. static inline unsigned long long Metric_instance_u64(int metric, int pid, int offset, unsigned long long fallback) {
  59. pmAtomValue value;
  60. if (Metric_instance(metric, pid, offset, &value, PM_TYPE_U64))
  61. return value.ull;
  62. return fallback;
  63. }
  64. static inline unsigned long long Metric_instance_time(int metric, int pid, int offset) {
  65. pmAtomValue value;
  66. if (Metric_instance(metric, pid, offset, &value, PM_TYPE_U64))
  67. return value.ull / 10;
  68. return 0;
  69. }
  70. static inline unsigned long long Metric_instance_ONE_K(int metric, int pid, int offset) {
  71. pmAtomValue value;
  72. if (Metric_instance(metric, pid, offset, &value, PM_TYPE_U64))
  73. return value.ull / ONE_K;
  74. return ULLONG_MAX;
  75. }
  76. static inline char Metric_instance_char(int metric, int pid, int offset, char fallback) {
  77. pmAtomValue value;
  78. if (Metric_instance(metric, pid, offset, &value, PM_TYPE_STRING)) {
  79. char uchar = value.cp[0];
  80. free(value.cp);
  81. return uchar;
  82. }
  83. return fallback;
  84. }
  85. static char* setUser(UsersTable* this, unsigned int uid, int pid, int offset) {
  86. char* name = Hashtable_get(this->users, uid);
  87. if (name)
  88. return name;
  89. pmAtomValue value;
  90. if (Metric_instance(PCP_PROC_ID_USER, pid, offset, &value, PM_TYPE_STRING)) {
  91. Hashtable_put(this->users, uid, value.cp);
  92. name = value.cp;
  93. }
  94. return name;
  95. }
  96. static inline ProcessState PCPProcessTable_getProcessState(char state) {
  97. switch (state) {
  98. case '?': return UNKNOWN;
  99. case 'R': return RUNNING;
  100. case 'W': return WAITING;
  101. case 'D': return UNINTERRUPTIBLE_WAIT;
  102. case 'P': return PAGING;
  103. case 'T': return STOPPED;
  104. case 't': return TRACED;
  105. case 'Z': return ZOMBIE;
  106. case 'X': return DEFUNCT;
  107. case 'I': return IDLE;
  108. case 'S': return SLEEPING;
  109. default: return UNKNOWN;
  110. }
  111. }
  112. static void PCPProcessTable_updateID(Process* process, int pid, int offset) {
  113. Process_setThreadGroup(process, Metric_instance_u32(PCP_PROC_TGID, pid, offset, 1));
  114. Process_setParent(process, Metric_instance_u32(PCP_PROC_PPID, pid, offset, 1));
  115. process->state = PCPProcessTable_getProcessState(Metric_instance_char(PCP_PROC_STATE, pid, offset, '?'));
  116. }
  117. static void PCPProcessTable_updateInfo(PCPProcess* pp, int pid, int offset, char* command, size_t commLen) {
  118. Process* process = &pp->super;
  119. pmAtomValue value;
  120. if (!Metric_instance(PCP_PROC_CMD, pid, offset, &value, PM_TYPE_STRING))
  121. value.cp = xStrdup("<unknown>");
  122. String_safeStrncpy(command, value.cp, commLen);
  123. free(value.cp);
  124. process->pgrp = Metric_instance_u32(PCP_PROC_PGRP, pid, offset, 0);
  125. process->session = Metric_instance_u32(PCP_PROC_SESSION, pid, offset, 0);
  126. process->tty_nr = Metric_instance_u32(PCP_PROC_TTY, pid, offset, 0);
  127. process->tpgid = Metric_instance_u32(PCP_PROC_TTYPGRP, pid, offset, 0);
  128. process->minflt = Metric_instance_u32(PCP_PROC_MINFLT, pid, offset, 0);
  129. pp->cminflt = Metric_instance_u32(PCP_PROC_CMINFLT, pid, offset, 0);
  130. process->majflt = Metric_instance_u32(PCP_PROC_MAJFLT, pid, offset, 0);
  131. pp->cmajflt = Metric_instance_u32(PCP_PROC_CMAJFLT, pid, offset, 0);
  132. pp->utime = Metric_instance_time(PCP_PROC_UTIME, pid, offset);
  133. pp->stime = Metric_instance_time(PCP_PROC_STIME, pid, offset);
  134. pp->cutime = Metric_instance_time(PCP_PROC_CUTIME, pid, offset);
  135. pp->cstime = Metric_instance_time(PCP_PROC_CSTIME, pid, offset);
  136. process->priority = Metric_instance_u32(PCP_PROC_PRIORITY, pid, offset, 0);
  137. process->nice = Metric_instance_s32(PCP_PROC_NICE, pid, offset, 0);
  138. process->nlwp = Metric_instance_u32(PCP_PROC_THREADS, pid, offset, 0);
  139. process->starttime_ctime = Metric_instance_time(PCP_PROC_STARTTIME, pid, offset);
  140. process->processor = Metric_instance_u32(PCP_PROC_PROCESSOR, pid, offset, 0);
  141. process->time = pp->utime + pp->stime;
  142. }
  143. static void PCPProcessTable_updateIO(PCPProcess* pp, int pid, int offset, unsigned long long now) {
  144. pmAtomValue value;
  145. pp->io_rchar = Metric_instance_ONE_K(PCP_PROC_IO_RCHAR, pid, offset);
  146. pp->io_wchar = Metric_instance_ONE_K(PCP_PROC_IO_WCHAR, pid, offset);
  147. pp->io_syscr = Metric_instance_u64(PCP_PROC_IO_SYSCR, pid, offset, ULLONG_MAX);
  148. pp->io_syscw = Metric_instance_u64(PCP_PROC_IO_SYSCW, pid, offset, ULLONG_MAX);
  149. pp->io_cancelled_write_bytes = Metric_instance_ONE_K(PCP_PROC_IO_CANCELLED, pid, offset);
  150. if (Metric_instance(PCP_PROC_IO_READB, pid, offset, &value, PM_TYPE_U64)) {
  151. unsigned long long last_read = pp->io_read_bytes;
  152. pp->io_read_bytes = value.ull / ONE_K;
  153. pp->io_rate_read_bps = ONE_K * (pp->io_read_bytes - last_read) /
  154. (now - pp->io_last_scan_time);
  155. } else {
  156. pp->io_read_bytes = ULLONG_MAX;
  157. pp->io_rate_read_bps = NAN;
  158. }
  159. if (Metric_instance(PCP_PROC_IO_WRITEB, pid, offset, &value, PM_TYPE_U64)) {
  160. unsigned long long last_write = pp->io_write_bytes;
  161. pp->io_write_bytes = value.ull;
  162. pp->io_rate_write_bps = ONE_K * (pp->io_write_bytes - last_write) /
  163. (now - pp->io_last_scan_time);
  164. } else {
  165. pp->io_write_bytes = ULLONG_MAX;
  166. pp->io_rate_write_bps = NAN;
  167. }
  168. pp->io_last_scan_time = now;
  169. }
  170. static void PCPProcessTable_updateMemory(PCPProcess* pp, int pid, int offset) {
  171. pp->super.m_virt = Metric_instance_u32(PCP_PROC_MEM_SIZE, pid, offset, 0);
  172. pp->super.m_resident = Metric_instance_u32(PCP_PROC_MEM_RSS, pid, offset, 0);
  173. pp->m_share = Metric_instance_u32(PCP_PROC_MEM_SHARE, pid, offset, 0);
  174. pp->m_priv = pp->super.m_resident - pp->m_share;
  175. pp->m_trs = Metric_instance_u32(PCP_PROC_MEM_TEXTRS, pid, offset, 0);
  176. pp->m_lrs = Metric_instance_u32(PCP_PROC_MEM_LIBRS, pid, offset, 0);
  177. pp->m_drs = Metric_instance_u32(PCP_PROC_MEM_DATRS, pid, offset, 0);
  178. pp->m_dt = Metric_instance_u32(PCP_PROC_MEM_DIRTY, pid, offset, 0);
  179. }
  180. static void PCPProcessTable_updateSmaps(PCPProcess* pp, pid_t pid, int offset) {
  181. pp->m_pss = Metric_instance_u64(PCP_PROC_SMAPS_PSS, pid, offset, 0);
  182. pp->m_swap = Metric_instance_u64(PCP_PROC_SMAPS_SWAP, pid, offset, 0);
  183. pp->m_psswp = Metric_instance_u64(PCP_PROC_SMAPS_SWAPPSS, pid, offset, 0);
  184. }
  185. static void PCPProcessTable_readOomData(PCPProcess* pp, int pid, int offset) {
  186. pp->oom = Metric_instance_u32(PCP_PROC_OOMSCORE, pid, offset, 0);
  187. }
  188. static void PCPProcessTable_readAutogroup(PCPProcess* pp, int pid, int offset) {
  189. pp->autogroup_id = Metric_instance_s64(PCP_PROC_AUTOGROUP_ID, pid, offset, -1);
  190. pp->autogroup_nice = Metric_instance_s32(PCP_PROC_AUTOGROUP_NICE, pid, offset, 0);
  191. }
  192. static void PCPProcessTable_readCtxtData(PCPProcess* pp, int pid, int offset) {
  193. pmAtomValue value;
  194. unsigned long ctxt = 0;
  195. if (Metric_instance(PCP_PROC_VCTXSW, pid, offset, &value, PM_TYPE_U32))
  196. ctxt += value.ul;
  197. if (Metric_instance(PCP_PROC_NVCTXSW, pid, offset, &value, PM_TYPE_U32))
  198. ctxt += value.ul;
  199. pp->ctxt_diff = ctxt > pp->ctxt_total ? ctxt - pp->ctxt_total : 0;
  200. pp->ctxt_total = ctxt;
  201. }
  202. static char* setString(Metric metric, int pid, int offset, char* string) {
  203. if (string)
  204. free(string);
  205. pmAtomValue value;
  206. if (Metric_instance(metric, pid, offset, &value, PM_TYPE_STRING))
  207. string = value.cp;
  208. else
  209. string = NULL;
  210. return string;
  211. }
  212. static void PCPProcessTable_updateTTY(Process* process, int pid, int offset) {
  213. process->tty_name = setString(PCP_PROC_TTYNAME, pid, offset, process->tty_name);
  214. }
  215. static void PCPProcessTable_readCGroups(PCPProcess* pp, int pid, int offset) {
  216. pp->cgroup = setString(PCP_PROC_CGROUPS, pid, offset, pp->cgroup);
  217. if (pp->cgroup) {
  218. char* cgroup_short = CGroup_filterName(pp->cgroup);
  219. if (cgroup_short) {
  220. Row_updateFieldWidth(CCGROUP, strlen(cgroup_short));
  221. free_and_xStrdup(&pp->cgroup_short, cgroup_short);
  222. free(cgroup_short);
  223. } else {
  224. //CCGROUP is alias to normal CGROUP if shortening fails
  225. Row_updateFieldWidth(CCGROUP, strlen(pp->cgroup));
  226. free(pp->cgroup_short);
  227. pp->cgroup_short = NULL;
  228. }
  229. char* container_short = CGroup_filterName(pp->cgroup);
  230. if (container_short) {
  231. Row_updateFieldWidth(CONTAINER, strlen(container_short));
  232. free_and_xStrdup(&pp->container_short, container_short);
  233. free(container_short);
  234. } else {
  235. Row_updateFieldWidth(CONTAINER, strlen("N/A"));
  236. free(pp->container_short);
  237. pp->container_short = NULL;
  238. }
  239. } else {
  240. free(pp->cgroup_short);
  241. pp->cgroup_short = NULL;
  242. free(pp->container_short);
  243. pp->container_short = NULL;
  244. }
  245. }
  246. static void PCPProcessTable_readSecattrData(PCPProcess* pp, int pid, int offset) {
  247. pp->secattr = setString(PCP_PROC_LABELS, pid, offset, pp->secattr);
  248. }
  249. static void PCPProcessTable_readCwd(PCPProcess* pp, int pid, int offset) {
  250. pp->super.procCwd = setString(PCP_PROC_CWD, pid, offset, pp->super.procCwd);
  251. }
  252. static void PCPProcessTable_updateUsername(Process* process, int pid, int offset, UsersTable* users) {
  253. process->st_uid = Metric_instance_u32(PCP_PROC_ID_UID, pid, offset, 0);
  254. process->user = setUser(users, process->st_uid, pid, offset);
  255. }
  256. static void PCPProcessTable_updateCmdline(Process* process, int pid, int offset, const char* comm) {
  257. pmAtomValue value;
  258. if (!Metric_instance(PCP_PROC_PSARGS, pid, offset, &value, PM_TYPE_STRING)) {
  259. if (process->state != ZOMBIE)
  260. process->isKernelThread = true;
  261. Process_updateCmdline(process, NULL, 0, 0);
  262. return;
  263. }
  264. char* command = value.cp;
  265. int length = strlen(command);
  266. if (command[0] != '(') {
  267. process->isKernelThread = false;
  268. } else {
  269. ++command;
  270. --length;
  271. if (command[length - 1] == ')')
  272. command[--length] = '\0';
  273. process->isKernelThread = true;
  274. }
  275. int tokenEnd = 0;
  276. int tokenStart = 0;
  277. bool argSepSpace = false;
  278. for (int i = 0; i < length; i++) {
  279. /* htop considers the next character after the last / that is before
  280. * basenameOffset, as the start of the basename in cmdline - see
  281. * Process_writeCommand */
  282. if (command[i] == '/')
  283. tokenStart = i + 1;
  284. /* special-case arguments for problematic situations like "find /" */
  285. if (command[i] <= ' ')
  286. argSepSpace = true;
  287. }
  288. tokenEnd = length;
  289. if (argSepSpace)
  290. tokenStart = 0;
  291. Process_updateCmdline(process, command, tokenStart, tokenEnd);
  292. free(value.cp);
  293. Process_updateComm(process, comm);
  294. if (Metric_instance(PCP_PROC_EXE, pid, offset, &value, PM_TYPE_STRING)) {
  295. Process_updateExe(process, value.cp[0] ? value.cp : NULL);
  296. free(value.cp);
  297. }
  298. }
  299. static bool PCPProcessTable_updateProcesses(PCPProcessTable* this) {
  300. ProcessTable* pt = (ProcessTable*) this;
  301. Machine* host = pt->super.host;
  302. PCPMachine* phost = (PCPMachine*) host;
  303. const Settings* settings = host->settings;
  304. bool hideKernelThreads = settings->hideKernelThreads;
  305. bool hideUserlandThreads = settings->hideUserlandThreads;
  306. uint32_t flags = settings->ss->flags;
  307. unsigned long long now = (unsigned long long)(phost->timestamp * 1000);
  308. int pid = -1, offset = -1;
  309. /* for every process ... */
  310. while (Metric_iterate(PCP_PROC_PID, &pid, &offset)) {
  311. bool preExisting;
  312. Process* proc = ProcessTable_getProcess(pt, pid, &preExisting, PCPProcess_new);
  313. PCPProcess* pp = (PCPProcess*) proc;
  314. PCPProcessTable_updateID(proc, pid, offset);
  315. proc->isUserlandThread = Process_getPid(proc) != Process_getThreadGroup(proc);
  316. pp->offset = offset >= 0 ? offset : 0;
  317. /*
  318. * These conditions will not trigger on first occurrence, cause we need to
  319. * add the process to the ProcessTable and do all one time scans
  320. * (e.g. parsing the cmdline to detect a kernel thread)
  321. * But it will short-circuit subsequent scans.
  322. */
  323. if (preExisting && hideKernelThreads && Process_isKernelThread(proc)) {
  324. proc->super.updated = true;
  325. proc->super.show = false;
  326. if (proc->state == RUNNING)
  327. pt->runningTasks++;
  328. pt->kernelThreads++;
  329. pt->totalTasks++;
  330. continue;
  331. }
  332. if (preExisting && hideUserlandThreads && Process_isUserlandThread(proc)) {
  333. proc->super.updated = true;
  334. proc->super.show = false;
  335. if (proc->state == RUNNING)
  336. pt->runningTasks++;
  337. pt->userlandThreads++;
  338. pt->totalTasks++;
  339. continue;
  340. }
  341. if (flags & PROCESS_FLAG_IO)
  342. PCPProcessTable_updateIO(pp, pid, offset, now);
  343. PCPProcessTable_updateMemory(pp, pid, offset);
  344. if ((flags & PROCESS_FLAG_LINUX_SMAPS) && !Process_isKernelThread(proc)) {
  345. if (Metric_enabled(PCP_PROC_SMAPS_PSS)) {
  346. PCPProcessTable_updateSmaps(pp, pid, offset);
  347. }
  348. }
  349. char command[MAX_NAME + 1];
  350. unsigned int tty_nr = proc->tty_nr;
  351. unsigned long long int lasttimes = pp->utime + pp->stime;
  352. PCPProcessTable_updateInfo(pp, pid, offset, command, sizeof(command));
  353. proc->starttime_ctime += Platform_getBootTime();
  354. if (tty_nr != proc->tty_nr)
  355. PCPProcessTable_updateTTY(proc, pid, offset);
  356. proc->percent_cpu = NAN;
  357. if (phost->period > 0.0) {
  358. float percent_cpu = saturatingSub(pp->utime + pp->stime, lasttimes) / phost->period * 100.0;
  359. proc->percent_cpu = MINIMUM(percent_cpu, host->activeCPUs * 100.0F);
  360. }
  361. proc->percent_mem = proc->m_resident / (double) host->totalMem * 100.0;
  362. Process_updateCPUFieldWidths(proc->percent_cpu);
  363. PCPProcessTable_updateUsername(proc, pid, offset, host->usersTable);
  364. if (!preExisting) {
  365. PCPProcessTable_updateCmdline(proc, pid, offset, command);
  366. Process_fillStarttimeBuffer(proc);
  367. ProcessTable_add(pt, proc);
  368. } else if (settings->updateProcessNames && proc->state != ZOMBIE) {
  369. PCPProcessTable_updateCmdline(proc, pid, offset, command);
  370. }
  371. if (flags & PROCESS_FLAG_LINUX_CGROUP)
  372. PCPProcessTable_readCGroups(pp, pid, offset);
  373. if (flags & PROCESS_FLAG_LINUX_OOM)
  374. PCPProcessTable_readOomData(pp, pid, offset);
  375. if (flags & PROCESS_FLAG_LINUX_CTXT)
  376. PCPProcessTable_readCtxtData(pp, pid, offset);
  377. if (flags & PROCESS_FLAG_LINUX_SECATTR)
  378. PCPProcessTable_readSecattrData(pp, pid, offset);
  379. if (flags & PROCESS_FLAG_CWD)
  380. PCPProcessTable_readCwd(pp, pid, offset);
  381. if (flags & PROCESS_FLAG_LINUX_AUTOGROUP)
  382. PCPProcessTable_readAutogroup(pp, pid, offset);
  383. if (proc->state == ZOMBIE && !proc->cmdline && command[0]) {
  384. Process_updateCmdline(proc, command, 0, strlen(command));
  385. } else if (Process_isThread(proc)) {
  386. if ((settings->showThreadNames || Process_isKernelThread(proc)) && command[0]) {
  387. Process_updateCmdline(proc, command, 0, strlen(command));
  388. }
  389. if (Process_isKernelThread(proc)) {
  390. pt->kernelThreads++;
  391. } else {
  392. pt->userlandThreads++;
  393. }
  394. }
  395. /* Set at the end when we know if a new entry is a thread */
  396. proc->super.show = ! ((hideKernelThreads && Process_isKernelThread(proc)) ||
  397. (hideUserlandThreads && Process_isUserlandThread(proc)));
  398. pt->totalTasks++;
  399. if (proc->state == RUNNING)
  400. pt->runningTasks++;
  401. proc->super.updated = true;
  402. }
  403. return true;
  404. }
  405. void ProcessTable_goThroughEntries(ProcessTable* super) {
  406. PCPProcessTable* this = (PCPProcessTable*) super;
  407. PCPProcessTable_updateProcesses(this);
  408. }