2 * pidstat: Report statistics for Linux tasks
3 * (C) 2007-2020 by Sebastien GODARD (sysstat <at> orange.fr)
5 ***************************************************************************
6 * This program is free software; you can redistribute it and/or modify it *
7 * under the terms of the GNU General Public License as published by the *
8 * Free Software Foundation; either version 2 of the License, or (at your *
9 * option) any later version. *
11 * This program is distributed in the hope that it will be useful, but *
12 * WITHOUT ANY WARRANTY; without the implied warranty of MERCHANTABILITY *
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
16 * You should have received a copy of the GNU General Public License along *
17 * with this program; if not, write to the Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA *
19 ***************************************************************************
30 #include <sys/types.h>
32 #include <sys/utsname.h>
35 #ifdef HAVE_LINUX_SCHED_H
36 #include <linux/sched.h>
47 #define _(string) gettext(string)
49 #define _(string) (string)
53 #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__
54 char *sccsid(void) { return (SCCSID); }
57 unsigned long long tot_jiffies[3] = {0, 0, 0};
58 unsigned long long uptime_cs[3] = {0, 0, 0};
59 struct st_pid *pid_list = NULL;
61 struct tm ps_tstamp[3];
62 char commstr[MAX_COMM_LEN];
63 char userstr[MAX_USER_LEN];
64 char procstr[MAX_COMM_LEN];
66 int cpu_nr = 0; /* Nb of processors on the machine */
67 unsigned long tlmkb; /* Total memory in kB */
70 unsigned int pidflag = 0; /* General flags */
71 unsigned int tskflag = 0; /* TASK/CHILD stats */
72 unsigned int actflag = 0; /* Activity flag */
74 struct sigaction alrm_act, int_act, chld_act;
75 int signal_caught = 0;
77 int dplaces_nr = -1; /* Number of decimal places */
80 ***************************************************************************
81 * Print usage and exit.
84 * @progname Name of sysstat command
85 ***************************************************************************
87 void usage(char *progname)
89 fprintf(stderr, _("Usage: %s [ options ] [ <interval> [ <count> ] ] [ -e <program> <args> ]\n"),
92 fprintf(stderr, _("Options are:\n"
93 "[ -d ] [ -H ] [ -h ] [ -I ] [ -l ] [ -R ] [ -r ] [ -s ] [ -t ] [ -U [ <username> ] ]\n"
94 "[ -u ] [ -V ] [ -v ] [ -w ] [ -C <command> ] [ -G <process_name> ]\n"
95 "[ -p { <pid> [,...] | SELF | ALL } ] [ -T { TASK | CHILD | ALL } ]\n"
96 "[ --dec={ 0 | 1 | 2 } ] [ --human ]\n"));
101 ***************************************************************************
102 * SIGALRM signal handler. No need to reset the handler here.
105 * @sig Signal number.
106 ***************************************************************************
108 void alarm_handler(int sig)
114 ***************************************************************************
115 * SIGINT and SIGCHLD signals handler.
118 * @sig Signal number.
119 ***************************************************************************
121 void int_handler(int sig)
127 ***************************************************************************
128 * Free unused PID structures.
131 * @plist Pointer address on the start of the linked list.
132 * @force Set to TRUE if all PID structures shall be freed.
133 ***************************************************************************
135 void sfree_pid(struct st_pid **plist, int force)
140 while (*plist != NULL) {
142 if (!p->exist || force) {
144 for (i = 0; i < 3; i++) {
158 ***************************************************************************
159 * Set every PID in list to nonexistent status.
162 * @plist Pointer on the start of the linked list.
163 ***************************************************************************
165 void set_pid_nonexistent(struct st_pid *plist)
167 while (plist != NULL) {
168 plist->exist = FALSE;
174 ***************************************************************************
175 * Check flags and set default values.
176 ***************************************************************************
178 void check_flags(void)
180 unsigned int act = 0;
182 /* Display CPU usage for active tasks by default */
187 if (!DISPLAY_PID(pidflag)) {
188 pidflag |= P_D_ACTIVE_PID + P_D_PID + P_D_ALL_PID;
195 /* Check that requested activities are available */
196 if (DISPLAY_TASK_STATS(tskflag)) {
197 act |= P_A_CPU + P_A_MEM + P_A_IO + P_A_CTXSW
198 + P_A_STACK + P_A_KTAB + P_A_RT;
200 if (DISPLAY_CHILD_STATS(tskflag)) {
201 act |= P_A_CPU + P_A_MEM;
207 fprintf(stderr, _("Requested activities not available\n"));
213 ***************************************************************************
214 * Look for the PID in the list and store it if necessary.
215 * PID -> PID -> TGID -> TID -> TID -> TID -> PID -> NULL
216 * Eg.: 1234 -> 1289 -> 1356 -> 1356 -> 1361 -> 4678 -> 1376 -> NULL
219 * @plist Pointer address on the start of the linked list.
221 * @tgid If PID is a TID then @tgid is its TGID number. 0 otherwise.
224 * Pointer on the st_pid structure in the list where the PID is located
225 * (whether it was already in the list or if it has been added).
226 * NULL if the PID is 0 or it is a TID and its TGID has not been found in
228 ***************************************************************************
230 struct st_pid *add_list_pid(struct st_pid **plist, pid_t pid, pid_t tgid)
232 struct st_pid *p, *ps, *tgid_p = NULL;
234 int tgid_found = FALSE;
241 * Add a true PID to the list.
242 * Add it in ascending order, not taking into account
245 while (*plist != NULL) {
247 if (!p->tgid && (p->pid == pid))
248 /* PID found in list */
251 if (!p->tgid && (p->pid > pid))
252 /* Stop now to insert PID in list */
261 * It will be inserted in ascending order immediately
262 * following its TGID.
264 while (*plist != NULL) {
266 if (p->pid == tgid) {
267 /* TGID found in list */
276 /* TGID not found: Stop now */
280 while (*plist != NULL) {
282 if ((p->tgid == tgid_p) && (p->pid == pid))
283 /* TID found in list */
286 if ((p->tgid == tgid_p) && (p->pid > pid))
287 /* Stop now to insert TID in list */
289 if (p->tgid != tgid_p)
290 /* End of TID list: insert TID here */
300 /* Add PID to the list */
301 if ((*plist = (struct st_pid *) malloc(sizeof(struct st_pid))) == NULL) {
305 memset(*plist, 0, sizeof(struct st_pid));
308 for (i = 0; i < 3; i++) {
309 if ((p->pstats[i] = (struct pid_stats *) malloc(sizeof(struct pid_stats))) == NULL) {
313 memset(p->pstats[i], 0, PID_STATS_SIZE);
325 ***************************************************************************
326 * Get pointer on task's command string.
327 * If this is a thread then return the short command name so that threads
328 * can still be identified.
331 * @plist Pointer address on the start of the linked list.
332 ***************************************************************************
334 char *get_tcmd(struct st_pid *plist)
336 if (DISPLAY_CMDLINE(pidflag) && strlen(plist->cmdline) && !plist->tgid)
337 /* Option "-l" used */
338 return plist->cmdline;
344 ***************************************************************************
345 * Display process command name or command line.
348 * @plist Pointer address on the start of the linked list.
349 ***************************************************************************
351 void print_comm(struct st_pid *plist)
355 /* Get pointer on task's command string */
359 if (IS_PID_DISPLAYED(plist->tgid->flags)) {
360 cprintf_s(IS_ZERO, " |__%s\n", p);
363 /* Its TGID has not been displayed */
364 cprintf_s(IS_STR, " (%s)", plist->tgid->comm);
365 cprintf_s(IS_ZERO, "__%s\n", p);
367 /* We can now consider this has been the case */
368 plist->tgid->flags |= F_PID_DISPLAYED;
372 cprintf_s(IS_STR, " %s\n", p);
377 ***************************************************************************
378 * Read /proc/meminfo.
379 ***************************************************************************
381 void read_proc_meminfo(void)
383 struct stats_memory st_mem;
385 memset(&st_mem, 0, STATS_MEMORY_SIZE);
386 read_meminfo(&st_mem);
387 tlmkb = st_mem.tlmkb;
391 ***************************************************************************
392 * Read stats from /proc/#[/task/##]/stat.
395 * @pid Process whose stats are to be read.
396 * @plist Pointer on the linked list where PID is saved.
397 * @tgid If !=0, thread whose stats are to be read.
398 * @curr Index in array for current sample statistics.
401 * @thread_nr Number of threads of the process.
404 * 0 if stats have been successfully read, and 1 otherwise.
405 ***************************************************************************
407 int read_proc_pid_stat(pid_t pid, struct st_pid *plist,
408 unsigned int *thread_nr, pid_t tgid, int curr)
410 int fd, sz, rc, commsz;
412 static char buffer[1024 + 1];
414 struct pid_stats *pst = plist->pstats[curr];
417 sprintf(filename, TASK_STAT, tgid, pid);
420 sprintf(filename, PID_STAT, pid);
423 if ((fd = open(filename, O_RDONLY)) < 0)
424 /* No such process */
427 sz = read(fd, buffer, 1024);
433 if ((start = strchr(buffer, '(')) == NULL)
436 if ((end = strrchr(start, ')')) == NULL)
438 commsz = end - start;
439 if (commsz >= MAX_COMM_LEN)
441 memcpy(plist->comm, start, commsz);
442 plist->comm[commsz] = '\0';
446 "%*s %*d %*d %*d %*d %*d %*u %llu %llu"
447 " %llu %llu %llu %llu %lld %lld %*d %*d %u %*u %*d %llu %llu"
448 " %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u"
449 " %*u %u %u %u %llu %llu %lld\n",
450 &pst->minflt, &pst->cminflt, &pst->majflt, &pst->cmajflt,
451 &pst->utime, &pst->stime, &pst->cutime, &pst->cstime,
452 thread_nr, &pst->vsz, &pst->rss, &pst->processor,
453 &pst->priority, &pst->policy,
454 &pst->blkio_swapin_delays, &pst->gtime, &pst->cgtime);
460 /* gtime and cgtime fields are unavailable in file */
461 pst->gtime = pst->cgtime = 0;
466 pst->rss = PG_TO_KB(pst->rss);
472 ***************************************************************************
473 * Read stats from /proc/#[/task/##]/schedstat.
476 * @pid Process whose stats are to be read.
477 * @plist Pointer on the linked list where PID is saved.
478 * @tgid If != 0, thread whose stats are to be read.
479 * @curr Index in array for current sample statistics.
482 * 0 if stats have been successfully read, and 1 otherwise.
483 ***************************************************************************
485 int read_proc_pid_sched(pid_t pid, struct st_pid *plist, pid_t tgid, int curr)
489 static char buffer[1024 + 1];
490 unsigned long long wtime = 0;
491 struct pid_stats *pst = plist->pstats[curr];
494 sprintf(filename, TASK_SCHED, tgid, pid);
497 sprintf(filename, PID_SCHED, pid);
500 if ((fd = open(filename, O_RDONLY)) >= 0) {
501 /* schedstat file found for process */
502 sz = read(fd, buffer, 1024);
507 rc = sscanf(buffer, "%*u %llu %*d\n", &wtime);
511 /* Convert ns to jiffies */
512 pst->wtime = wtime * HZ / 1000000000;
521 *****************************************************************************
522 * Read stats from /proc/#[/task/##]/status.
525 * @pid Process whose stats are to be read.
526 * @plist Pointer on the linked list where PID is saved.
527 * @tgid If != 0, thread whose stats are to be read.
528 * @curr Index in array for current sample statistics.
531 * 0 if stats have been successfully read, and 1 otherwise.
532 *****************************************************************************
534 int read_proc_pid_status(pid_t pid, struct st_pid *plist, pid_t tgid, int curr)
537 char filename[128], line[256];
538 struct pid_stats *pst = plist->pstats[curr];
541 sprintf(filename, TASK_STATUS, tgid, pid);
544 sprintf(filename, PID_STATUS, pid);
547 if ((fp = fopen(filename, "r")) == NULL)
548 /* No such process */
551 while (fgets(line, sizeof(line), fp) != NULL) {
553 if (!strncmp(line, "Uid:", 4)) {
554 sscanf(line + 5, "%u", &plist->uid);
556 else if (!strncmp(line, "Threads:", 8)) {
557 sscanf(line + 9, "%u", &pst->threads);
559 else if (!strncmp(line, "voluntary_ctxt_switches:", 24)) {
560 sscanf(line + 25, "%lu", &pst->nvcsw);
562 else if (!strncmp(line, "nonvoluntary_ctxt_switches:", 27)) {
563 sscanf(line + 28, "%lu", &pst->nivcsw);
573 *****************************************************************************
574 * Read information from /proc/#[/task/##}/smaps.
576 * @pid Process whose stats are to be read.
577 * @plist Pointer on the linked list where PID is saved.
578 * @tgid If != 0, thread whose stats are to be read.
579 * @curr Index in array for current sample statistics.
582 * 0 if stats have been successfully read, and 1 otherwise.
583 *****************************************************************************
585 int read_proc_pid_smap(pid_t pid, struct st_pid *plist, pid_t tgid, int curr)
588 char filename[128], line[256];
590 struct pid_stats *pst = plist->pstats[curr];
593 sprintf(filename, TASK_SMAP, tgid, pid);
596 sprintf(filename, PID_SMAP, pid);
599 if ((fp = fopen(filename, "rt")) == NULL)
600 /* No such process */
603 while ((state < 3) && (fgets(line, sizeof(line), fp) != NULL)) {
606 if (strstr(line, "[stack]")) {
611 if (strstr(line, "Size:")) {
612 sscanf(line + sizeof("Size:"), "%lu", &pst->stack_size);
617 if (strstr(line, "Referenced:")) {
618 sscanf(line + sizeof("Referenced:"), "%lu", &pst->stack_ref);
631 *****************************************************************************
632 * Read process command line from /proc/#[/task/##]/cmdline.
635 * @pid Process whose command line is to be read.
636 * @plist Pointer on the linked list where PID is saved.
637 * @tgid If != 0, thread whose stats are to be read.
640 * @pst Pointer on structure where command line has been saved.
643 * 0 if command line has been successfully read (even if the /proc/.../cmdline
644 * is just empty), and 1 otherwise (the process has terminated).
645 *****************************************************************************
647 int read_proc_pid_cmdline(pid_t pid, struct st_pid *plist, pid_t tgid)
650 char filename[128], line[MAX_CMDLINE_LEN];
652 int i, found = FALSE;
655 sprintf(filename, TASK_CMDLINE, tgid, pid);
658 sprintf(filename, PID_CMDLINE, pid);
661 if ((fp = fopen(filename, "r")) == NULL)
662 /* No such process */
665 memset(line, 0, MAX_CMDLINE_LEN);
667 len = fread(line, 1, sizeof(line) - 1, fp);
671 for (i = len - 2; i >= 0; i--) {
679 strncpy(plist->cmdline, line, sizeof(plist->cmdline) - 1);
680 plist->cmdline[sizeof(plist->cmdline) - 1] = '\0';
683 /* proc/.../cmdline was empty */
684 plist->cmdline[0] = '\0';
690 ***************************************************************************
691 * Read stats from /proc/#[/task/##]/io.
694 * @pid Process whose stats are to be read.
695 * @plist Pointer on the linked list where PID is saved.
696 * @tgid If != 0, thread whose stats are to be read.
697 * @curr Index in array for current sample statistics.
700 * 0 if stats have been successfully read.
701 * Also returns 0 if current process has terminated or if its io file
702 * doesn't exist, but in this case, set process' F_NO_PID_IO flag to
703 * indicate that I/O stats should no longer be read for it.
704 ***************************************************************************
706 int read_proc_pid_io(pid_t pid, struct st_pid *plist, pid_t tgid, int curr)
709 char filename[128], line[256];
710 struct pid_stats *pst = plist->pstats[curr];
713 sprintf(filename, TASK_IO, tgid, pid);
716 sprintf(filename, PID_IO, pid);
719 if ((fp = fopen(filename, "r")) == NULL) {
720 /* No such process... or file non existent! */
721 plist->flags |= F_NO_PID_IO;
723 * Also returns 0 since io stats file doesn't necessarily exist,
724 * depending on the kernel version used.
729 while (fgets(line, sizeof(line), fp) != NULL) {
731 if (!strncmp(line, "read_bytes:", 11)) {
732 sscanf(line + 12, "%llu", &pst->read_bytes);
734 else if (!strncmp(line, "write_bytes:", 12)) {
735 sscanf(line + 13, "%llu", &pst->write_bytes);
737 else if (!strncmp(line, "cancelled_write_bytes:", 22)) {
738 sscanf(line + 23, "%llu", &pst->cancelled_write_bytes);
744 plist->flags &= ~F_NO_PID_IO;
750 ***************************************************************************
751 * Count number of file descriptors in /proc/#[/task/##]/fd directory.
754 * @pid Process whose stats are to be read.
755 * @plist Pointer on the linked list where PID is saved.
756 * @tgid If != 0, thread whose stats are to be read.
757 * @curr Index in array for current sample statistics.
760 * 0 if stats have been successfully read.
761 * Also returns 0 if current process has terminated or if we cannot read its
762 * fd directory, but in this case, set process' F_NO_PID_FD flag to
763 * indicate that fd directory couldn't be read.
764 ***************************************************************************
766 int read_proc_pid_fd(pid_t pid, struct st_pid *plist, pid_t tgid, int curr)
771 struct pid_stats *pst = plist->pstats[curr];
774 sprintf(filename, TASK_FD, tgid, pid);
777 sprintf(filename, PID_FD, pid);
780 if ((dir = opendir(filename)) == NULL) {
781 /* Cannot read fd directory */
782 plist->flags |= F_NO_PID_FD;
788 /* Count number of entries if fd directory */
789 while ((drp = readdir(dir)) != NULL) {
790 if (isdigit(drp->d_name[0])) {
797 plist->flags &= ~F_NO_PID_FD;
803 ***************************************************************************
804 * Read various stats for given PID.
807 * @pid Process whose stats are to be read.
808 * @plist Pointer on the linked list where PID is saved.
809 * @tgid If !=0, thread whose stats are to be read.
810 * @curr Index in array for current sample statistics.
813 * @thread_nr Number of threads of the process.
816 * 0 if stats have been successfully read, and 1 otherwise.
817 ***************************************************************************
819 int read_pid_stats(pid_t pid, struct st_pid *plist, unsigned int *thread_nr,
820 pid_t tgid, int curr)
822 if (read_proc_pid_stat(pid, plist, thread_nr, tgid, curr))
826 * No need to test the return code here: Not finding
827 * the schedstat files shouldn't make pidstat stop.
829 read_proc_pid_sched(pid, plist, tgid, curr);
831 if (DISPLAY_CMDLINE(pidflag) && !plist->cmdline[0]) {
832 if (read_proc_pid_cmdline(pid, plist, tgid))
836 if (read_proc_pid_status(pid, plist, tgid, curr))
839 if (DISPLAY_STACK(actflag)) {
840 if (read_proc_pid_smap(pid, plist, tgid, curr))
844 if (DISPLAY_KTAB(actflag)) {
845 if (read_proc_pid_fd(pid, plist, tgid, curr))
849 if (DISPLAY_IO(actflag))
850 /* Assume that /proc/#/task/#/io exists! */
851 return (read_proc_pid_io(pid, plist, tgid, curr));
857 ***************************************************************************
858 * Read stats for threads in /proc/#/task directory.
861 * @pid Process number whose threads stats are to be read.
862 * @plist Pointer on the linked list where PID is saved.
863 * @curr Index in array for current sample statistics.
864 ***************************************************************************
866 void read_task_stats(pid_t pid, struct st_pid *plist, int curr)
873 struct st_pid *tlist;
875 /* Open /proc/#/task directory */
876 sprintf(filename, PROC_TASK, pid);
877 if ((dir = __opendir(filename)) == NULL)
880 while ((drp = __readdir(dir)) != NULL) {
881 if (!isdigit(drp->d_name[0])) {
885 tid = atoi(drp->d_name);
887 tlist = add_list_pid(&pid_list, tid, pid);
892 if (read_pid_stats(tid, tlist, &thr_nr, pid, curr)) {
893 /* Thread doesn't exist */
894 tlist->exist = FALSE;
902 ***************************************************************************
903 * Read various stats.
906 * @curr Index in array for current sample statistics.
907 ***************************************************************************
909 void read_stats(int curr)
915 struct st_pid *plist;
916 struct stats_cpu *st_cpu;
919 * Allocate two structures for CPU statistics.
920 * No need to init them (done by read_stat_cpu() function).
922 if ((st_cpu = (struct stats_cpu *) malloc(STATS_CPU_SIZE * 2)) == NULL) {
926 /* Read statistics for CPUs "all" */
927 read_stat_cpu(st_cpu, 1);
930 * Compute the total number of jiffies spent by all processors.
931 * NB: Don't add cpu_guest/cpu_guest_nice because cpu_user/cpu_nice
932 * already include them.
934 tot_jiffies[curr] = st_cpu->cpu_user + st_cpu->cpu_nice +
935 st_cpu->cpu_sys + st_cpu->cpu_idle +
936 st_cpu->cpu_iowait + st_cpu->cpu_hardirq +
937 st_cpu->cpu_steal + st_cpu->cpu_softirq;
940 if (DISPLAY_ALL_PID(pidflag)) {
942 /* Open /proc directory */
943 if ((dir = __opendir(PROC)) == NULL) {
948 /* Get directory entries */
949 while ((drp = __readdir(dir)) != NULL) {
950 if (!isdigit(drp->d_name[0])) {
954 pid = atoi(drp->d_name);
956 plist = add_list_pid(&pid_list, pid, 0);
961 if (read_pid_stats(pid, plist, &thr_nr, 0, curr)) {
962 /* PID has terminated */
963 plist->exist = FALSE;
965 } else if (DISPLAY_TID(pidflag)) {
966 /* Read stats for threads in task subdirectory */
967 read_task_stats(pid, plist, curr);
971 /* Close /proc directory */
975 else if (DISPLAY_PID(pidflag)) {
976 /* Read stats for each PID in the list */
977 for (plist = pid_list; plist != NULL; plist = plist->next) {
982 * The user can only enter PIDs on the command line.
983 * If there is a TID then this is because the user has
984 * used option -t, and the TID has been inserted in the
985 * list by read_task_stats() function below.
989 if (read_pid_stats(plist->pid, plist, &thr_nr, 0, curr)) {
990 /* PID has terminated */
991 plist->exist = FALSE;
996 if (DISPLAY_TID(pidflag)) {
997 read_task_stats(plist->pid, plist, curr);
1003 /* Free unused PID structures */
1004 sfree_pid(&pid_list, FALSE);
1008 ***************************************************************************
1009 * Get current PID to display.
1010 * First, check that PID exists. *Then* check that it's an active process
1011 * and/or that the string (entered on the command line with option -C)
1012 * is found in command name, or that the process string (entered on the
1013 * command line with option -G) is found either in its command name (in case
1014 * PID is a process) or in command name of its thread leader (in case
1018 * @prev Index in array where stats used as reference are.
1019 * @curr Index in array for current sample statistics.
1020 * @activity Current activity to display (CPU, memory...).
1021 * Can be more than one if stats are displayed on one line.
1022 * @pflag Flag indicating whether stats are to be displayed for
1023 * individual tasks or for all their children.
1024 * @plist Pointer on the linked list where PID is saved.
1027 * 0 if PID no longer exists.
1028 * -1 if PID exists but should not be displayed.
1029 * 1 if PID can be displayed.
1030 ***************************************************************************
1032 int get_pid_to_display(int prev, int curr, unsigned int activity, unsigned int pflag,
1033 struct st_pid *plist)
1038 struct passwd *pwdent;
1039 struct pid_stats *pstc = plist->pstats[curr], *pstp = plist->pstats[prev];
1042 /* PID no longer exists */
1046 /* This is group leader: Set it as not displayed by default */
1047 plist->flags &= ~F_PID_DISPLAYED;
1050 if ((DISPLAY_ALL_PID(pidflag) || DISPLAY_TID(pidflag)) &&
1051 DISPLAY_ACTIVE_PID(pidflag)) {
1052 int isActive = FALSE;
1054 /* Check that it's an "active" process */
1055 if (DISPLAY_CPU(activity)) {
1056 /* User time already includes guest time */
1057 if ((pstc->utime != pstp->utime) ||
1058 (pstc->stime != pstp->stime)) {
1063 * Process is not active but if we are showing
1064 * child stats then we need to look there.
1066 if (DISPLAY_CHILD_STATS(pflag)) {
1067 /* User time already includes guest time */
1068 if ((pstc->cutime != pstp->cutime) ||
1069 (pstc->cstime != pstp->cstime)) {
1076 if (DISPLAY_MEM(activity) && !isActive) {
1077 if ((pstc->minflt != pstp->minflt) ||
1078 (pstc->majflt != pstp->majflt)) {
1082 if (DISPLAY_TASK_STATS(pflag)) {
1083 if ((pstc->vsz != pstp->vsz) ||
1084 (pstc->rss != pstp->rss)) {
1088 else if (DISPLAY_CHILD_STATS(pflag)) {
1089 if ((pstc->cminflt != pstp->cminflt) ||
1090 (pstc->cmajflt != pstp->cmajflt)) {
1097 if (DISPLAY_STACK(activity) && !isActive) {
1098 if ((pstc->stack_size != pstp->stack_size) ||
1099 (pstc->stack_ref != pstp->stack_ref)) {
1104 if (DISPLAY_IO(activity) && !isActive) {
1105 if (pstc->blkio_swapin_delays !=
1106 pstp->blkio_swapin_delays) {
1109 if (!(NO_PID_IO(plist->flags)) && !isActive) {
1110 /* /proc/#/io file should exist to check I/O stats */
1111 if ((pstc->read_bytes != pstp->read_bytes) ||
1112 (pstc->write_bytes != pstp->write_bytes) ||
1113 (pstc->cancelled_write_bytes !=
1114 pstp->cancelled_write_bytes)) {
1120 if (DISPLAY_CTXSW(activity) && !isActive) {
1121 if ((pstc->nvcsw != pstp->nvcsw) ||
1122 (pstc->nivcsw != pstp->nivcsw)) {
1127 if (DISPLAY_RT(activity) && !isActive) {
1128 if ((pstc->priority != pstp->priority) ||
1129 (pstc->policy != pstp->policy)) {
1134 if (DISPLAY_KTAB(activity) && !isActive &&
1135 !(NO_PID_FD(plist->flags))) { /* /proc/#/fd directory should be readable */
1136 if ((pstc->threads != pstp->threads) ||
1137 (pstc->fd_nr != pstp->fd_nr)) {
1142 /* If PID isn't active for any of the activities then return */
1147 if (COMMAND_STRING(pidflag)) {
1148 if (regcomp(®ex, commstr, REG_EXTENDED | REG_NOSUB) != 0)
1149 /* Error in preparing regex structure */
1152 pc = get_tcmd(plist); /* Get pointer on task's command string */
1153 rc = regexec(®ex, pc, 0, NULL, 0);
1157 /* regex pattern not found in command name */
1161 if (PROCESS_STRING(pidflag)) {
1163 /* This PID is a process ("thread group leader") */
1164 if (regcomp(®ex, procstr, REG_EXTENDED | REG_NOSUB) != 0)
1165 /* Error in preparing regex structure */
1168 pc = get_tcmd(plist); /* Get pointer on task's command string */
1169 rc = regexec(®ex, pc, 0, NULL, 0);
1173 /* regex pattern not found in command name */
1177 else if (!IS_PID_DISPLAYED(plist->tgid->flags))
1178 /* This pid is a thread and is not part of a process to display */
1182 if (USER_STRING(pidflag)) {
1183 if ((pwdent = __getpwuid(plist->uid)) != NULL) {
1184 if (strcmp(pwdent->pw_name, userstr))
1185 /* This PID doesn't belong to user */
1190 plist->flags |= F_PID_DISPLAYED;
1195 ***************************************************************************
1196 * Display UID/username, PID and TID.
1199 * @plist Pointer on the linked list where PID is saved.
1200 * @c No-op character.
1201 ***************************************************************************
1203 void __print_line_id(struct st_pid *plist, char c)
1206 struct passwd *pwdent;
1208 if (DISPLAY_USERNAME(pidflag) && ((pwdent = __getpwuid(plist->uid)) != NULL)) {
1209 cprintf_in(IS_STR, " %8s", pwdent->pw_name, 0);
1212 cprintf_in(IS_INT, " %5d", "", plist->uid);
1215 if (DISPLAY_TID(pidflag)) {
1219 if (IS_PID_DISPLAYED(plist->tgid->flags)) {
1220 sprintf(format, " %c %%9u", c);
1223 strcpy(format, " %9u");
1224 cprintf_in(IS_INT, format, "", plist->tgid->pid);
1228 /* This is a PID (TGID) */
1229 sprintf(format, " %%9u %c", c);
1233 strcpy(format, " %9u");
1236 cprintf_in(IS_INT, format, "", plist->pid);
1240 ***************************************************************************
1241 * Display timestamp, PID and TID.
1244 * @timestamp Current timestamp.
1245 * @plist Pointer on the linked list where PID is saved.
1246 ***************************************************************************
1248 void print_line_id(char *timestamp, struct st_pid *plist)
1250 printf("%-11s", timestamp);
1251 __print_line_id(plist, '-');
1255 ***************************************************************************
1256 * Display all statistics for tasks in one line format.
1259 * @prev Index in array where stats used as reference are.
1260 * @curr Index in array for current sample statistics.
1261 * @dis TRUE if a header line must be printed.
1262 * @prev_string String displayed at the beginning of a header line. This is
1263 * the timestamp of the previous sample.
1264 * @curr_string String displayed at the beginning of current sample stats.
1265 * This is the timestamp of the current sample.
1266 * @itv Interval of time in jiffies.
1268 * Number of jiffies spent on the interval by all processors.
1271 * 0 if all the processes to display have terminated.
1272 * <> 0 if there are still some processes left to display.
1273 ***************************************************************************
1275 int write_pid_task_all_stats(int prev, int curr, int dis,
1276 char *prev_string, char *curr_string,
1277 unsigned long long itv,
1278 unsigned long long deltot_jiffies)
1280 struct pid_stats *pstc, *pstp;
1281 struct st_pid *plist;
1286 PRINT_ID_HDR(prev_string, pidflag);
1287 if (DISPLAY_CPU(actflag)) {
1288 printf(" %%usr %%system %%guest %%wait %%CPU CPU");
1290 if (DISPLAY_MEM(actflag)) {
1291 printf(" minflt/s majflt/s VSZ RSS %%MEM");
1293 if (DISPLAY_STACK(actflag)) {
1294 printf(" StkSize StkRef");
1296 if (DISPLAY_IO(actflag)) {
1297 printf(" kB_rd/s kB_wr/s kB_ccwr/s iodelay");
1299 if (DISPLAY_CTXSW(actflag)) {
1300 printf(" cswch/s nvcswch/s");
1302 if (DISPLAY_KTAB(actflag)) {
1303 printf(" threads fd-nr");
1305 if (DISPLAY_RT(actflag)) {
1306 printf(" prio policy");
1308 printf(" Command\n");
1311 for (plist = pid_list; plist != NULL; plist = plist->next) {
1313 if (get_pid_to_display(prev, curr, actflag, P_TASK, plist) <= 0)
1316 print_line_id(curr_string, plist);
1318 pstc = plist->pstats[curr];
1319 pstp = plist->pstats[prev];
1321 if (DISPLAY_CPU(actflag)) {
1322 cprintf_pc(DISPLAY_UNIT(pidflag), 5, 7, 2,
1323 (pstc->utime - pstc->gtime) < (pstp->utime - pstp->gtime) ?
1325 SP_VALUE(pstp->utime - pstp->gtime,
1326 pstc->utime - pstc->gtime, itv * HZ / 100),
1327 SP_VALUE(pstp->stime, pstc->stime, itv * HZ / 100),
1328 SP_VALUE(pstp->gtime, pstc->gtime, itv * HZ / 100),
1329 SP_VALUE(pstp->wtime, pstc->wtime, itv * HZ / 100),
1330 /* User time already includes guest time */
1331 IRIX_MODE_OFF(pidflag) ?
1332 SP_VALUE(pstp->utime + pstp->stime,
1333 pstc->utime + pstc->stime, deltot_jiffies) :
1334 SP_VALUE(pstp->utime + pstp->stime,
1335 pstc->utime + pstc->stime, itv * HZ / 100));
1337 cprintf_in(IS_INT, " %3d", "", pstc->processor);
1340 if (DISPLAY_MEM(actflag)) {
1341 cprintf_f(NO_UNIT, 2, 9, 2,
1342 S_VALUE(pstp->minflt, pstc->minflt, itv),
1343 S_VALUE(pstp->majflt, pstc->majflt, itv));
1344 cprintf_u64(DISPLAY_UNIT(pidflag) ? UNIT_KILOBYTE : NO_UNIT, 2, 7,
1345 (unsigned long long) pstc->vsz,
1346 (unsigned long long) pstc->rss);
1347 cprintf_pc(DISPLAY_UNIT(pidflag), 1, 6, 2,
1348 tlmkb ? SP_VALUE(0, pstc->rss, tlmkb) : 0.0);
1351 if (DISPLAY_STACK(actflag)) {
1352 cprintf_u64(DISPLAY_UNIT(pidflag) ? UNIT_KILOBYTE : NO_UNIT, 2, 7,
1353 (unsigned long long) pstc->stack_size,
1354 (unsigned long long) pstc->stack_ref);
1357 if (DISPLAY_IO(actflag)) {
1358 if (!NO_PID_IO(plist->flags))
1360 double rbytes, wbytes, cbytes;
1362 rbytes = S_VALUE(pstp->read_bytes, pstc->read_bytes, itv);
1363 wbytes = S_VALUE(pstp->write_bytes, pstc->write_bytes, itv);
1364 cbytes = S_VALUE(pstp->cancelled_write_bytes,
1365 pstc->cancelled_write_bytes, itv);
1366 if (!DISPLAY_UNIT(pidflag)) {
1371 cprintf_f(DISPLAY_UNIT(pidflag) ? UNIT_BYTE : NO_UNIT, 3, 9, 2,
1372 rbytes, wbytes, cbytes);
1376 * Keep the layout even though this task has no I/O
1377 * typically threads with no I/O measurements.
1379 sprintf(dstr, " %9.2f %9.2f %9.2f", -1.0, -1.0, -1.0);
1380 cprintf_s(IS_ZERO, "%s", dstr);
1382 /* I/O delays come from another file (/proc/#/stat) */
1383 cprintf_u64(NO_UNIT, 1, 7,
1384 (unsigned long long) (pstc->blkio_swapin_delays - pstp->blkio_swapin_delays));
1387 if (DISPLAY_CTXSW(actflag)) {
1388 cprintf_f(NO_UNIT, 2, 9, 2,
1389 S_VALUE(pstp->nvcsw, pstc->nvcsw, itv),
1390 S_VALUE(pstp->nivcsw, pstc->nivcsw, itv));
1393 if (DISPLAY_KTAB(actflag)) {
1394 cprintf_u64(NO_UNIT, 1, 7,
1395 (unsigned long long) pstc->threads);
1396 if (NO_PID_FD(plist->flags)) {
1397 /* /proc/#/fd directory not readable */
1398 cprintf_s(IS_ZERO, " %7s", "-1");
1401 cprintf_u64(NO_UNIT, 1, 7, (unsigned long long) pstc->fd_nr);
1405 if (DISPLAY_RT(actflag)) {
1406 cprintf_u64(NO_UNIT, 1, 4,
1407 (unsigned long long) pstc->priority);
1408 cprintf_s(IS_STR, " %6s",
1409 GET_POLICY(pstc->policy));
1420 ***************************************************************************
1421 * Display all statistics for tasks' children in one line format.
1424 * @prev Index in array where stats used as reference are.
1425 * @curr Index in array for current sample statistics.
1426 * @dis TRUE if a header line must be printed.
1427 * @prev_string String displayed at the beginning of a header line. This is
1428 * the timestamp of the previous sample.
1429 * @curr_string String displayed at the beginning of current sample stats.
1430 * This is the timestamp of the current sample.
1433 * 0 if all the processes to display have terminated.
1434 * <> 0 if there are still some processes left to display.
1435 ***************************************************************************
1437 int write_pid_child_all_stats(int prev, int curr, int dis,
1438 char *prev_string, char *curr_string)
1440 struct pid_stats *pstc, *pstp;
1441 struct st_pid *plist;
1445 PRINT_ID_HDR(prev_string, pidflag);
1446 if (DISPLAY_CPU(actflag))
1447 printf(" usr-ms system-ms guest-ms");
1448 if (DISPLAY_MEM(actflag))
1449 printf(" minflt-nr majflt-nr");
1450 printf(" Command\n");
1453 for (plist = pid_list; plist != NULL; plist = plist->next) {
1455 if (get_pid_to_display(prev, curr, actflag, P_CHILD, plist) <= 0)
1458 print_line_id(curr_string, plist);
1460 pstc = plist->pstats[curr];
1461 pstp = plist->pstats[prev];
1463 if (DISPLAY_CPU(actflag)) {
1464 cprintf_f(NO_UNIT, 3, 9, 0,
1465 (pstc->utime + pstc->cutime - pstc->gtime - pstc->cgtime) <
1466 (pstp->utime + pstp->cutime - pstp->gtime - pstp->cgtime) ?
1468 (double) ((pstc->utime + pstc->cutime - pstc->gtime - pstc->cgtime) -
1469 (pstp->utime + pstp->cutime - pstp->gtime - pstp->cgtime)) /
1471 (double) ((pstc->stime + pstc->cstime) -
1472 (pstp->stime + pstp->cstime)) / HZ * 1000,
1473 (double) ((pstc->gtime + pstc->cgtime) -
1474 (pstp->gtime + pstp->cgtime)) / HZ * 1000);
1477 if (DISPLAY_MEM(actflag)) {
1478 cprintf_u64(NO_UNIT, 2, 9,
1479 (unsigned long long) ((pstc->minflt + pstc->cminflt) - (pstp->minflt + pstp->cminflt)),
1480 (unsigned long long) ((pstc->majflt + pstc->cmajflt) - (pstp->majflt + pstp->cmajflt)));
1491 ***************************************************************************
1492 * Display CPU statistics for tasks.
1495 * @prev Index in array where stats used as reference are.
1496 * @curr Index in array for current sample statistics.
1497 * @dis TRUE if a header line must be printed.
1498 * @disp_avg TRUE if average stats are displayed.
1499 * @prev_string String displayed at the beginning of a header line. This is
1500 * the timestamp of the previous sample, or "Average" when
1501 * displaying average stats.
1502 * @curr_string String displayed at the beginning of current sample stats.
1503 * This is the timestamp of the current sample, or "Average"
1504 * when displaying average stats.
1505 * @itv Interval of time in 1/100th of a second.
1507 * Number of jiffies spent on the interval by all processors.
1510 * 0 if all the processes to display have terminated.
1511 * <> 0 if there are still some processes left to display.
1512 ***************************************************************************
1514 int write_pid_task_cpu_stats(int prev, int curr, int dis, int disp_avg,
1515 char *prev_string, char *curr_string,
1516 unsigned long long itv,
1517 unsigned long long deltot_jiffies)
1519 struct pid_stats *pstc, *pstp;
1520 struct st_pid *plist;
1524 PRINT_ID_HDR(prev_string, pidflag);
1525 printf(" %%usr %%system %%guest %%wait %%CPU CPU Command\n");
1528 for (plist = pid_list; plist != NULL; plist = plist->next) {
1530 if (get_pid_to_display(prev, curr, P_A_CPU, P_TASK, plist) <= 0)
1533 print_line_id(curr_string, plist);
1535 pstc = plist->pstats[curr];
1536 pstp = plist->pstats[prev];
1538 cprintf_pc(DISPLAY_UNIT(pidflag), 5, 7, 2,
1539 (pstc->utime - pstc->gtime) < (pstp->utime - pstp->gtime) ?
1541 SP_VALUE(pstp->utime - pstp->gtime,
1542 pstc->utime - pstc->gtime, itv * HZ / 100),
1543 SP_VALUE(pstp->stime, pstc->stime, itv * HZ / 100),
1544 SP_VALUE(pstp->gtime, pstc->gtime, itv * HZ / 100),
1545 SP_VALUE(pstp->wtime, pstc->wtime, itv * HZ / 100),
1546 /* User time already includes guest time */
1547 IRIX_MODE_OFF(pidflag) ?
1548 SP_VALUE(pstp->utime + pstp->stime,
1549 pstc->utime + pstc->stime, deltot_jiffies) :
1550 SP_VALUE(pstp->utime + pstp->stime,
1551 pstc->utime + pstc->stime, itv * HZ / 100));
1554 cprintf_in(IS_INT, " %3d", "", pstc->processor);
1557 cprintf_in(IS_STR, "%s", " -", 0);
1567 ***************************************************************************
1568 * Display CPU statistics for tasks' children.
1571 * @prev Index in array where stats used as reference are.
1572 * @curr Index in array for current sample statistics.
1573 * @dis TRUE if a header line must be printed.
1574 * @disp_avg TRUE if average stats are displayed.
1575 * @prev_string String displayed at the beginning of a header line. This is
1576 * the timestamp of the previous sample, or "Average" when
1577 * displaying average stats.
1578 * @curr_string String displayed at the beginning of current sample stats.
1579 * This is the timestamp of the current sample, or "Average"
1580 * when displaying average stats.
1583 * 0 if all the processes to display have terminated.
1584 * <> 0 if there are still some processes left to display.
1585 ***************************************************************************
1587 int write_pid_child_cpu_stats(int prev, int curr, int dis, int disp_avg,
1588 char *prev_string, char *curr_string)
1590 struct pid_stats *pstc, *pstp;
1591 struct st_pid *plist;
1595 PRINT_ID_HDR(prev_string, pidflag);
1596 printf(" usr-ms system-ms guest-ms Command\n");
1599 for (plist = pid_list; plist != NULL; plist = plist->next) {
1601 if ((rc = get_pid_to_display(prev, curr, P_A_CPU, P_CHILD, plist)) == 0)
1602 /* PID no longer exists */
1605 /* This will be used to compute average */
1607 plist->uc_asum_count += 1;
1611 /* PID should not be displayed */
1614 print_line_id(curr_string, plist);
1616 pstc = plist->pstats[curr];
1617 pstp = plist->pstats[prev];
1620 cprintf_f(NO_UNIT, 3, 9, 0,
1621 (pstc->utime + pstc->cutime - pstc->gtime - pstc->cgtime) <
1622 (pstp->utime + pstp->cutime - pstp->gtime - pstp->cgtime) ?
1624 (double) ((pstc->utime + pstc->cutime - pstc->gtime - pstc->cgtime) -
1625 (pstp->utime + pstp->cutime - pstp->gtime - pstp->cgtime)) /
1626 (HZ * plist->uc_asum_count) * 1000,
1627 (double) ((pstc->stime + pstc->cstime) -
1628 (pstp->stime + pstp->cstime)) /
1629 (HZ * plist->uc_asum_count) * 1000,
1630 (double) ((pstc->gtime + pstc->cgtime) -
1631 (pstp->gtime + pstp->cgtime)) /
1632 (HZ * plist->uc_asum_count) * 1000);
1635 cprintf_f(NO_UNIT, 3, 9, 0,
1636 (pstc->utime + pstc->cutime - pstc->gtime - pstc->cgtime) <
1637 (pstp->utime + pstp->cutime - pstp->gtime - pstp->cgtime) ?
1639 (double) ((pstc->utime + pstc->cutime - pstc->gtime - pstc->cgtime) -
1640 (pstp->utime + pstp->cutime - pstp->gtime - pstp->cgtime)) /
1642 (double) ((pstc->stime + pstc->cstime) -
1643 (pstp->stime + pstp->cstime)) / HZ * 1000,
1644 (double) ((pstc->gtime + pstc->cgtime) -
1645 (pstp->gtime + pstp->cgtime)) / HZ * 1000);
1655 ***************************************************************************
1656 * Display memory statistics for tasks.
1659 * @prev Index in array where stats used as reference are.
1660 * @curr Index in array for current sample statistics.
1661 * @dis TRUE if a header line must be printed.
1662 * @disp_avg TRUE if average stats are displayed.
1663 * @prev_string String displayed at the beginning of a header line. This is
1664 * the timestamp of the previous sample, or "Average" when
1665 * displaying average stats.
1666 * @curr_string String displayed at the beginning of current sample stats.
1667 * This is the timestamp of the current sample, or "Average"
1668 * when displaying average stats.
1669 * @itv Interval of time in 1/100th of a second.
1672 * 0 if all the processes to display have terminated.
1673 * <> 0 if there are still some processes left to display.
1674 ***************************************************************************
1676 int write_pid_task_memory_stats(int prev, int curr, int dis, int disp_avg,
1677 char *prev_string, char *curr_string,
1678 unsigned long long itv)
1680 struct pid_stats *pstc, *pstp;
1681 struct st_pid *plist;
1685 PRINT_ID_HDR(prev_string, pidflag);
1686 printf(" minflt/s majflt/s VSZ RSS %%MEM Command\n");
1689 for (plist = pid_list; plist != NULL; plist = plist->next) {
1691 if ((rc = get_pid_to_display(prev, curr, P_A_MEM, P_TASK, plist)) == 0)
1692 /* PID no longer exists */
1695 pstc = plist->pstats[curr];
1696 pstp = plist->pstats[prev];
1698 /* This will be used to compute average */
1700 plist->total_vsz += pstc->vsz;
1701 plist->total_rss += pstc->rss;
1702 plist->rt_asum_count += 1;
1706 /* PID should not be displayed */
1709 print_line_id(curr_string, plist);
1711 cprintf_f(NO_UNIT, 2, 9, 2,
1712 S_VALUE(pstp->minflt, pstc->minflt, itv),
1713 S_VALUE(pstp->majflt, pstc->majflt, itv));
1716 cprintf_f(DISPLAY_UNIT(pidflag) ? UNIT_KILOBYTE : NO_UNIT, 2, 7, 0,
1717 (double) plist->total_vsz / plist->rt_asum_count,
1718 (double) plist->total_rss / plist->rt_asum_count);
1720 cprintf_pc(DISPLAY_UNIT(pidflag), 1, 6, 2,
1722 SP_VALUE(0, plist->total_rss / plist->rt_asum_count, tlmkb)
1726 cprintf_u64(DISPLAY_UNIT(pidflag) ? UNIT_KILOBYTE : NO_UNIT, 2, 7,
1727 (unsigned long long) pstc->vsz,
1728 (unsigned long long) pstc->rss);
1730 cprintf_pc(DISPLAY_UNIT(pidflag), 1, 6, 2,
1731 tlmkb ? SP_VALUE(0, pstc->rss, tlmkb) : 0.0);
1742 ***************************************************************************
1743 * Display memory statistics for tasks' children.
1746 * @prev Index in array where stats used as reference are.
1747 * @curr Index in array for current sample statistics.
1748 * @dis TRUE if a header line must be printed.
1749 * @disp_avg TRUE if average stats are displayed.
1750 * @prev_string String displayed at the beginning of a header line. This is
1751 * the timestamp of the previous sample, or "Average" when
1752 * displaying average stats.
1753 * @curr_string String displayed at the beginning of current sample stats.
1754 * This is the timestamp of the current sample, or "Average"
1755 * when displaying average stats.
1758 * 0 if all the processes to display have terminated.
1759 * <> 0 if there are still some processes left to display.
1760 ***************************************************************************
1762 int write_pid_child_memory_stats(int prev, int curr, int dis, int disp_avg,
1763 char *prev_string, char *curr_string)
1765 struct pid_stats *pstc, *pstp;
1766 struct st_pid *plist;
1770 PRINT_ID_HDR(prev_string, pidflag);
1771 printf(" minflt-nr majflt-nr Command\n");
1774 for (plist = pid_list; plist != NULL; plist = plist->next) {
1776 if ((rc = get_pid_to_display(prev, curr, P_A_MEM, P_CHILD, plist)) == 0)
1777 /* PID no longer exists */
1780 /* This will be used to compute average */
1782 plist->rc_asum_count += 1;
1786 /* PID should not be displayed */
1789 print_line_id(curr_string, plist);
1791 pstc = plist->pstats[curr];
1792 pstp = plist->pstats[prev];
1795 cprintf_f(NO_UNIT, 2, 9, 0,
1796 (double) ((pstc->minflt + pstc->cminflt) -
1797 (pstp->minflt + pstp->cminflt)) / plist->rc_asum_count,
1798 (double) ((pstc->majflt + pstc->cmajflt) -
1799 (pstp->majflt + pstp->cmajflt)) / plist->rc_asum_count);
1802 cprintf_u64(NO_UNIT, 2, 9,
1803 (unsigned long long) ((pstc->minflt + pstc->cminflt) - (pstp->minflt + pstp->cminflt)),
1804 (unsigned long long) ((pstc->majflt + pstc->cmajflt) - (pstp->majflt + pstp->cmajflt)));
1814 ***************************************************************************
1815 * Display stack size statistics for tasks.
1818 * @prev Index in array where stats used as reference are.
1819 * @curr Index in array for current sample statistics.
1820 * @dis TRUE if a header line must be printed.
1821 * @disp_avg TRUE if average stats are displayed.
1822 * @prev_string String displayed at the beginning of a header line. This is
1823 * the timestamp of the previous sample, or "Average" when
1824 * displaying average stats.
1825 * @curr_string String displayed at the beginning of current sample stats.
1826 * This is the timestamp of the current sample, or "Average"
1827 * when displaying average stats.
1830 * 0 if all the processes to display have terminated.
1831 * <> 0 if there are still some processes left to display.
1832 ***************************************************************************
1834 int write_pid_stack_stats(int prev, int curr, int dis, int disp_avg,
1835 char *prev_string, char *curr_string)
1837 struct pid_stats *pstc;
1838 struct st_pid *plist;
1842 PRINT_ID_HDR(prev_string, pidflag);
1843 printf(" StkSize StkRef Command\n");
1846 for (plist = pid_list; plist != NULL; plist = plist->next) {
1848 if ((rc = get_pid_to_display(prev, curr, P_A_STACK, P_NULL, plist)) == 0)
1849 /* PID no longer exists */
1852 pstc = plist->pstats[curr];
1854 /* This will be used to compute average */
1856 plist->total_stack_size += pstc->stack_size;
1857 plist->total_stack_ref += pstc->stack_ref;
1858 plist->sk_asum_count += 1;
1862 /* PID should not be displayed */
1865 print_line_id(curr_string, plist);
1868 cprintf_f(DISPLAY_UNIT(pidflag) ? UNIT_KILOBYTE : NO_UNIT, 2, 7, 0,
1869 (double) plist->total_stack_size / plist->sk_asum_count,
1870 (double) plist->total_stack_ref / plist->sk_asum_count);
1873 cprintf_u64(DISPLAY_UNIT(pidflag) ? UNIT_KILOBYTE : NO_UNIT, 2, 7,
1874 (unsigned long long) pstc->stack_size,
1875 (unsigned long long) pstc->stack_ref);
1886 ***************************************************************************
1887 * Display I/O statistics.
1890 * @prev Index in array where stats used as reference are.
1891 * @curr Index in array for current sample statistics.
1892 * @dis TRUE if a header line must be printed.
1893 * @disp_avg TRUE if average stats are displayed.
1894 * @prev_string String displayed at the beginning of a header line. This is
1895 * the timestamp of the previous sample, or "Average" when
1896 * displaying average stats.
1897 * @curr_string String displayed at the beginning of current sample stats.
1898 * This is the timestamp of the current sample, or "Average"
1899 * when displaying average stats.
1900 * @itv Interval of time in 1/100th of a second.
1903 * 0 if all the processes to display have terminated.
1904 * <> 0 if there are still some processes left to display.
1905 ***************************************************************************
1907 int write_pid_io_stats(int prev, int curr, int dis, int disp_avg,
1908 char *prev_string, char *curr_string,
1909 unsigned long long itv)
1911 struct pid_stats *pstc, *pstp;
1912 struct st_pid *plist;
1915 double rbytes, wbytes, cbytes;
1918 PRINT_ID_HDR(prev_string, pidflag);
1919 printf(" kB_rd/s kB_wr/s kB_ccwr/s iodelay Command\n");
1922 for (plist = pid_list; plist != NULL; plist = plist->next) {
1924 if ((rc = get_pid_to_display(prev, curr, P_A_IO, P_NULL, plist)) == 0)
1925 /* PID no longer exists */
1928 /* This will be used to compute average delays */
1930 plist->delay_asum_count += 1;
1934 /* PID should not be displayed */
1937 print_line_id(curr_string, plist);
1939 pstc = plist->pstats[curr];
1940 pstp = plist->pstats[prev];
1942 if (!NO_PID_IO(plist->flags)) {
1943 rbytes = S_VALUE(pstp->read_bytes, pstc->read_bytes, itv);
1944 wbytes = S_VALUE(pstp->write_bytes, pstc->write_bytes, itv);
1945 cbytes = S_VALUE(pstp->cancelled_write_bytes,
1946 pstc->cancelled_write_bytes, itv);
1947 if (!DISPLAY_UNIT(pidflag)) {
1952 cprintf_f(DISPLAY_UNIT(pidflag) ? UNIT_BYTE : NO_UNIT, 3, 9, 2,
1953 rbytes, wbytes, cbytes);
1956 /* I/O file not readable (permission denied or file non existent) */
1957 sprintf(dstr, " %9.2f %9.2f %9.2f", -1.0, -1.0, -1.0);
1958 cprintf_s(IS_ZERO, "%s", dstr);
1960 /* I/O delays come from another file (/proc/#/stat) */
1962 cprintf_f(NO_UNIT, 1, 7, 0,
1963 (double) (pstc->blkio_swapin_delays - pstp->blkio_swapin_delays) /
1964 plist->delay_asum_count);
1967 cprintf_u64(NO_UNIT, 1, 7,
1968 (unsigned long long) (pstc->blkio_swapin_delays - pstp->blkio_swapin_delays));
1979 ***************************************************************************
1980 * Display context switches statistics.
1983 * @prev Index in array where stats used as reference are.
1984 * @curr Index in array for current sample statistics.
1985 * @dis TRUE if a header line must be printed.
1986 * @prev_string String displayed at the beginning of a header line. This is
1987 * the timestamp of the previous sample, or "Average" when
1988 * displaying average stats.
1989 * @curr_string String displayed at the beginning of current sample stats.
1990 * This is the timestamp of the current sample, or "Average"
1991 * when displaying average stats.
1992 * @itv Interval of time in 1/100th of a second.
1995 * 0 if all the processes to display have terminated.
1996 * <> 0 if there are still some processes left to display.
1997 ***************************************************************************
1999 int write_pid_ctxswitch_stats(int prev, int curr, int dis,
2000 char *prev_string, char *curr_string,
2001 unsigned long long itv)
2003 struct pid_stats *pstc, *pstp;
2004 struct st_pid *plist;
2008 PRINT_ID_HDR(prev_string, pidflag);
2009 printf(" cswch/s nvcswch/s Command\n");
2012 for (plist = pid_list; plist != NULL; plist = plist->next) {
2014 if (get_pid_to_display(prev, curr, P_A_CTXSW, P_NULL, plist) <= 0)
2017 print_line_id(curr_string, plist);
2019 pstc = plist->pstats[curr];
2020 pstp = plist->pstats[prev];
2022 cprintf_f(NO_UNIT, 2, 9, 2,
2023 S_VALUE(pstp->nvcsw, pstc->nvcsw, itv),
2024 S_VALUE(pstp->nivcsw, pstc->nivcsw, itv));
2034 ***************************************************************************
2035 * Display scheduling priority and policy information.
2038 * @prev Index in array where stats used as reference are.
2039 * @curr Index in array for current sample statistics.
2040 * @dis TRUE if a header line must be printed.
2041 * @prev_string String displayed at the beginning of a header line. This is
2042 * the timestamp of the previous sample, or "Average" when
2043 * displaying average stats.
2044 * @curr_string String displayed at the beginning of current sample stats.
2045 * This is the timestamp of the current sample, or "Average"
2046 * when displaying average stats.
2049 * 0 if all the processes to display have terminated.
2050 * <> 0 if there are still some processes left to display.
2051 ***************************************************************************
2053 int write_pid_rt_stats(int prev, int curr, int dis,
2054 char *prev_string, char *curr_string)
2056 struct pid_stats *pstc;
2057 struct st_pid *plist;
2061 PRINT_ID_HDR(prev_string, pidflag);
2062 printf(" prio policy Command\n");
2065 for (plist = pid_list; plist != NULL; plist = plist->next) {
2067 if (get_pid_to_display(prev, curr, P_A_RT, P_NULL, plist) <= 0)
2070 print_line_id(curr_string, plist);
2072 pstc = plist->pstats[curr];
2074 cprintf_u64(NO_UNIT, 1, 4,
2075 (unsigned long long) pstc->priority);
2076 cprintf_s(IS_STR, " %6s", GET_POLICY(pstc->policy));
2086 ***************************************************************************
2087 * Display some kernel tables values for tasks.
2090 * @prev Index in array where stats used as reference are.
2091 * @curr Index in array for current sample statistics.
2092 * @dis TRUE if a header line must be printed.
2093 * @disp_avg TRUE if average stats are displayed.
2094 * @prev_string String displayed at the beginning of a header line. This is
2095 * the timestamp of the previous sample, or "Average" when
2096 * displaying average stats.
2097 * @curr_string String displayed at the beginning of current sample stats.
2098 * This is the timestamp of the current sample, or "Average"
2099 * when displaying average stats.
2102 * 0 if all the processes to display have terminated.
2103 * <> 0 if there are still some processes left to display.
2104 ***************************************************************************
2106 int write_pid_ktab_stats(int prev, int curr, int dis, int disp_avg,
2107 char *prev_string, char *curr_string)
2109 struct pid_stats *pstc;
2110 struct st_pid *plist;
2114 PRINT_ID_HDR(prev_string, pidflag);
2115 printf(" threads fd-nr");
2116 printf(" Command\n");
2119 for (plist = pid_list; plist != NULL; plist = plist->next) {
2121 if ((rc = get_pid_to_display(prev, curr, P_A_KTAB, P_NULL, plist)) == 0)
2122 /* PID no longer exists */
2125 pstc = plist->pstats[curr];
2127 /* This will be used to compute average */
2129 plist->total_threads += pstc->threads;
2130 plist->total_fd_nr += pstc->fd_nr;
2131 plist->tf_asum_count += 1;
2135 /* PID should not be displayed */
2138 print_line_id(curr_string, plist);
2141 cprintf_f(NO_UNIT, 2, 7, 0,
2142 (double) plist->total_threads / plist->tf_asum_count,
2143 NO_PID_FD(plist->flags) ?
2145 (double) plist->total_fd_nr / plist->tf_asum_count);
2148 cprintf_u64(NO_UNIT, 1, 7,
2149 (unsigned long long) pstc->threads);
2150 if (NO_PID_FD(plist->flags)) {
2151 cprintf_s(IS_ZERO, " %7s", "-1");
2154 cprintf_u64(NO_UNIT, 1, 7,
2155 (unsigned long long) pstc->fd_nr);
2167 ***************************************************************************
2168 * Display statistics.
2171 * @prev Index in array where stats used as reference are.
2172 * @curr Index in array for current sample statistics.
2173 * @dis TRUE if a header line must be printed.
2174 * @disp_avg TRUE if average stats are displayed.
2175 * @prev_string String displayed at the beginning of a header line. This is
2176 * the timestamp of the previous sample, or "Average" when
2177 * displaying average stats.
2178 * @curr_string String displayed at the beginning of current sample stats.
2179 * This is the timestamp of the current sample, or "Average"
2180 * when displaying average stats.
2183 * 0 if all the processes to display have terminated.
2184 * <> 0 if there are still some processes left to display.
2185 ***************************************************************************
2187 int write_stats_core(int prev, int curr, int dis, int disp_avg,
2188 char *prev_string, char *curr_string)
2190 unsigned long long itv, deltot_jiffies;
2194 TEST_STDOUT(STDOUT_FILENO);
2196 /* Total number of jiffies spent on the interval */
2197 deltot_jiffies = get_interval(tot_jiffies[prev], tot_jiffies[curr]);
2199 itv = get_interval(uptime_cs[prev], uptime_cs[curr]);
2201 if (DISPLAY_ONELINE(pidflag)) {
2202 if (DISPLAY_TASK_STATS(tskflag)) {
2203 again += write_pid_task_all_stats(prev, curr, dis, prev_string, curr_string,
2204 itv, deltot_jiffies);
2206 if (DISPLAY_CHILD_STATS(tskflag)) {
2207 again += write_pid_child_all_stats(prev, curr, dis, prev_string, curr_string);
2211 /* Display CPU stats */
2212 if (DISPLAY_CPU(actflag)) {
2214 if (DISPLAY_TASK_STATS(tskflag)) {
2215 again += write_pid_task_cpu_stats(prev, curr, dis, disp_avg,
2216 prev_string, curr_string,
2217 itv, deltot_jiffies);
2219 if (DISPLAY_CHILD_STATS(tskflag)) {
2220 again += write_pid_child_cpu_stats(prev, curr, dis, disp_avg,
2221 prev_string, curr_string);
2225 /* Display memory stats */
2226 if (DISPLAY_MEM(actflag)) {
2228 if (DISPLAY_TASK_STATS(tskflag)) {
2229 again += write_pid_task_memory_stats(prev, curr, dis, disp_avg,
2230 prev_string, curr_string, itv);
2232 if (DISPLAY_CHILD_STATS(tskflag) && DISPLAY_MEM(actflag)) {
2233 again += write_pid_child_memory_stats(prev, curr, dis, disp_avg,
2234 prev_string, curr_string);
2238 /* Display stack stats */
2239 if (DISPLAY_STACK(actflag)) {
2240 again += write_pid_stack_stats(prev, curr, dis, disp_avg,
2241 prev_string, curr_string);
2244 /* Display I/O stats */
2245 if (DISPLAY_IO(actflag)) {
2246 again += write_pid_io_stats(prev, curr, dis, disp_avg, prev_string,
2250 /* Display context switches stats */
2251 if (DISPLAY_CTXSW(actflag)) {
2252 again += write_pid_ctxswitch_stats(prev, curr, dis, prev_string,
2256 /* Display kernel table stats */
2257 if (DISPLAY_KTAB(actflag)) {
2258 again += write_pid_ktab_stats(prev, curr, dis, disp_avg,
2259 prev_string, curr_string);
2262 /* Display scheduling priority and policy information */
2263 if (DISPLAY_RT(actflag)) {
2264 again += write_pid_rt_stats(prev, curr, dis, prev_string, curr_string);
2268 if (DISPLAY_ALL_PID(pidflag)) {
2276 ***************************************************************************
2277 * Print statistics average.
2280 * @curr Index in array for current sample statistics.
2281 * @dis TRUE if a header line must be printed.
2282 ***************************************************************************
2284 void write_stats_avg(int curr, int dis)
2288 strncpy(string, _("Average:"), 16);
2290 write_stats_core(2, curr, dis, TRUE, string, string);
2294 ***************************************************************************
2295 * Get previous and current timestamps, then display statistics.
2298 * @curr Index in array for current sample statistics.
2299 * @dis TRUE if a header line must be printed.
2302 * 0 if all the processes to display have terminated.
2303 * <> 0 if there are still some processes left to display.
2304 ***************************************************************************
2306 int write_stats(int curr, int dis)
2308 char cur_time[2][TIMESTAMP_LEN];
2310 /* Get previous timestamp */
2311 if (DISPLAY_ONELINE(pidflag)) {
2312 strcpy(cur_time[!curr], "# Time ");
2314 else if (PRINT_SEC_EPOCH(pidflag)) {
2315 snprintf(cur_time[!curr], sizeof(cur_time[!curr]), "%-11ld", mktime(&ps_tstamp[!curr]));
2316 cur_time[!curr][sizeof(cur_time[!curr]) - 1] = '\0';
2318 else if (is_iso_time_fmt()) {
2319 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%H:%M:%S", &ps_tstamp[!curr]);
2322 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%X", &ps_tstamp[!curr]);
2325 /* Get current timestamp */
2326 if (PRINT_SEC_EPOCH(pidflag)) {
2327 snprintf(cur_time[curr], sizeof(cur_time[curr]), "%-11ld", mktime(&ps_tstamp[curr]));
2328 cur_time[curr][sizeof(cur_time[curr]) - 1] = '\0';
2330 else if (is_iso_time_fmt()) {
2331 strftime(cur_time[curr], sizeof(cur_time[curr]), "%H:%M:%S", &ps_tstamp[curr]);
2334 strftime(cur_time[curr], sizeof(cur_time[curr]), "%X", &ps_tstamp[curr]);
2337 return (write_stats_core(!curr, curr, dis, FALSE,
2338 cur_time[!curr], cur_time[curr]));
2342 ***************************************************************************
2343 * Main loop: Read and display PID stats.
2346 * @dis_hdr Set to TRUE if the header line must always be printed.
2347 * @rows Number of rows of screen.
2348 ***************************************************************************
2350 void rw_pidstat_loop(int dis_hdr, int rows)
2352 int curr = 1, dis = 1;
2354 unsigned long lines = rows;
2355 struct st_pid *plist;
2357 /* Read system uptime */
2358 read_uptime(&uptime_cs[0]);
2361 if (DISPLAY_MEM(actflag)) {
2362 /* Get total memory */
2363 read_proc_meminfo();
2367 /* Display since boot time */
2368 ps_tstamp[1] = ps_tstamp[0];
2369 write_stats(0, DISP_HDR);
2373 /* Set a handler for SIGALRM */
2374 memset(&alrm_act, 0, sizeof(alrm_act));
2375 alrm_act.sa_handler = alarm_handler;
2376 sigaction(SIGALRM, &alrm_act, NULL);
2379 /* Save the first stats collected. Will be used to compute the average */
2380 ps_tstamp[2] = ps_tstamp[0];
2381 tot_jiffies[2] = tot_jiffies[0];
2382 uptime_cs[2] = uptime_cs[0];
2383 for (plist = pid_list; plist != NULL; plist = plist->next) {
2384 memcpy(plist->pstats[2], plist->pstats[0], PID_STATS_SIZE);
2387 /* Set a handler for SIGINT */
2388 memset(&int_act, 0, sizeof(int_act));
2389 int_act.sa_handler = int_handler;
2390 sigaction(SIGINT, &int_act, NULL);
2392 /* Wait for SIGALRM (or possibly SIGINT) signal */
2396 /* SIGINT/SIGCHLD signals caught during first interval: Exit immediately */
2400 /* Every PID is potentially nonexistent */
2401 set_pid_nonexistent(pid_list);
2404 get_localtime(&ps_tstamp[curr], 0);
2406 /* Read system uptime (in 1/100th of a second) */
2407 read_uptime(&(uptime_cs[curr]));
2421 again = write_stats(curr, dis);
2434 if (signal_caught) {
2435 /* SIGINT/SIGCHLD signals caught => Display average stats */
2437 printf("\n"); /* Skip "^C" displayed on screen */
2447 * The one line format uses a raw time value rather than time strings
2448 * so the average doesn't really fit.
2450 if (!DISPLAY_ONELINE(pidflag))
2452 /* Write stats average */
2453 write_stats_avg(curr, dis_hdr);
2458 ***************************************************************************
2459 * Start a program that will be monitored by pidstat.
2462 * @argc Number of arguments.
2463 * @argv Arguments values.
2466 * The PID of the program executed.
2467 ***************************************************************************
2469 pid_t exec_pgm(int argc, char **argv)
2472 char *args[argc + 1];
2486 for (i = 0; i < argc; i++) {
2491 execvp(args[0], args);
2499 * Set a handler for SIGCHLD (signal that will be received
2500 * by pidstat when the child program terminates).
2501 * The handler is the same as for SIGINT: Stop and display
2502 * average statistics.
2504 memset(&chld_act, 0, sizeof(chld_act));
2505 chld_act.sa_handler = int_handler;
2506 sigaction(SIGCHLD, &chld_act, NULL);
2513 ***************************************************************************
2514 * Main entry to the pidstat program.
2515 ***************************************************************************
2517 int main(int argc, char **argv)
2519 int opt = 1, dis_hdr = -1, pid_nr = 0;
2522 struct utsname header;
2527 /* Init National Language Support */
2531 /* Init color strings */
2537 /* Compute page shift in kB */
2540 /* Process args... */
2541 while (opt < argc) {
2543 if (!strcmp(argv[opt], "-e")) {
2548 add_list_pid(&pid_list, exec_pgm(argc - opt, argv + opt), 0);
2552 else if (!strcmp(argv[opt], "-p")) {
2558 for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ","), pid_nr++) {
2559 if (!strcmp(t, K_ALL)) {
2560 pidflag |= P_D_ALL_PID;
2563 else if (!strcmp(t, K_SELF)) {
2564 add_list_pid(&pid_list, getpid(), 0);
2567 if (strspn(t, DIGITS) != strlen(t)) {
2574 add_list_pid(&pid_list, pid, 0);
2580 else if (!strcmp(argv[opt], "-C")) {
2584 strncpy(commstr, argv[opt++], sizeof(commstr));
2585 commstr[sizeof(commstr) - 1] = '\0';
2586 pidflag |= P_F_COMMSTR;
2587 if (!strlen(commstr)) {
2592 else if (!strcmp(argv[opt], "-G")) {
2596 strncpy(procstr, argv[opt++], sizeof(procstr));
2597 procstr[sizeof(procstr) - 1] = '\0';
2598 pidflag |= P_F_PROCSTR;
2599 if (!strlen(procstr)) {
2604 else if (!strcmp(argv[opt], "--human")) {
2605 pidflag |= P_D_UNIT;
2609 else if (!strncmp(argv[opt], "--dec=", 6) && (strlen(argv[opt]) == 7)) {
2610 /* Get number of decimal places */
2611 dplaces_nr = atoi(argv[opt] + 6);
2612 if ((dplaces_nr < 0) || (dplaces_nr > 2)) {
2618 else if (!strcmp(argv[opt], "-T")) {
2625 if (!strcmp(argv[opt], K_P_TASK)) {
2628 else if (!strcmp(argv[opt], K_P_CHILD)) {
2631 else if (!strcmp(argv[opt], K_P_ALL)) {
2632 tskflag |= P_TASK + P_CHILD;
2641 /* Option used individually. See below for grouped option */
2642 else if (!strcmp(argv[opt], "-U")) {
2643 /* Display username instead of UID */
2644 pidflag |= P_D_USERNAME;
2645 if (argv[++opt] && (argv[opt][0] != '-') &&
2646 (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) {
2647 strncpy(userstr, argv[opt++], sizeof(userstr));
2648 userstr[sizeof(userstr) - 1] = '\0';
2649 pidflag |= P_F_USERSTR;
2650 if (!strlen(userstr)) {
2656 else if (!strncmp(argv[opt], "-", 1)) {
2657 for (i = 1; *(argv[opt] + i); i++) {
2659 switch (*(argv[opt] + i)) {
2662 /* Display I/O usage */
2668 /* Display timestamps in sec since the epoch */
2669 pidflag |= P_D_SEC_EPOCH;
2673 /* Display stats on one line */
2674 pidflag |= P_D_ONELINE;
2679 pidflag |= P_F_IRIX_MODE;
2683 /* Display whole command line */
2684 pidflag |= P_D_CMDLINE;
2688 /* Display priority and policy info */
2694 /* Display memory usage */
2700 /* Display stack sizes */
2701 actflag |= P_A_STACK;
2706 /* Display stats for threads */
2711 /* When option is grouped, it cannot take an arg */
2712 pidflag |= P_D_USERNAME;
2716 /* Display CPU usage */
2722 /* Print version number and exit */
2727 /* Display some kernel tables values */
2728 actflag |= P_A_KTAB;
2733 /* Display context switches */
2734 actflag |= P_A_CTXSW;
2745 else if (interval < 0) { /* Get interval */
2746 if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
2749 interval = atol(argv[opt++]);
2756 else if (count <= 0) { /* Get count value */
2757 if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) ||
2761 count = atol(argv[opt++]);
2772 /* Interval not set => display stats since boot time */
2776 if (!DISPLAY_PID(pidflag)) {
2780 /* Check flags and set default values */
2783 /* Count nb of proc */
2784 cpu_nr = get_cpu_nr(~0, FALSE);
2794 rows = get_win_height();
2799 get_localtime(&(ps_tstamp[0]), 0);
2802 * Don't buffer data if redirected to a pipe.
2803 * Note: With musl-c, the behavior of this function is undefined except
2804 * when it is the first operation on the stream.
2806 setbuf(stdout, NULL);
2808 /* Get system name, release number and hostname */
2810 print_gal_header(&(ps_tstamp[0]), header.sysname, header.release,
2811 header.nodename, header.machine, cpu_nr,
2815 rw_pidstat_loop(dis_hdr, rows);
2817 /* Free structures */
2818 sfree_pid(&pid_list, TRUE);