diff -Nru atop-2.8.1/acctproc.c atop-2.9.0/acctproc.c --- atop-2.8.1/acctproc.c 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/acctproc.c 2023-05-13 08:20:27.000000000 +0000 @@ -61,8 +61,9 @@ static count_t acctexp (comp_t ct); static int acctvers(int); -static void acctrestarttrial(); +static void acctrestarttrial(void); static void switchshadow(void); +static int atopacctd(int); /* ** possible process accounting files used by (ps)acct package @@ -120,11 +121,12 @@ int acctswon(void) { - int i, j, sematopid, sempacctpubid; + int i, j, sematopid; static ushort vals[] = {1, ATOPACCTTOT}; union {ushort *array;} arg = {vals}; struct stat statbuf; char *ep; + int ret; /* ** when a particular environment variable is present, atop should @@ -171,105 +173,8 @@ ** when the atopacctd daemon is active on this system, ** it should be the preferred way to read the accounting records */ - if ( (sempacctpubid = semget(PACCTPUBKEY, 2, 0)) != -1) - { - FILE *cfp; - char shadowpath[128]; - struct flock flock; - struct timespec maxsemwait = {3, 0}; - - if (! droprootprivs() ) - mcleanstop(42, "failed to drop root privs\n"); - - if (semtimedop(sempacctpubid, semreglock, 2, &maxsemwait) == -1) - { - acctfd = -1; - regainrootprivs(); - return 3; - } - - snprintf(shadowpath, sizeof shadowpath, "%s/%s/%s", - pacctdir, PACCTSHADOWD, PACCTSHADOWC); - - if ( (cfp = fopen(shadowpath, "r")) ) - { - if (fscanf(cfp, "%ld/%ld", - &curshadowseq, &maxshadowrec) == 2) - { - fclose(cfp); - - snprintf(shadowpath, sizeof shadowpath, - PACCTSHADOWF, pacctdir, - PACCTSHADOWD, curshadowseq); - - if ( (acctfd = open(shadowpath, O_RDONLY))!=-1) - { - if ( !acctvers(acctfd) ) - { - int maxcnt = 40; - - if ( fork() == 0 ) - exit(0); - - (void) wait((int *) 0); - - while ( !acctvers(acctfd) && - --maxcnt) - usleep(50000); - - if (!acctversion) - { - (void) close(acctfd); - acctfd = -1; - - semop(sempacctpubid, - &semrelse, 1); - semop(sempacctpubid, - &semunlock, 1); - - regainrootprivs(); - return 1; - } - } - - /* - ** set read lock on current shadow file - */ - flock.l_type = F_RDLCK; - flock.l_whence = SEEK_SET; - flock.l_start = 0; - flock.l_len = 1; - - if ( fcntl(acctfd, F_SETLK, &flock) - != -1) - { - supportflags |= ACCTACTIVE; - regainrootprivs(); - semop(sempacctpubid, - &semunlock, 1); - return 0; - } - - (void) close(acctfd); - } - else - { - perror("open shadowpath"); - abort(); - } - } - else - { - fprintf(stderr, - "fscanf failed on shadow currency\n"); - fclose(cfp); - maxshadowrec = 0; - } - } - - (void) semop(sempacctpubid, &semrelse, 1); - (void) semop(sempacctpubid, &semunlock, 1); - } + if ( (ret = atopacctd(1)) >= 0 ) + return ret; /* ** check if process accounting is already switched on @@ -351,9 +256,9 @@ */ (void) semop(sematopid, &semclaim, 1); - /* - ** are we the first to use the accounting-mechanism ? - */ + /* + ** are we the first to use the accounting-mechanism ? + */ if (semctl(sematopid, 1, GETVAL, 0) == ATOPACCTTOT) { /* @@ -464,6 +369,138 @@ } /* +** try to use process accounting via the atopacctd daemon +** swon: 1 - initial switch on +** 0 - switch on again after the atopacct service has been down +*/ +static int +atopacctd(int swon) +{ + int sempacctpubid; + + acctfd = -1; // reset to not being open + + /* + ** open semaphore group that has been initialized by atopacctd + ** semaphore 0: 100 counting down to reflect number of users of atopacctd + ** semaphore 1: value 0 is locked and value 1 is unlocked (binary semaphore) + */ + if ( (sempacctpubid = semget(PACCTPUBKEY, 2, 0)) != -1) + { + FILE *cfp; + char shadowpath[128]; + struct flock flock; + struct timespec maxsemwait = {3, 0}; + + if (! droprootprivs() ) + mcleanstop(42, "failed to drop root privs\n"); + + /* + ** lock binary semaphore and decrement semaphore 0 (extra user) + */ + if (semtimedop(sempacctpubid, semreglock, 2, &maxsemwait) == -1) + { + regainrootprivs(); + return 3; + } + + /* + ** open the 'current' file, containing the current + ** shadow sequence number and maximum number of records + ** per shadow file + */ + snprintf(shadowpath, sizeof shadowpath, "%s/%s/%s", + pacctdir, PACCTSHADOWD, PACCTSHADOWC); + + if ( (cfp = fopen(shadowpath, "r")) ) + { + if (fscanf(cfp, "%ld/%ld", + &curshadowseq, &maxshadowrec) == 2) + { + fclose(cfp); + + /* + ** open the current shadow file + */ + snprintf(shadowpath, sizeof shadowpath, + PACCTSHADOWF, pacctdir, + PACCTSHADOWD, curshadowseq); + + if ( (acctfd = open(shadowpath, O_RDONLY))!=-1) + { + if ( swon && !acctvers(acctfd) ) + { + + int maxcnt = 40; + + if ( fork() == 0 ) + exit(0); + + (void) wait((int *) 0); + + while ( !acctvers(acctfd) && + --maxcnt) + usleep(50000); + + if (!acctversion) + { + (void) close(acctfd); + acctfd = -1; + + semop(sempacctpubid, + &semrelse, 1); + semop(sempacctpubid, + &semunlock, 1); + + regainrootprivs(); + return 1; + } + } + + /* + ** set read lock on current shadow file + */ + flock.l_type = F_RDLCK; + flock.l_whence = SEEK_SET; + flock.l_start = 0; + flock.l_len = 1; + + if ( fcntl(acctfd, F_SETLK, &flock) + != -1) + { + supportflags |= ACCTACTIVE; + regainrootprivs(); + semop(sempacctpubid, + &semunlock, 1); + return 0; + } + + (void) close(acctfd); + acctfd = -1; + } + else + { + perror("open shadowpath"); + abort(); + } + } + else + { + fprintf(stderr, + "fscanf failed on shadow currency\n"); + fclose(cfp); + maxshadowrec = 0; + } + } + + (void) semop(sempacctpubid, &semrelse, 1); + (void) semop(sempacctpubid, &semunlock, 1); + } + + return -1; // try another accounting mechanism +} + +/* ** determine the version of the accounting-record layout/length ** and reposition the seek-pointer to the end of the accounting file */ @@ -599,22 +636,10 @@ struct stat statacc; /* - ** if accounting not supported, skip call - */ - if (acctfd == -1) - return 0; - - /* - ** determine the current size of the accounting file - */ - if (fstat(acctfd, &statacc) == -1) - return 0; - - /* ** handle atopacctd-based process accounting on bases of ** fixed-chunk shadow files */ - if (maxshadowrec) + if (maxshadowrec) // atopacctd has been detected before? { unsigned long numrecs = 0; long newseq; @@ -622,6 +647,26 @@ FILE *cfp; /* + ** determine the current size of the current shadow file + ** (fails if acctfd == -1) and determine if the file + ** has not been deleted by stopping the atopacct service + */ + if (fstat(acctfd, &statacc) == -1 || statacc.st_nlink == 0) + { + /* close the previous obsolete shadow file */ + (void) close(acctfd); + + acctsize = 0; + + /* reacquire the current real acctfd */ + if (atopacctd(0)) + return 0; // reaqcuire failed + + if (fstat(acctfd, &statacc) == -1) + return 0; + } + + /* ** verify how many new processes are added to the current ** shadow file */ @@ -668,10 +713,25 @@ ** determine the size of newest shadow file */ if (stat(shadowpath, &statacc) == -1) + { + fprintf(stderr, "failed to stat the size of newest shadow file\n"); return numrecs; + } - numrecs += ((newseq - curshadowseq - 1) * maxshadowrec) + - (statacc.st_size / acctrecsz); + /* + ** Check cases like statacc.st_size / acctrecsz > maxshadowrec, + ** and atopacctd restarts at the same time, now newseq is zero. + ** Omit this interval's statistics by returning zero. + */ + if (newseq > curshadowseq) + { + numrecs += ((newseq - curshadowseq - 1) * maxshadowrec) + + (statacc.st_size / acctrecsz); + } + else + { + numrecs = 0; + } return numrecs; } @@ -682,6 +742,12 @@ */ { /* + ** determine size of current process accounting file + */ + if (acctfd == -1 || fstat(acctfd, &statacc) == -1) + return 0; + + /* ** accounting reset? */ if (acctsize > statacc.st_size) @@ -810,6 +876,7 @@ struct acct acctrec; struct acct_v3 acctrec_v3; struct stat statacc; + int filled; /* ** if accounting not supported, skip call @@ -826,8 +893,7 @@ /* ** check all exited processes in accounting file */ - for (nrexit=0, api=accproc; nrexit < nrprocs; - nrexit++, api++, acctsize += acctrecsz) + for (nrexit=0, api=accproc; nrexit < nrprocs; ) { /* ** in case of shadow accounting files, we might have to @@ -909,6 +975,7 @@ strncpy(api->gen.name, acctrec.ac_comm, PNAMLEN); api->gen.name[PNAMLEN] = '\0'; + filled = 1; break; case 3: @@ -937,8 +1004,17 @@ strncpy(api->gen.name, acctrec_v3.ac_comm, PNAMLEN); api->gen.name[PNAMLEN] = '\0'; + filled = 1; break; } + + if (filled == 1) { + nrexit++; + api++; + acctsize += acctrecsz; + + filled = 0; + } } if (acctsize > ACCTMAXFILESZ && !maxshadowrec) @@ -956,7 +1032,7 @@ ** that is currently using the accounting file */ static void -acctrestarttrial() +acctrestarttrial(void) { struct stat statacc; int sematopid; diff -Nru atop-2.8.1/acctproc.h atop-2.9.0/acctproc.h --- atop-2.8.1/acctproc.h 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/acctproc.h 2023-05-13 08:20:27.000000000 +0000 @@ -21,6 +21,10 @@ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ** See the GNU General Public License for more details. */ + +#ifndef __ACCTPROC__ +#define __ACCTPROC__ + int acctswon(void); void acctswoff(void); unsigned long acctprocnt(void); @@ -156,3 +160,5 @@ comp_t ac_swaps; /* Number of Swaps */ char ac_comm[ACCT_COMM]; /* Command Name */ }; + +#endif diff -Nru atop-2.8.1/atopacctd.c atop-2.9.0/atopacctd.c --- atop-2.8.1/atopacctd.c 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/atopacctd.c 2023-05-13 08:20:27.000000000 +0000 @@ -120,11 +120,8 @@ static void gcshadows(unsigned long *, unsigned long); static void setcurrent(long); static int acctsize(struct acct *); -static void cleanup(int); - - -int netlink_open(void); // from netlink.c -int netlink_recv(int, int); // from netlink.c +static void parent_cleanup(int); +static void child_cleanup(int); int @@ -276,19 +273,19 @@ } /* - ** prepare cleanup signal handler - */ - memset(&sigcleanup, 0, sizeof sigcleanup); - sigcleanup.sa_handler = cleanup; - sigemptyset(&sigcleanup.sa_mask); - - /* ** daemonize this process ** i.e. be sure that the daemon is no session leader (any more) ** and get rid of a possible bad context that might have been ** inherited from ancestors */ parentpid = getpid(); // to be killed when initialized + + /* + ** prepare cleanup signal handler + */ + memset(&sigcleanup, 0, sizeof sigcleanup); + sigemptyset(&sigcleanup.sa_mask); + sigcleanup.sa_handler = parent_cleanup; (void) sigaction(SIGTERM, &sigcleanup, (struct sigaction *)0); if ( fork() ) // implicitly switch to background @@ -308,6 +305,9 @@ if ( fork() ) // finish parent; continue in child exit(0); // --> no session leader, no ctty + sigcleanup.sa_handler = child_cleanup; + (void) sigaction(SIGTERM, &sigcleanup, (struct sigaction *)0); + getrlimit(RLIMIT_NOFILE, &rlim); for (i=0; i < rlim.rlim_cur; i++) // close all files, but @@ -1114,11 +1114,17 @@ } /* -** signal catcher: +** signal catchers: ** set flag to be verified in main loop to cleanup and terminate */ void -cleanup(int sig) +child_cleanup(int sig) { cleanup_and_go = sig; } + +void +parent_cleanup(int sig) +{ + exit(0); +} diff -Nru atop-2.8.1/atopacctd.h atop-2.9.0/atopacctd.h --- atop-2.8.1/atopacctd.h 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/atopacctd.h 2023-05-13 08:20:27.000000000 +0000 @@ -26,6 +26,9 @@ ** -------------------------------------------------------------------------- */ +#ifndef __ATOPACCTD__ +#define __ATOPACCTD__ + /* ** keys to access the semaphores */ @@ -61,3 +64,5 @@ // sequence and MAXSHADOWREC #define MAXSHADOWREC 10000 // number of accounting records per shadow file + +#endif diff -Nru atop-2.8.1/atop.c atop-2.9.0/atop.c --- atop-2.8.1/atop.c 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/atop.c 2023-05-13 08:20:27.000000000 +0000 @@ -113,162 +113,6 @@ ** flags. In this way various representation-layers (ASCII, graphical, ...) ** can be linked with 'atop'; the one to use can eventually be chosen ** at runtime. -** -** $Log: atop.c,v $ -** Revision 1.49 2010/10/23 14:01:00 gerlof -** Show counters for total number of running and sleep (S and D) threads. -** -** Revision 1.48 2010/10/23 08:18:15 gerlof -** Catch signal SIGUSR2 to take a final sample and stop. -** Needed for improved of suspend/hibernate. -** -** Revision 1.47 2010/04/23 12:20:19 gerlof -** Modified mail-address in header. -** -** Revision 1.46 2010/04/23 09:57:28 gerlof -** Version (flag -V) handled earlier after startup. -** -** Revision 1.45 2010/04/17 17:19:41 gerlof -** Allow modifying the layout of the columns in the system lines. -** -** Revision 1.44 2010/04/16 13:00:23 gerlof -** Automatically start another version of atop if the logfile to -** be read has not been created by the current version. -** -** Revision 1.43 2010/03/04 10:51:10 gerlof -** Support I/O-statistics on logical volumes and MD devices. -** -** Revision 1.42 2009/12/31 11:33:33 gerlof -** Sanity-check to bypass kernel-bug showing 497 days of CPU-consumption. -** -** Revision 1.41 2009/12/17 10:51:31 gerlof -** Allow own defined process line with key 'o' and a definition -** in the atoprc file. -** -** Revision 1.40 2009/12/17 08:15:15 gerlof -** Introduce branch-key to go to specific time in raw file. -** -** Revision 1.39 2009/12/10 13:34:32 gerlof -** Cosmetical changes. -** -** Revision 1.38 2009/12/10 11:55:38 gerlof -** Introduce -L flag for line length. -** -** Revision 1.37 2009/12/10 10:43:33 gerlof -** Correct calculation of node name. -** -** Revision 1.36 2009/12/10 09:19:06 gerlof -** Various changes related to redesign of user-interface. -** Made by JC van Winkel. -** -** Revision 1.35 2009/11/27 15:11:55 gerlof -** *** empty log message *** -** -** Revision 1.34 2009/11/27 15:07:25 gerlof -** Give up root-privileges at a earlier stage. -** -** Revision 1.33 2009/11/27 14:01:01 gerlof -** Introduce system-wide configuration file /etc/atoprc -** -** Revision 1.32 2008/01/07 10:16:13 gerlof -** Implement summaries for atopsar. -** -** Revision 1.31 2007/11/06 09:16:05 gerlof -** Add keyword atopsarflags to configuration-file ~/.atoprc -** -** Revision 1.30 2007/08/16 11:58:35 gerlof -** Add support for atopsar reporting. -** -** Revision 1.29 2007/03/20 13:01:36 gerlof -** Introduction of variable supportflags. -** -** Revision 1.28 2007/03/20 12:13:00 gerlof -** Be sure that all tstat struct's are initialized with binary zeroes. -** -** Revision 1.27 2007/02/19 11:55:04 gerlof -** Bug-fix: flag -S was not recognized any more. -** -** Revision 1.26 2007/02/13 10:34:20 gerlof -** Support parseable output with flag -P -** -** Revision 1.25 2007/01/26 12:10:40 gerlof -** Add configuration-value 'swoutcritsec'. -** -** Revision 1.24 2007/01/18 10:29:22 gerlof -** Improved syntax-checking for ~/.atoprc file. -** Support for network-interface busy-percentage. -** -** Revision 1.23 2006/02/07 08:27:04 gerlof -** Cosmetic changes. -** -** Revision 1.22 2005/10/28 09:50:29 gerlof -** All flags/subcommands are defined as macro's. -** -** Revision 1.21 2005/10/21 09:48:48 gerlof -** Per-user accumulation of resource consumption. -** -** Revision 1.20 2004/12/14 15:05:38 gerlof -** Implementation of patch-recognition for disk and network-statistics. -** -** Revision 1.19 2004/10/26 13:42:49 gerlof -** Also lock current physical pages in memory. -** -** Revision 1.18 2004/09/15 08:23:42 gerlof -** Set resource limit for locked memory to infinite, because -** in certain environments it is set to 32K (causes atop-malloc's -** to fail). -** -** Revision 1.17 2004/05/06 09:45:44 gerlof -** Ported to kernel-version 2.6. -** -** Revision 1.16 2003/07/07 09:18:22 gerlof -** Cleanup code (-Wall proof). -** -** Revision 1.15 2003/07/03 11:16:14 gerlof -** Implemented subcommand `r' (reset). -** -** Revision 1.14 2003/06/30 11:29:12 gerlof -** Handle configuration file ~/.atoprc -** -** Revision 1.13 2003/01/14 09:01:10 gerlof -** Explicit clearing of malloced space for exited processes. -** -** Revision 1.12 2002/10/30 13:44:51 gerlof -** Generate notification for statistics since boot. -** -** Revision 1.11 2002/10/08 11:34:52 gerlof -** Modified storage of raw filename. -** -** Revision 1.10 2002/09/26 13:51:47 gerlof -** Limit header lines by not showing disks. -** -** Revision 1.9 2002/09/17 10:42:00 gerlof -** Copy functions rawread() and rawwrite() to separate source-file rawlog.c -** -** Revision 1.8 2002/08/30 07:49:35 gerlof -** Implement possibility to store and retrieve atop-data in raw format. -** -** Revision 1.7 2002/08/27 12:09:16 gerlof -** Allow raw data file to be written and to be read (with compression). -** -** Revision 1.6 2002/07/24 11:12:07 gerlof -** Redesigned to ease porting to other UNIX-platforms. -** -** Revision 1.5 2002/07/11 09:15:53 root -** *** empty log message *** -** -** Revision 1.4 2002/07/08 09:20:45 root -** Bug solution: flag list overflow. -** -** Revision 1.3 2001/11/07 09:17:41 gerlof -** Use /proc instead of /dev/kmem for process-level statistics. -** -** Revision 1.2 2001/10/04 13:03:15 gerlof -** Separate kopen() function called i.s.o. implicit with first kmem-read -** -** Revision 1.1 2001/10/02 10:43:19 gerlof -** Initial revision -** */ #include @@ -294,6 +138,7 @@ #include "photoproc.h" #include "photosyst.h" #include "showgeneric.h" +#include "showlinux.h" #include "parseable.h" #include "json.h" #include "gpucom.h" @@ -323,7 +168,10 @@ char calcpss = 0; /* boolean: read/calculate process PSS */ char getwchan = 0; /* boolean: obtain wchan string */ char rmspaces = 0; /* boolean: remove spaces from command */ - /* name in case of parseable output */ + /* name in case of parsable output */ + +char displaymode = 'T'; /* 'T' = text, 'D' = draw */ +char barmono = 0; /* boolean: bar without categories? */ unsigned short hertz; unsigned int pidwidth; @@ -353,53 +201,8 @@ */ static void readrc(char *, int); -void do_flags(char *, char *); -void do_interval(char *, char *); -void do_linelength(char *, char *); -void do_username(char *, char *); -void do_procname(char *, char *); -void do_maxcpu(char *, char *); -void do_maxgpu(char *, char *); -void do_maxdisk(char *, char *); -void do_maxmdd(char *, char *); -void do_maxlvm(char *, char *); -void do_maxintf(char *, char *); -void do_maxifb(char *, char *); -void do_maxnfsm(char *, char *); -void do_maxcont(char *, char *); -void do_maxnuma(char *, char *); -void do_maxllc(char *, char *); -void do_colinfo(char *, char *); -void do_colalmost(char *, char *); -void do_colcrit(char *, char *); -void do_colthread(char *, char *); -void do_ownsysprcline(char *, char *); -void do_ownallcpuline(char *, char *); -void do_ownindivcpuline(char *, char *); -void do_owncplline(char *, char *); -void do_ownmemline(char *, char *); -void do_ownswpline(char *, char *); -void do_ownpagline(char *, char *); -void do_ownmemnumaline(char *, char *); -void do_owncpunumaline(char *, char *); -void do_ownllcline(char *, char *); -void do_owndskline(char *, char *); -void do_ownnettransportline(char *, char *); -void do_ownnetnetline(char *, char *); -void do_ownnetinterfaceline(char *, char *); -void do_owninfinibandline(char *, char *); -void do_ownprocline(char *, char *); -void do_cpucritperc(char *, char *); -void do_gpucritperc(char *, char *); -void do_memcritperc(char *, char *); -void do_swpcritperc(char *, char *); -void do_dskcritperc(char *, char *); -void do_netcritperc(char *, char *); -void do_swoutcritsec(char *, char *); -void do_almostcrit(char *, char *); -void do_atopsarflags(char *, char *); -void do_pacctdir(char *, char *); -void do_perfevents(char *, char *); +static void do_interval(char *, char *); +static void do_linelength(char *, char *); static struct { char *tag; @@ -545,6 +348,14 @@ vis.show_samp = rawwrite; break; + case 'B': /* bar graphs ? */ + displaymode = 'D'; + break; + + case 'H': /* bar graphs ? */ + barmono = 1; + break; + case 'r': /* reading of raw data ? */ if (optind < argc) { @@ -582,7 +393,7 @@ prusage(argv[0]); break; - case 'P': /* parseable output? */ + case 'P': /* parsable output? */ if ( !parsedef(optarg) ) prusage(argv[0]); @@ -764,7 +575,6 @@ { struct sigaction sigact; static time_t timelimit; - void getusr1(int), getusr2(int); /* ** reserve space for system-level statistics @@ -1090,15 +900,17 @@ myname); printf("\n"); printf("\tgeneric flags:\n"); + printf("\t -%c show bar graphs for system statistics\n", MBARGRAPH); + printf("\t -%c show bar graphs without categories\n", MBARMONO); printf("\t -%c show version information\n", MVERSION); printf("\t -%c show or log all processes (i.s.o. active processes " "only)\n", MALLPROC); printf("\t -%c calculate proportional set size (PSS) per process\n", MCALCPSS); printf("\t -%c determine WCHAN (string) per thread\n", MGETWCHAN); - printf("\t -P generate parseable output for specified label(s)\n"); + printf("\t -P generate parsable output for specified label(s)\n"); printf("\t -J generate JSON output for specified label(s)\n"); - printf("\t -%c no spaces in parseable output for command (line)\n", + printf("\t -%c no spaces in parsable output for command (line)\n", MRMSPACES); printf("\t -L alternate line length (default 80) in case of " "non-screen output\n"); @@ -1164,15 +976,13 @@ /* ** functions to handle a particular tag in the .atoprc file */ -extern int get_posval(char *name, char *val); - -void +static void do_interval(char *name, char *val) { interval = get_posval(name, val); } -void +static void do_linelength(char *name, char *val) { linelen = get_posval(name, val); @@ -1273,7 +1083,7 @@ { fprintf(stderr, "%s: warning at line %2d " - "- tag name %s not valid\n", + "- tag name %s not recognized\n", path, line, tagname); errorcnt++; diff -Nru atop-2.8.1/atopconvert.c atop-2.9.0/atopconvert.c --- atop-2.8.1/atopconvert.c 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/atopconvert.c 2023-05-13 08:20:27.000000000 +0000 @@ -82,6 +82,29 @@ #include "prev/photosyst_28.h" #include "prev/photoproc_28.h" +#include "prev/photosyst_29.h" +#include "prev/photoproc_29.h" + + +void justcopy(void *, void *, count_t, count_t); + +void scpu_to_21(void *, void *, count_t, count_t); +void sdsk_to_21(void *, void *, count_t, count_t); +void sint_to_22(void *, void *, count_t, count_t); +void scpu_to_27(void *, void *, count_t, count_t); +void smem_to_27(void *, void *, count_t, count_t); +void sdsk_to_27(void *, void *, count_t, count_t); +void smem_to_28(void *, void *, count_t, count_t); +void sdsk_to_28(void *, void *, count_t, count_t); +void smnu_to_28(void *, void *, count_t, count_t); +void scnu_to_28(void *, void *, count_t, count_t); +void tgen_to_21(void *, void *, count_t, count_t); +void tmem_to_21(void *, void *, count_t, count_t); +void tgen_to_22(void *, void *, count_t, count_t); +void tcpu_to_26(void *, void *, count_t, count_t); +void tmem_to_26(void *, void *, count_t, count_t); +void tcpu_to_28(void *, void *, count_t, count_t); +void tmem_to_28(void *, void *, count_t, count_t); /////////////////////////////////////////////////////////////// // Conversion functions @@ -486,6 +509,7 @@ struct sstat_26 sstat_26; struct sstat_27 sstat_27; struct sstat_28 sstat_28; +struct sstat_29 sstat_29; struct sstat sstat; struct tstat_20 tstat_20; @@ -497,6 +521,7 @@ struct tstat_26 tstat_26; struct tstat_27 tstat_27; struct tstat_28 tstat_28; +struct tstat_29 tstat_29; struct tstat tstat; struct convertall { @@ -825,6 +850,39 @@ {sizeof(struct gpu_28), STROFFSET(&tstat_28.gpu, &tstat_28), justcopy}, }, + + {SETVERSION(2,9), // 2.8 --> 2.9 + sizeof(struct sstat_29), &sstat_29, + sizeof(struct tstat_29), NULL, + + {sizeof(struct cpustat_29), &sstat_29.cpu, justcopy}, + {sizeof(struct memstat_29), &sstat_29.mem, justcopy}, + {sizeof(struct netstat_29), &sstat_29.net, justcopy}, + {sizeof(struct intfstat_29), &sstat_29.intf, justcopy}, + {sizeof(struct dskstat_29), &sstat_29.dsk, justcopy}, + {sizeof(struct nfsstat_29), &sstat_29.nfs, justcopy}, + {sizeof(struct contstat_29), &sstat_29.cfs, justcopy}, + {sizeof(struct wwwstat_29), &sstat_29.www, justcopy}, + {sizeof(struct pressure_29), &sstat_29.psi, justcopy}, + {sizeof(struct gpustat_29), &sstat_29.gpu, justcopy}, + {sizeof(struct ifbstat_29), &sstat_29.ifb, justcopy}, + {sizeof(struct memnuma_29), &sstat_29.memnuma, justcopy}, + {sizeof(struct cpunuma_29), &sstat_29.cpunuma, justcopy}, + {sizeof(struct llcstat_29), &sstat_29.llc, justcopy}, + + {sizeof(struct gen_29), + STROFFSET(&tstat_29.gen, &tstat_29), justcopy}, + {sizeof(struct cpu_29), + STROFFSET(&tstat_29.cpu, &tstat_29), justcopy}, + {sizeof(struct dsk_29), + STROFFSET(&tstat_29.dsk, &tstat_29), justcopy}, + {sizeof(struct mem_29), + STROFFSET(&tstat_29.mem, &tstat_29), justcopy}, + {sizeof(struct net_29), + STROFFSET(&tstat_29.net, &tstat_29), justcopy}, + {sizeof(struct gpu_29), + STROFFSET(&tstat_29.gpu, &tstat_29), justcopy}, + }, }; int numconvs = sizeof convs / sizeof(struct convertall); diff -Nru atop-2.8.1/atopgpud atop-2.9.0/atopgpud --- atop-2.8.1/atopgpud 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/atopgpud 2023-05-13 08:20:27.000000000 +0000 @@ -86,9 +86,17 @@ self.gpuhandle = gpuhandle self.stats = Stats() - self.stats.busid = pciInfo.busId.decode('ascii', errors='replace') - self.stats.devname = pynvml.nvmlDeviceGetName(gpuhandle).decode( - 'ascii', errors='replace').replace(' ', '_') + + self.stats.busid = pciInfo.busId + self.stats.devname = pynvml.nvmlDeviceGetName(gpuhandle) + + # nvml backward compatibility + if type(self.stats.busid) == bytes: + self.stats.busid = self.stats.busid.decode('ascii', errors='replace') + if type(self.stats.devname) == bytes: + self.stats.devname = self.stats.devname.decode('ascii', errors='replace') + + self.stats.devname = self.stats.devname.replace(' ', '_') self.stats.tasksupport = 0 # process stats support diff -Nru atop-2.8.1/atop.h atop-2.9.0/atop.h --- atop-2.8.1/atop.h 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/atop.h 2023-05-13 08:20:27.000000000 +0000 @@ -21,6 +21,9 @@ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ** See the GNU General Public License for more details. */ +#ifndef __ATOP__ +#define __ATOP__ + #define EQ 0 #define SECONDSINDAY 86400 #define RAWNAMESZ 256 @@ -94,6 +97,9 @@ extern char flaglist[]; extern struct visualize vis; +extern char displaymode; +extern char barmono; + extern int osrel; extern int osvers; extern int ossub; @@ -207,3 +213,12 @@ void netatop_exitfind(unsigned long, struct tstat *, struct tstat *); void set_oom_score_adj(void); int run_in_guest(void); + +void getusr1(int), getusr2(int); +void do_pacctdir(char *, char *); +void do_atopsarflags(char *, char *); + +int netlink_open(void); +int netlink_recv(int, int); + +#endif diff -Nru atop-2.8.1/atop-rotate.service atop-2.9.0/atop-rotate.service --- atop-2.8.1/atop-rotate.service 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/atop-rotate.service 2023-05-13 08:20:27.000000000 +0000 @@ -4,4 +4,4 @@ [Service] Type=oneshot -ExecStart=/usr/bin/systemctl try-restart atop.service +ExecStart=/usr/bin/systemctl restart atop.service diff -Nru atop-2.8.1/atopsar.c atop-2.9.0/atopsar.c --- atop-2.8.1/atopsar.c 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/atopsar.c 2023-05-13 08:20:27.000000000 +0000 @@ -407,7 +407,6 @@ engine(void) { struct sigaction sigact; - void getusr1(int); int nrgpus; /* number of GPUs */ int nrgpuproc, /* number of GPU procs */ diff -Nru atop-2.8.1/ChangeLog atop-2.9.0/ChangeLog --- atop-2.8.1/ChangeLog 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/ChangeLog 2023-05-13 08:20:27.000000000 +0000 @@ -1,1245 +1,590 @@ -commit 5bc3edc64ca01dd46922b34402c67c6f286399aa -Author: Gerlof Langeveld -Date: Sat Jan 7 14:27:52 2023 +0100 - - Version 2.8.1 - -M version.h - -commit a2c45992f59ce6110b24b22fc9bf65028197e96d -Author: Gerlof Langeveld -Date: Sat Jan 7 12:21:03 2023 +0100 - - Solve compiler warnings about format-truncation - -M various.c - -commit b93546d1ed03ec5b6e0c747a2571820129d60771 +commit db3454393c07f73462df89d39e722fb1d82e5609 Author: Gerlof Langeveld -Date: Sat Jan 7 12:02:37 2023 +0100 - - Avoid buffer overflows during value formatting +Date: Sat May 13 10:17:41 2023 +0200 -M various.c - -commit 490c73ce516bff6dd53786e2be29bbcbc4185071 -Author: Gerlof Langeveld -Date: Sat Jan 7 12:00:36 2023 +0100 - - Correct NUMA conversion in logfiles from version 2.7 to 2.8 + Prepare for atop 2.9 M atopconvert.c +A prev/photoproc_29.h +A prev/photosyst_29.h -commit ed17722fa50f3a0be4d1d4a86336180a38a69109 +commit fab95e9104a08ff23ab73f3490d63bdaa36094e7 Author: Gerlof Langeveld -Date: Sat Jan 7 11:16:42 2023 +0100 +Date: Sat May 13 10:16:56 2023 +0200 - Added contributor + Avoid compiler warning by limiting PSI average -M AUTHORS +M showsys.c -commit 338637d911b98d67b3d3b8a25e25532659a36571 +commit 6a5dc86e2db59c8cfa954a6738c50b6d03b1a1dc +Merge: 6423e5d e5f9489 Author: Gerlof Langeveld -Date: Thu Dec 29 23:32:50 2022 +0100 +Date: Sun May 7 16:55:30 2023 +0200 - Rename AUTHOR in spec file - -M rpmspec/atop.specsystemd + Merge pull request #258 from bytedance/PAG_STEAL + + add man for PAG steal -commit 6621b213326fdeba79e8c15214f7e78597ce391f +commit 6423e5d0276de2da3c794839996a5b5489ada60c +Merge: 0e0a4f5 1e10331 Author: Gerlof Langeveld -Date: Thu Dec 29 23:24:23 2022 +0100 +Date: Sun May 7 16:49:45 2023 +0200 - Up-to-date list of contributors + Merge branch 'bytedance-atopacct_fail' -D AUTHOR -A AUTHORS - -commit be2d5c43e4fd8b6f2754e2cabdd55857d5ad8da2 +commit 1e10331add3ffb94f43e017835a4943c99865462 Author: Gerlof Langeveld -Date: Thu Dec 29 22:33:12 2022 +0100 +Date: Sun May 7 16:47:47 2023 +0200 - New version 2.8.0 + Install cleanup function to avoid termination of parent process -M version.h +M atopacctd.c -commit d7f71c0bfc3980a0103ed23f55a8db4c72b8d6f2 -Author: Gerlof Langeveld -Date: Thu Dec 29 21:56:05 2022 +0100 +commit e5f9489fba326d3db9ff914bc9972afef0ccca74 +Author: liutingjieni +Date: Sat May 6 11:52:00 2023 +0800 - Update timestamp of man pages + add man for PAG steal M man/atop.1 -M man/atopacctd.8 -M man/atopcat.1 -M man/atopconvert.1 -M man/atopgpud.8 -M man/atoprc.5 -M man/atopsar.1 -commit 3bfd0dbbeaf023c351235a44b92ad8b3691c4648 +commit ef4eaba7aefcf166e869ffd474ef61bb2ef765f6 +Merge: 0e0a4f5 22bebc9 Author: Gerlof Langeveld -Date: Thu Dec 29 15:39:34 2022 +0100 +Date: Sat Apr 29 23:04:59 2023 +0200 - Adapt atopconvert for conversion to version 2.8 + Merge branch 'atopacct_fail' of github.com:bytedance/atop into bytedance-atopacct_fail -M README -M atopconvert.c -A prev/netstats_wrong.h -A prev/photoproc_28.h -M prev/photosyst_20.h -M prev/photosyst_21.h -M prev/photosyst_22.h -M prev/photosyst_23.h -M prev/photosyst_24.h -M prev/photosyst_25.h -M prev/photosyst_26.h -M prev/photosyst_27.h -A prev/photosyst_28.h - -commit 33c0abcd3423e276e538d26f4850c266abdcdbf5 -Merge: 3b7ad4b 6cc222a +commit 0e0a4f5af9bb9c6a66388add69161d5aa9caabeb Author: Gerlof Langeveld -Date: Thu Dec 29 12:11:20 2022 +0100 - - Merge pull request #229 from pizhenwei/json-fix - - Json fix - -commit 3b7ad4b61f94776ddc0f9755ef2f0353c3eac962 -Author: Gerlof Langeveld -Date: Thu Dec 29 11:59:11 2022 +0100 - - Atopacct.service verifies if psacct/acct is active (solves issue #227) - To avoid that the atopacctd daemon and the (ps)acct service - both try to activate process accounting continuously, the - atopacct.service refuses to start when the (ps)acct service is - already active. +Date: Sat Apr 29 10:07:07 2023 +0200 -M atopacct.service + Oomkills event should not remain orange after boot values -commit 6cc222a8c528112f39f8657b84367a0a3b7c961f -Author: zhenwei pi -Date: Tue Dec 27 10:15:51 2022 +0800 - - Add avque counters to json data - - Signed-off-by: zhenwei pi +M drawbar.c -M json.c - -commit be1fc512f00b36d6b80d9fe6aa73640787bf3417 -Author: zhenwei pi -Date: Tue Dec 27 09:36:44 2022 +0800 +commit 9517b682ff6729a4e7d810720ea7ba2a0b20e8a2 +Merge: 967a629 a8082ea +Author: Gerlof Langeveld +Date: Fri Apr 28 15:57:42 2023 +0200 - Add inflight counters to json data + Merge pull request #249 from natoscott/fix-warnings - Signed-off-by: zhenwei pi - -M json.c + Resolve compiler warnings from latest versions of GCC -commit cf4d2d268f9fefadc5b56e717eb57f7260223834 -Author: zhenwei pi -Date: Fri Dec 2 16:05:46 2022 +0800 - - Fix LLC output for Json - - Signed-off-by: zhenwei pi - -M json.c - -commit 66641630457e3b607391dd08bfe79b0a3ccbf416 +commit 967a629645eb7170af6b6dac155b8abfc3439271 +Merge: 75f8e14 8d18a52 Author: Gerlof Langeveld -Date: Sat Dec 24 13:24:24 2022 +0100 - - Solve format-overflow/maybe-uninitialized warnings +Date: Fri Apr 28 15:52:02 2023 +0200 -M atopsar.c -M gpucom.c -M photosyst.c -M showprocs.c -M various.c + Merge pull request #246 from Algebra970/clean-versdate + + Added versdate.h to make clean target -commit b6041164d738ba51eeacc9ef2676745564a33ee7 +commit 75f8e144fcf2790959811e8a746d2f11f9d50cfb Author: Gerlof Langeveld -Date: Sat Dec 24 13:22:22 2022 +0100 +Date: Sun Apr 23 22:22:38 2023 +0200 - Reshuffle counters to ease raw file conversion + Clarified atop man page -M photosyst.h +M man/atop.1 -commit e395f48d4709bbcb03918cc752d9f8a2387e5c53 +commit 2dd526cb1ac6ba5f0e23cf7bcb27083aa4bc2b6e Author: Gerlof Langeveld -Date: Sat Dec 24 12:13:12 2022 +0100 +Date: Sun Apr 23 12:15:42 2023 +0200 - Recalculate average queue in parseable output + Closing bracket missing in synopsis M man/atop.1 -M parseable.c -commit 8d133c6f51f7d1424f3c4590dbb8621e971688ec +commit dd16cc037c1dc2d24b721d5f3186a2ac5a4870c2 Author: Gerlof Langeveld -Date: Sat Dec 24 11:58:33 2022 +0100 +Date: Sat Apr 22 12:24:25 2023 +0200 - Corrected the order of inflight/avque + Add highlight concerning bar graph mode -M man/atop.1 -M parseable.c +M README.md -commit 3a210c1b77f5069a8be364a8107aaa686bccdcd3 -Merge: e52eaaa ebfda60 +commit 2bc0a169330215b3d5bae3dff0b9d38aa1ff8814 +Merge: 2eeed8b 57851a8 Author: Gerlof Langeveld -Date: Sat Dec 24 11:54:06 2022 +0100 +Date: Sat Apr 22 12:11:54 2023 +0200 - Merge branch 'bytedance-add-inflight' + Merge branch 'bargraph' -commit ebfda604a89c0906dc038636887ec0e11d0590d3 +commit 57851a8032cd79460536d2a5314d4384ea2aef81 Author: Gerlof Langeveld -Date: Sat Dec 24 11:53:36 2022 +0100 - - Add inflight and avque counters to parseable data +Date: Sat Apr 22 11:12:30 2023 +0200 + + Introduce bar graph mode + Besides all detailed information that is supplied by atop on + system and process level, a (character-based) bar graph can be + shown about the utilization of the most critical system resources, + i.e. processors, disks, network interfaces and memory. The original + interface of atop is still compatible and is called 'text mode' + from now on, while the additional interface is called + 'bar graph mode'. + Atop will still be started in 'text mode' unless the '-B' flag is + used. Within an interactive atop session, the 'B' key can be used + to switch between the two modes. + The bar graph mode can be used for live monitoring as well as + for viewing of raw files. +M Makefile +M atop.c +M atop.h +A drawbar.c M man/atop.1 +M man/atoprc.5 M parseable.c +M showgeneric.c +M showgeneric.h M showlinux.c +M showprocs.c +M showsys.c -commit a57b7ef96fba4fbb98ba92048c2ced2e90d92298 -Merge: e52eaaa a232722 -Author: Gerlof Langeveld -Date: Sat Dec 24 11:38:27 2022 +0100 - - Merge branch 'add-inflight' of github.com:bytedance/atop into bytedance-add-inflight - -commit e52eaaa65f87ad0315cbd33362d046e2d786f5bc -Merge: a082801 c6a0661 -Author: Gerlof Langeveld -Date: Sat Dec 24 11:17:39 2022 +0100 - - Merge pull request #225 from natoscott/bdelay-space-fix - - Fix BDELAY in priphead call to make_proc_prints for schedprocs - -commit a0828016b1c5e87b73b58ff427b371dc0cb93195 -Merge: 7e83f05 e892d9a +commit 2eeed8b8ff907ac330459b6ca0a2b3a8b2860ae2 Author: Gerlof Langeveld -Date: Sat Dec 24 11:16:40 2022 +0100 - - Merge pull request #224 from natoscott/deviate-container-preindex - - Correct the array index used for previous samples per-container CPU values +Date: Mon Apr 3 08:35:36 2023 +0200 -commit 7e83f05e98d33f52f9c892a886584a0bdf6dec26 -Merge: e40449b cff3075 -Author: Gerlof Langeveld -Date: Sat Dec 24 11:10:56 2022 +0100 + Freeing ethlink should depend of ifdef - Merge pull request #223 from natoscott/dskavio-print-fix - - Reinstate dropped printing of avio msec values between 99.95 and 9995 +M ifprop.c -commit e40449b7b2623da00f43a2141be536c38d196d5e -Merge: 21bd4fd a26b937 +commit 5f5a41407222a407add06d59da46b5e64a3f763d +Merge: 0c7ce67 e34e936 Author: Gerlof Langeveld -Date: Sat Dec 24 10:46:42 2022 +0100 +Date: Sat Apr 1 22:19:08 2023 +0200 - Merge pull request #222 from bytedance/display-rbd-disk - - photosyst: add ceph rbd disk display + Merge branch 'bytedance-recollect-nprocexit-by-reacquire-acctfd' -commit 21bd4fd643605e1b42e3e61f4ae82ce4bfadba5b -Merge: d8d97f9 2b07b01 +commit e34e9366c6ce4bf0de2b9f875e0e8375618bdd1e Author: Gerlof Langeveld -Date: Sat Dec 24 10:43:14 2022 +0100 +Date: Sat Apr 1 22:18:28 2023 +0200 - Merge pull request #217 from bytedance/fix-numanr - - photosys.c: correct the numa number for NUM and NUC + Added reset to indicate shadow file to be closed -commit c6a066167ee33a9cbef353439594f7dfa61cb940 -Author: Nathan Scott -Date: Thu Dec 15 15:16:08 2022 +1100 - - Fix BDELAY in priphead call to make_proc_prints for schedprocs - -M showlinux.c - -commit e892d9afae4883f3488542a664de83012e42d9c1 -Author: Nathan Scott -Date: Thu Dec 15 13:49:00 2022 +1100 - - Correct the array index used for previous samples per-container CPU values - - Compare to previous sample array handling for NFS, disks, interfaces, etc. - -M deviate.c - -commit cff3075a5a05f98629c3f22c6c5d8466ca46c573 -Author: Nathan Scott -Date: Thu Dec 15 11:27:04 2022 +1100 +M acctproc.c - Reinstate dropped printing of avio msec values between 99.95 and 9995 - - I believe this was an accidental change in commit db9eef1d4 which has - introduced a code path where no value is added to the buffer at all. +commit 22bebc9fc2a3d83799072d711aa2a977d4f7c481 +Author: Ting Liu +Date: Thu Mar 23 20:50:43 2023 +0800 + + fix atopacctd.c: failed to start atopacct.service + + The type of atopacct.service is "forking". If the parent process + does not exit within 90 seconds after starting, the service is + considered to have failed to start. + After executing fork(), there is a situation where the child process + gets scheduled before the parent process. When the child process + reaches the kill() function and sends a signal to the parent process, + the parent process has not yet been scheduled. After receiving the + signal, the parent process executes the signal handling function but + has not yet reached the pause() function. As a result, the parent + process gets stuck in the pause() function and does not exit, causing + the atopacct.service to fail to start. -M showsys.c +M atopacctd.c -commit a26b937efb4cac44c5a8adcd0a7981501b48b83e +commit 90efc4bea781b71cc8f77f8f9484c80fbfd21b49 Author: Fei Li -Date: Tue Dec 13 16:15:08 2022 +0800 +Date: Mon Jan 16 17:40:23 2023 +0800 - photosyst: add ceph rbd disk display + acctatop: reacquire acctfd to collect nprocexit for some bad cases - Ceph block devices are used in many scenarios, especially in k8s - cluster, in which case an external ceph storage cluster is used to - implement persistent storage for pods inside the k8s cluster. - - An example in /proc/diskstats is as follows: - 254 288 rbd18 25359 1 2459552 18239 2 0 16 42 0 19706 11358 0 0 0 0 - 254 289 rbd18p1 25240 1 2453022 18190 2 0 16 42 0 19655 11337 0 0 0 0 + In current code, the acctfd value in acctproc.c will not be updated + once atop runs. This can cause 'nprocexit is zero' problem when + atopacct.service restarts but atop.service not, in which case, the + previous shadow file that atop read is being '(deleted)'. As acctfd + does not change, atop will continue reading that obsolete file whose + size will never grow, leading to get a wrong number of exited process, + e.i. always be zero from now on until atop.service restarts. + + Fix this by reacquiring the new shadow file fd after atopacct.service + restarts. By the way, only reacquire for atopacct case; as for other + cases that directly read from acct() file, restarting service does + not make the nprocexit a wrong value. Besides, if the atopacct or + (p)acct service is stopped for a while, ignore this situation too, + as we are not sure if the action is on purpose or not. Signed-off-by: Fei Li -M photosyst.c +M acctproc.c -commit 2b07b014153b6ccb00a4e02b134fa6cc9cec6fc2 +commit 6f4761381c6f669613a5339542fa2e6cbac41adf Author: Fei Li -Date: Tue Dec 6 20:48:13 2022 +0800 +Date: Fri Jan 13 21:16:58 2023 +0800 - photosys.c: correct the numa number for NUM and NUC - - Current code uses array index to store the numa number, which may - sort the numanr to a wrong value after the qsort() funtion in - generic_samp(). + Calibrate nprocexit to avoid atop coredumps unexpectedly - Fix this by re-adding the 'numanr' member for struct mempernuma and - cpupernuma to store the correct numa number. The permanent 'numanr' - member can guarantee the numa number from adjusting after qsort(), - while the qsort() function can continue working by sorting NUM from - small to large according to free memory, and sorting NUC from small - to large according to idle cpu. + There's a case that the shadow file becomes larger than its + limit, e.i. (maxshadowrec * acctrecsz), and then suddenly + atopacct.service restarts suddenly. + + In current logic supposing atopacct.service does not restart, we + will continue to read a new shadowpath whose sequence is one greater + than the fulled one. But this does not work if atopacct.service + restarts, as the new shadowpath's sequence number will be started + with zero, leading to a negative value when comparing with the + fulled one. And thus return the unsigned long 'nprocexit' as a + very huge positive number. + + What's more, after acctphotoproc(), we get a wrong acctsize + (including reset acctsize to zero), and thus a dummy huge 'curpexit' + struct whose partial attributes like gen/cpu/mem/disk are still + zeroed. Then later, the same as 'devtstat' struct. Finally, these + zeroed attributes will cause a glibc sort() coredump like "*a = 0" + during compcpu(), compmem() and so on. + + To fix this case, + - firstly, return numrecs as zero once detecting atopacct.service + restarts or other bad cases, regarding as an incomplete sample; + - secondly, to avoid other bad cases, calibrate nrexit during + acctphotoproc(), re-calculate the real 'nprocexit' to avoid the + "*a = 0" error. - Besides, add NUC for JSON output. - - Fixes: 1fbda3f1081a ("Additions to NUMA counters") - Reported-by: Qi Zheng Signed-off-by: Fei Li - -M deviate.c -M json.c -M parseable.c -M photosyst.c -M photosyst.h -M showsys.c - -commit d8d97f93f2425be97e4aca6df5c91fd18913ac16 -Author: Gerlof Langeveld -Date: Sat Nov 26 12:56:14 2022 +0100 - - Timeout when setting semaphore in atop (issue #207) + Co-authored-by: Ting Liu M acctproc.c -commit e1a50559934bb9a1ca2b41eba77134abeaae3d22 +commit 0c7ce67ab72041f1829ef71cfa00f4b7bfa630d6 +Merge: 7a917f3 8390f4d Author: Gerlof Langeveld -Date: Sat Nov 26 11:38:17 2022 +0100 +Date: Sat Mar 25 12:23:06 2023 +0100 - Current CPU set to -1 for terminated process (solves issue #201) - When a process has terminated (status 'E') the current CPU will - be set to -1 (means: unknown) in the parsable output with label PRC. - -M deviate.c -M man/atop.1 + Merge pull request #248 from bytedance/fix-json-lvm + + json.c: fix avque counters output -commit ecfc92e04f33ebd09ca0c06debc16585ec993002 -Merge: 75a67ee 580099c +commit 7a917f3e20980d1488ddb8a111a5f1f460561843 +Merge: 6b9691a 6809e6f Author: Gerlof Langeveld -Date: Sat Nov 26 10:41:39 2022 +0100 +Date: Sat Mar 25 12:22:03 2023 +0100 - Merge branch 'pizhenwei-json' + Merge pull request #245 from xixiliguo/fix-paging-stat + + fix calculation for scan and steal -commit 580099c03e344f401755ad5f8297842b7e950083 +commit 6b9691a4248e933ef608bad59ca89302a1fc154d +Merge: eb158ef a273887 Author: Gerlof Langeveld -Date: Sat Nov 26 10:41:00 2022 +0100 - - Typo corrections and correction in man page +Date: Sat Mar 25 12:09:08 2023 +0100 -M json.c -M man/atop.1 + Merge pull request #239 from pizhenwei/fix-memory-leak + + ifprop.c: Fix possible memory leak -commit fb9edb2cabda7368b9115691ee297b71a486904c -Author: zhenwei pi -Date: Mon Nov 14 10:09:39 2022 +0800 +commit 8390f4d028c328ee4d9ca604ec2f14930ddb1ac7 +Author: Fei Li +Date: Mon Mar 6 11:37:24 2023 +0800 - Introduce JSON output by '-J xxx' + json.c: fix avque counters output - It's possible to dump the record by JSON format, this is quite - friendly to web service, and lot of use libraries could parse these - data easily. - - The syntax is similar to parseable output. - - Co-authored-by: Fei Li + Fixes: 6cc222a8c528 ("Add avque counters to json data") Signed-off-by: Fei Li - Signed-off-by: zhenwei pi -M Makefile -M atop.c -A json.c -A json.h -M man/atop.1 - -commit 75a67eee67962ab2b2a787375de6907a008164f9 -Author: Gerlof Langeveld -Date: Tue Nov 1 20:17:39 2022 +0100 - - Add missing counter iInCsumErrors to ICMP counters +M json.c -M netstats.h +commit a8082ea0c401a8a5dc70b62be0027f3e7324b5d5 +Author: Nathan Scott +Date: Mon Mar 6 14:42:56 2023 +1100 -commit a232722a59c4eeeeadf4e8f5c269d59eff6b8f70 -Author: Teng Hu -Date: Mon Aug 15 14:16:25 2022 +0800 - - supplement inflight I/O requests - - Inflight I/O requests count I/O requests issued to the device driver but - have not yet completed, which are useful to analyze system I/O status. - More than this, since plenty of processes remain in D status for a long time - come from I/O troubles, inflight I/O values also help to examine these processes. + Resolve compiler warnings from latest versions of GCC + + Fix an incorrect struct array null test on bdev names, i.e. - Signed-off-by: Teng Hu + "warning: the comparison will always evaluate as ‘true’ for the address of ‘name’ will never be NULL [-Waddress]" + + in disk, LVM and MD block device deviate.c calculations. M deviate.c -M man/atop.1 -M photosyst.c -M photosyst.h -M showlinux.c -M showlinux.h -M showsys.c -commit be42f0b0eed45af5045c2f1d85b4bd87e22ca32f +commit eb158ef2b2a48607788c5cd0a8213100d6df12f8 +Merge: 5073b66 4f04c2c Author: Gerlof Langeveld -Date: Tue Aug 30 16:55:57 2022 +0200 +Date: Fri Mar 3 16:48:57 2023 +0100 - Man page: clarify elapsed time in PRG parseable output + Merge pull request #243 from Algebra970/master + + only call str.decode if nvml returned bytes -M man/atop.1 +commit 8d18a52efd8e77ac48cc5758f8ff5bf686f0142b +Author: elad +Date: Wed Mar 1 18:17:26 2023 +0200 -commit e9f3048f7e04c39d43cd19481e14797d6163556d -Author: Gerlof Langeveld -Date: Tue Aug 30 16:46:23 2022 +0200 + Added versdate.h to make clean target - Exponent calulation for high counter might exceed column width - When a column width was defined of e.g. 4 positions, the value - 99999 was shown as 100e3 instead of 99e3 (upward rounding caused - an extra position). +M Makefile -M various.c +commit 4f04c2ca5695e025413357c608abf9e2d0397a0f +Author: elad +Date: Wed Mar 1 18:14:10 2023 +0200 -commit 38ae774ef76bb5472215b4e0dc7e339b2fdddff2 -Author: Gerlof Langeveld -Date: Tue Aug 30 16:24:22 2022 +0200 + Revert "Added versdate.h to make clean target" + + This reverts commit 2973c8ee71d1cc23853fc79c503571b257ae97a8. - PID selection can not be undone for same interval - When pressing 'I' to select particular PIDs and pressing 'I' - again within the same interval to deselect by pressing the - Enter-key, the deselection is ignored. - Solved by reinitializing the input buffer. +M Makefile -M showgeneric.c +commit 2973c8ee71d1cc23853fc79c503571b257ae97a8 +Author: elad +Date: Wed Mar 1 18:07:52 2023 +0200 -commit ea723065de70854c127daa9545d25df1bab4fd3d -Merge: ba677a7 02479a2 -Author: Gerlof Langeveld -Date: Sat Aug 20 13:36:35 2022 +0200 + Added versdate.h to make clean target - Merge branch 'secondmem' +M Makefile -commit 02479a2ededa76c843d59828d4e8b8886d0723a9 -Author: Gerlof Langeveld -Date: Sat Aug 20 13:32:02 2022 +0200 +commit 6809e6f22c29435a244fe797e28328f37728b101 +Author: peter wang +Date: Wed Mar 1 21:33:46 2023 +0800 - Split the MEM line into two lines and add pagetable size - Since it was hardly possible to view the values in the MEM line - (too many), the memory utilization has been spread over two lines. - The amount of memory used for page tables has been added. + fix calculation for scan and steal -M deviate.c -M man/atop.1 -M parseable.c M photosyst.c -M photosyst.h -M showlinux.c -M showlinux.h -M showsys.c - -commit ba677a79c2cc987db03ea4226fd95a28351b429a -Merge: 76a6774 0933e00 -Author: Gerlof Langeveld -Date: Sat Aug 13 13:05:26 2022 +0200 - - Merge branch 'bytedance-support-sockstat-mem-consumption' -commit 0933e00880ebfb425ac98b106c24c825a10fbdad -Author: Gerlof Langeveld -Date: Sat Aug 13 13:03:04 2022 +0200 +commit 69bf04e1a1f5e8ba7c99da1dc56a3e022ccf83c6 +Author: elad +Date: Sun Feb 26 15:39:00 2023 +0200 - Memory usage for TCP/UDP sockets + only call str.decode if nvml returned bytes -M man/atop.1 -M parseable.c -M photosyst.c -M showlinux.c -M showsys.c - -commit ffdbb1994b9b4ca2de3e6ca6da102a3f9162787e -Merge: 76a6774 a2422e3 -Author: Gerlof Langeveld -Date: Sat Aug 13 11:56:44 2022 +0200 - - Merge branch 'support-sockstat-mem-consumption' of github.com:bytedance/atop into bytedance-support-sockstat-mem-consumption +M atopgpud -commit 76a67740379ffd13644d21ebe9e19f2e87e03273 +commit 5073b66c6945d7b22acdbd9c5ed0f353cf8e0eb9 Author: Gerlof Langeveld -Date: Sat Aug 13 11:49:02 2022 +0200 +Date: Sat Feb 25 14:49:42 2023 +0100 - Add Documentation key to atop-rotate.service/.timer (issue #206) + Add exit epoch to parseable output PRG (solves issue #242) -M atop-rotate.service -M atop-rotate.timer M man/atop.1 +M parseable.c -commit d24484bbc67ceaeb302cbd6294da398aea10c7b7 +commit 9e3b62584ae5cc710f222aaa1f52aa3e25cff49c Author: Gerlof Langeveld -Date: Sat Aug 13 11:30:54 2022 +0200 +Date: Sat Feb 25 14:23:20 2023 +0100 - Correct typos in man pages (solves issue #205) + Minor correction in man page for NVCSW/NIVCSW M man/atop.1 -M man/atopsar.1 -commit 69599a02aa21b77aaf56fc2303b86296c557c1e0 -Merge: 57a808e c9fea4e +commit 788cb32fcd7693f5773f5f4b361908146501a943 Author: Gerlof Langeveld -Date: Sat Aug 13 11:13:56 2022 +0200 - - Merge pull request #198 from bytedance/showhdrline-fix-sprintf-oob - - showhdrline: fix OOB access when COLS is too small +Date: Sat Feb 25 14:13:42 2023 +0100 -commit 57a808e3cdf0f2d4b516a211e8e915b0d972b33f -Merge: 8365a75 5c326ee -Author: Gerlof Langeveld -Date: Sat Aug 13 10:28:46 2022 +0200 + Context switches (voluntary and involuntary) on process level incorrect. + The context switches on process level only concern the values of + the main thread instead of all threads. Corrected by accumulating + values of all threads. - Merge pull request #203 from pizhenwei/fix-compile-error-with-http - - Fix compiling error with -DHTTPSTATS +M photoproc.c -commit 8365a7583e08a27ed14aedd2d0909dbde0513f18 -Merge: d9e0e6a 4243e34 +commit 999103c4983260cfdcbaad30f78030a88358ed16 +Merge: 71a8690 b870681 Author: Gerlof Langeveld -Date: Thu Jul 28 11:58:19 2022 +0200 +Date: Sat Feb 25 14:01:33 2023 +0100 - Merge branch 'cgroup' + Merge branch 'bytedance-photoproc-ctxSwitch' -commit 4243e34f6bb7444f630350843b66c8f490ecc283 +commit b870681434b8df10667f837a8d5cce5bb9d555ec Author: Gerlof Langeveld -Date: Thu Jul 28 11:52:34 2022 +0200 +Date: Sat Feb 25 13:56:58 2023 +0100 - Add cgroup support (solves issue #127) - The current cgroup is registered for systems that are based on cgroup v2. - Apart from the group name also relevant controller information is - maintained, like the cpu.max and the memory.max (for the group itself - and the most restrictive value in the parent groups). + Various modifications releated to (non)voluntary context switches. + - new counters should be added at the end of line for parseable output + - document parseable counters (man page) + - field descriptions in alphabetical order (man page) + - use val2valstr() for counters with a fixed column width -M atop.h -M deviate.c M man/atop.1 M parseable.c -M photoproc.c -M photoproc.h -M rawlog.c -M showgeneric.c -M showgeneric.h M showlinux.c -M showlinux.h M showprocs.c -commit 5c326ee948775afc541ecd88017c5e9d2b4099bf -Author: zhenwei pi -Date: Thu Jul 21 15:52:17 2022 +0800 - - Fix compiling error with -DHTTPSTATS - - Fix compiling error like this: - In file included from atopconvert.c:77: - prev/photosyst_27.h:327:5: error: conflicting types for ‘getwwwstat’ - 327 | int getwwwstat(unsigned short, struct wwwstat_27 *); - | ^~~~~~~~~~ - In file included from atopconvert.c:52: - photosyst.h:361:5: note: previous declaration of ‘getwwwstat’ was here - 361 | int getwwwstat(unsigned short, struct wwwstat *); - | ^~~~~~~~~~ - - Signed-off-by: zhenwei pi - -M prev/photosyst_27.h - -commit a2422e397af5ebbea1a03a36ec82e8bd77632b4a -Author: Fei Li -Date: Fri Jul 8 18:35:52 2022 +0800 - - supplement tcpsock and udpsock memory consumption - - In some production cases, tcp socket consumes lots of memory, which - has no intersection with the statistics in /proc/meminfo file. - - Considering the current code does not collect and record the tcpsock - or udpsock statistics reported via /proc/net/sockstat, supplement - the following two to help locate memory consumption issues: - - tcpsock, number of pages allocated by TCP sockets - - udpsock, number of pages allocated by UDP sockets - - Signed-off-by: Fei Li - -M deviate.c -M man/atop.1 -M parseable.c -M photosyst.c -M photosyst.h -M showlinux.c -M showlinux.h -M showsys.c - -commit d9e0e6a703f152e3e17195afb227596d9983ca4e -Merge: f2e7051 bc84472 +commit d3eea820addf0e943bb08b2934f4cb0a7a900dad +Merge: 71a8690 e22b934 Author: Gerlof Langeveld -Date: Sat Jul 9 12:25:29 2022 +0200 +Date: Sat Feb 25 13:23:06 2023 +0100 - Merge pull request #196 from pizhenwei/fix-man-disk-busy - - Fix disk busy in man page + Merge branch 'photoproc-ctxSwitch' of github.com:bytedance/atop into bytedance-photoproc-ctxSwitch -commit f2e7051a50ed116a1cd35d0e3e2b268cb3472d9e +commit 71a8690bccbce5b8b7794336b74eb12261214ce9 Author: Gerlof Langeveld -Date: Sat Jul 9 12:10:39 2022 +0200 +Date: Sat Feb 25 13:12:27 2023 +0100 - Store PID width in header of raw log - Register the number of positions for PID and TID numbers on the - measured system in the raw log. In this way, the viewing of the - raw log on another system will use the proper column width for PID/TID. + Merging macro protection in header files (pull request #215) -M atop.c +M acctproc.h M atop.h -M rawlog.c +M atopacctd.h +M ifprop.h +M mkdate +M netatop.h +M netatopd.h +M netstats.h +M parseable.h +M photoproc.h M rawlog.h -M showlinux.c -M various.c +M showgeneric.h +M showlinux.h +M version.h -commit c9fea4e3d55b589ec202fb651f461c7acffb8fc0 +commit e22b934636935e973136b6d1bc3285e83ddb2451 Author: Fei Li -Date: Fri Jun 10 15:06:21 2022 +0800 +Date: Wed Nov 23 14:51:24 2022 +0800 - showhdrline: fix OOB access when COLS is too small - - - How to reproduce: - Drag the window to the far right, a "Segmentation fault (core dumped)" - message occurs. + Add nvcsw and nivcsw for each process - - Debug: - Add some print values, saying COLS=2, thus maxw. + As we all know, too much context switches can lead to poor + performance. Besides, sometimes one same process deployed in two + places may behave different. Thus it's necessary to collect the + - nvcsw (number of times that the program was context-switched + voluntarily, for instance while waiting for an I/O operation + to complete) and + - nivcsw (number of times the process was context-switched + involuntarily, e.g. the time slice expired) + two indicators to monitor the performance. - After getspacings(), elemptr becomes a NULL array again: maxw is too - small, so after nitems times of memmove(), newelems is NULL. - - Then back to showhdrline(), as each curelem.f is zero, no chead is - assigned to buf and col is still zero. However, after the calculation: - allign=COLS-col-pagindiclen;//align=2-0-4=-2 < 0, previous code jumps - to sprintf(buf+col+allign, "%s", pagindic), which triggers - out-of-bounds access as col+allign = -2 < 0. - - - Fix: - Fix this by judging if (col+allign >= 0) before jumping to avoid the - OOB access. - - Reported-by: Qi Zheng Signed-off-by: Fei Li -M showprocs.c - -commit bc84472f20c9d8c101901b5b32f04168a596af27 -Author: zhenwei pi -Date: Mon May 16 08:59:37 2022 +0800 - - Fix disk busy in man page - - Reference source code from Linux: - https://github.com/torvalds/linux/blob/master/block/blk-core.c - - void update_io_ticks(struct block_device *part, unsigned long now, bool end) - { - unsigned long stamp; - again: - stamp = READ_ONCE(part->bd_stamp); - if (unlikely(time_after(now, stamp))) { - if (likely(cmpxchg(&part->bd_stamp, stamp, now) == stamp)) - __part_stat_add(part, io_ticks, end ? now - stamp : 1); - } - if (part->bd_partno) { - part = bdev_whole(part); - goto again; - } - } - - The io_ticks field records the elapsed time during which I/O requests - were issued to the device. From this design, one or more I/O requests - may occurs in the same tick, so this number does not reflect the - performance limits of mordern SSD/NVMe. - - atop reads this counter and calculates the percentage, fix the man - page to introduce this. - - Signed-off-by: zhenwei pi - -M man/atop.1 - -commit b9d7533ef536cd07683680786c1bcf9c4e6bd9d4 -Merge: f5da8d3 ed4fd0f -Author: Gerlof Langeveld -Date: Sat May 14 11:04:33 2022 +0200 - - Merge pull request #195 from pizhenwei/move-run_in_guest-into-various - - Move run_in_guest into various.c - -commit f5da8d31e7346a7873fe0748cdf136942c64bce3 -Merge: 98a82fd 591bf96 -Author: Gerlof Langeveld -Date: Sat May 7 12:47:16 2022 +0200 - - Merge branch 'blockdelay' - -commit 591bf964db4da7d66ffd4a2920fcb1dcf5d06436 -Author: Gerlof Langeveld -Date: Sat May 7 12:45:58 2022 +0200 - - Add block I/O delay to processes/threads - M deviate.c +M json.c M man/atop.1 M parseable.c M photoproc.c M photoproc.h +M showgeneric.c M showlinux.c M showlinux.h M showprocs.c -commit ed4fd0feab628fef20e6c08f3722fdb0dfbe3c4f +commit a273887b2defb457e0e5b1c58c5c906683b58921 Author: zhenwei pi -Date: Mon Apr 18 18:36:42 2022 +0800 +Date: Wed Feb 22 11:19:56 2023 +0800 - Move run_in_guest into various.c + ifprop.c: Fix possible memory leak - run_in_guest tries to detect hypervisor, it works as a helper - function. So move this into various.c. + Once 'ioctl(sockfd, SIOCETHTOOL, &ifreq)' fails, the dynamically + allocated memory buffer(ethlink points to) gets orphan. Signed-off-by: zhenwei pi -M atop.h -M photosyst.c -M various.c +M ifprop.c -commit 98a82fdc2258a3bb67ff6dc1dd189b81683837a1 -Merge: b90e41f 9cfeb90 +commit 416e955f7c8e6872dc27512b3084b1528e62163c +Merge: 3cd21d0 99a2581 Author: Gerlof Langeveld -Date: Sat Apr 9 12:28:32 2022 +0200 +Date: Sat Feb 18 16:56:26 2023 +0100 - Merge branch 'pizhenwei-pgintout' + Merge branch 'master' of github.com:Atoptool/atop -commit 9cfeb9096a45c21fd5e5e5791ff2a21e2fbe86d7 +commit 3cd21d05c690f9c0fd871bf3651c7936ff887d85 Author: Gerlof Langeveld -Date: Sat Apr 9 12:28:02 2022 +0200 +Date: Sat Feb 18 16:55:51 2023 +0100 - Minor changes to text, column priority and coloring + Code cleanup and prototype additions -M man/atop.1 -M showlinux.c -M showsys.c - -commit b0d07a04298d5dec969b174e3396f1a93cb6fc86 -Author: zhenwei pi -Date: Sun Mar 20 20:11:22 2022 +0800 - - Support pgin & pgout - - Collect pgint & pgout from /proc/vmstat. This counter is provided by - linux block layer, it represents the total number of memory read from/ - written to all the block devices. - - Signed-off-by: zhenwei pi - -M deviate.c -M man/atop.1 +M Makefile +M acctproc.c +M atop.c +M atop.h +M atopacctd.c +M atopconvert.c +M atopsar.c +M json.c +M netlink.c M parseable.c M photosyst.c M photosyst.h +M procdbase.c +M showgeneric.c +M showgeneric.h M showlinux.c M showlinux.h +M showprocs.c M showsys.c +M various.c +M version.h -commit b90e41f541f122b6521f476200e6b97657add417 -Merge: bfd2537 52676b9 -Author: Gerlof Langeveld -Date: Sat Mar 12 11:37:47 2022 +0100 - - Merge pull request #192 from pizhenwei/fix-compiling-errors - - Fix compiling warnings - -commit bfd2537d8282f79685a742c4b40779c2839d6974 -Merge: a038796 31b632b +commit 99a25812e50cbecdcad71fccec6d4a625b04436e +Merge: ca9d6d9 6180aba Author: Gerlof Langeveld -Date: Sat Mar 12 11:30:38 2022 +0100 +Date: Sat Feb 18 15:04:30 2023 +0100 - Merge pull request #193 from 7h3w1zz/man-typo + Merge pull request #231 from bytedance/fix-atop-rotate - Fix typo in man page + atop-rotate.service: use restart instead of try-restart -commit a038796ec877e098c1ba265f3782386257bf6421 -Merge: 5df2c9a 3bcfce3 +commit ca9d6d9f902ae73c1b9b78ff937900648ebfead1 Author: Gerlof Langeveld -Date: Sat Mar 12 11:24:59 2022 +0100 +Date: Sat Feb 4 12:34:20 2023 +0100 - Merge branch 'bytedance-calibrate-process-nthr' - -commit 3bcfce3e9dd747d628645b04dc39f9d1fac9b708 -Author: Gerlof Langeveld -Date: Sat Mar 12 11:24:34 2022 +0100 - - Correction on calibration (one too many) + Consistency check on number of threads (solves issue #232) M photoproc.c -commit 1876fd3474563b71a62b4f0e672f4b3ebd0d9def -Merge: 5df2c9a bdadf39 -Author: Gerlof Langeveld -Date: Sat Mar 12 10:59:58 2022 +0100 - - Merge branch 'calibrate-process-nthr' of https://github.com/bytedance/atop into bytedance-calibrate-process-nthr - -commit 5df2c9ae74a57312f2d0da245a58d1a0c84704d5 -Merge: 3dfaa7f ced67a5 -Author: Gerlof Langeveld -Date: Sat Mar 12 10:44:58 2022 +0100 - - Merge branch 'integerbeans-fix-vmwballoon-photosyst' - Accepting pull request #189 with modification to stay compatible. - -commit ced67a5ec6f4a258f59e247a87425179b3ff015d -Author: Gerlof Langeveld -Date: Sat Mar 12 10:44:32 2022 +0100 - - Detect vmmemctl at two locations - -M photosyst.c - -commit 52676b93113120a8bd38425b439ccc517bcd406e -Author: zhenwei pi -Date: Mon Mar 7 15:15:13 2022 +0800 - - Use dup2 instead of close+dup - - Build atop on Ubuntu 20.04, gcc 9.3: - showgeneric.c:2843:11: warning: ignoring return value of ‘dup’, declared - with attribute warn_unused_result [-Wunused-result] - 2843 | (void) dup(1); - - Use dup2 instead of close+dup to avoid compiling warning, also use - fileno to avoid hard code: - fd 0 -> fileno(stdin) - fd 1 -> fileno(stdout) - - Signed-off-by: zhenwei pi - -M atopcat.c -M atopsar.c -M showgeneric.c - -commit afa269ba299da4b04fe651a9159d40d7f4bd2f02 -Author: zhenwei pi -Date: Mon Mar 7 14:41:01 2022 +0800 - - Fix compiling warning - - Build atop on Ubuntu 20.04, gcc 9.3: - photosyst.c:79:17: warning: ‘%s’ directive output may be truncated writing - up to 255 bytes into a region of size 231 [-Wformat-truncation=] - 79 | #define NUMADIR "/sys/devices/system/node" - | ^~~~~~~~~~~~~~~~~~~~~~~~~~ - photosyst.c:867:28: note: in expansion of macro ‘NUMADIR’ - 867 | snprintf(fn, sizeof fn, NUMADIR "/%s/meminfo", dentry->d_name); - | ^~~~~~~ - photosyst.c:993:38: note: format string is defined here - 993 | snprintf(fn, sizeof fn, NUMADIR "/node%d/cpumap", j); - - Use larger buffer to avoid compiling warning. - - Signed-off-by: zhenwei pi - -M photosyst.c - -commit bdadf39b7a1062c69f0221250f10d5810402fbd6 +commit 6180aba57e07544c85dc9f8ba5d052e8bc719851 Author: Fei Li -Date: Tue Feb 15 15:00:22 2022 +0800 +Date: Fri Jul 15 20:01:08 2022 +0800 - Calibrate the value of nthr for each process + atop-rotate.service: use restart instead of try-restart + + `man systemctl` says the 'try-restart' pattern: + 'Restart one or more units specified on the command line if the units + are running. This does nothing if units are not running.' - In current code, we firstly get one process's thread number by - reading "Threads:" from /proc/pid/status; then secondly load each - thread's info into devtstat->taskall by traversing each tid under - /proc/pid/task/. Here, information inconsistency occurs if some - processes frequently creates or deletes threads. For example: - $cat /proc/6/status |grep Threads; sleep 0.1; ls /proc/6/task/ | wc -l - Threads: 70 - 71 - - To fix this, calibrate the value of nthr after iterating each - process's threads: re-record the number of threads and assign - to each process's nthr again. + That means atop can not be started successfully by daily + atop-rotate.timer if it is already exited. Fix this by changing + try-restart to restart. Signed-off-by: Fei Li -M photoproc.c - -commit d83d56cd7e0f26b7495901ebc186cd71b75d0c9d -Author: integerbeans -Date: Thu Feb 17 12:01:32 2022 +0100 - - photosyst.c: fixed path for vmmemctl - -M photosyst.c - -commit 31b632b6b9187cfa288796067849dee660afb756 -Author: Jacob <38846015+7h3w1zz@users.noreply.github.com> -Date: Tue Feb 8 14:20:58 2022 -0500 - - Fix typo in man page - -M man/atop.1 +M atop-rotate.service -commit 3dfaa7fd985324bc05f47cc892166ecb0d866d94 +commit 72f361df6ae11d63443cf562fee1bdeb0f6218bd Author: Gerlof Langeveld -Date: Sat Feb 5 12:32:08 2022 +0100 +Date: Sat Jan 7 19:42:31 2023 +0100 - Added link + Add link to atophttpd M README.md -commit d75775438afec328df6087e8fd5b537c9883bd30 -Author: Gerlof Langeveld -Date: Tue Jan 25 17:02:42 2022 +0100 - - Only print current CPU frequency when supported by CPU architecture - -M showsys.c - -commit 09e8812ff705b8a2f4a46f22968c40ead7799781 -Merge: 390fca3 31d4be0 -Author: Gerlof Langeveld -Date: Sun Jan 16 16:42:10 2022 +0100 - - Merge pull request #184 from pizhenwei/llc-per-sec - - Support per-second counter for LLC - -commit 390fca31bc0fc3026f9f351b2a46b93782d908fd -Author: Gerlof Langeveld -Date: Sun Jan 16 16:41:30 2022 +0100 - - Lower priority of column 'numnode' in MEM line - -M showlinux.c - -commit 31d4be081c950e859c7c62524d8812dea782720d -Author: zhenwei pi -Date: Fri Jan 14 15:02:18 2022 +0800 - - Support per-second counter for LLC - - Signed-off-by: zhenwei pi - -M showsys.c - -commit 69e61e071ce82933c2763bb5095caf3563da8080 -Merge: 78b4193 060dd9f -Author: Gerlof Langeveld -Date: Wed Jan 12 17:21:28 2022 +0100 - - Merge branch 'pizhenwei-llc-monitor' - -commit 060dd9fd2552f30319a999e3074b7fa00fb66c66 -Merge: 78b4193 0dfcb19 -Author: Gerlof Langeveld -Date: Wed Jan 12 17:21:09 2022 +0100 - - Fixed conflicts - -commit 78b419310928251b86751330fe30a7e9daef8c43 -Author: Gerlof Langeveld -Date: Wed Jan 12 17:01:35 2022 +0100 - - Reformat status line info in initial screen - -M showgeneric.c - -commit b155a541b93602053521796456ac8e957ff0fbec -Merge: 7cf3f3c eec27ce -Author: Gerlof Langeveld -Date: Wed Jan 12 16:45:49 2022 +0100 - - Merge branch 'pizhenwei-llc-monitor' - -commit eec27cebf4de9631199c50b318973201f0637a0e -Author: Gerlof Langeveld -Date: Wed Jan 12 16:45:16 2022 +0100 - - Cosmetic changes - -M deviate.c -M man/atop.1 -M photosyst.c -M showgeneric.c - -commit 0dfcb1996ac3f19663f6a38c30dc2ad92385db8d -Author: zhenwei pi -Date: Wed Jan 12 15:13:33 2022 +0800 - - Add LLC in atop man page - - Signed-off-by: zhenwei pi - -M man/atop.1 - -commit 48f32410caca06e0de8ea6066100550b683933c7 -Author: zhenwei pi -Date: Wed Dec 29 17:08:26 2021 +0800 - - Support LLC collection - - Since 2017, Linux started to support resctrl which can be used to - control QoS of CPU cache and monitor LLC(last level cache). - - End user can use on an Intel platform: - ~# mount -t resctrl resctrl -o mba_MBps /sys/fs/resctrl - Or on a AMD platform: - ~# mount -t resctrl resctrl -o cdp /sys/fs/resctrl - - Then we can find several directories like: - /sys/fs/resctrl/mon_data/mon_L3_XX - - These counters can be found in doc: - https://github.com/torvalds/linux/blob/master/Documentation/x86/resctrl.rst - - On AMD Rome/Milan, there are several dies in a socket, and each die - uses it's own L3 cache. With this patch, we can distinguish memory - bandwidth of each die to know workload is balanced or not. - - Or course, on a legacy platform, all the CPU cores share a single L3 - cache in a socket, we can know the memory bandwidth and cache usage - of the full socket. - - Test on AMD Milan(Zen3), atop shows: - LLC | tot 211.3G | loc 211.2G | LLC15 100% | - LLC | tot 185.0G | loc 308.1M | LLC00 100% | - LLC | tot 241.5M | loc 207.8M | LLC08 94% | - LLC | tot 130.1M | loc 94.5M | LLC05 20% | - LLC | tot 111.0M | loc 90.5M | LLC13 85% | - LLC | tot 117.1M | loc 83.0M | LLC03 11% | - LLC | tot 96.0M | loc 83.5M | LLC12 75% | - LLC | tot 106.6M | loc 56.1M | LLC01 42% | - LLC | tot 82.7M | loc 71.9M | LLC14 82% | - LLC | tot 80.8M | loc 69.0M | LLC11 82% | - LLC | tot 74.3M | loc 64.7M | LLC09 85% | - LLC | tot 70.8M | loc 59.2M | LLC10 77% | - LLC | tot 65.4M | loc 41.5M | LLC06 15% | - LLC | tot 50.5M | loc 28.1M | LLC07 16% | - LLC | tot 39.2M | loc 25.1M | LLC02 6% | - LLC | tot 38.7M | loc 20.8M | LLC04 4% | - - Signed-off-by: zhenwei pi - -M atop.c -M atop.h -M deviate.c -M parseable.c -M photosyst.c -M photosyst.h -M showgeneric.c -M showgeneric.h -M showlinux.c -M showlinux.h -M showsys.c - -commit 6180f2a8b10ed7dc0a7fe196fe5a70a4a73d48d4 -Merge: 7cf3f3c c4437bc -Author: Gerlof Langeveld -Date: Tue Jan 11 16:03:40 2022 +0100 - - Merge branch 'llc-monitor' of https://github.com/pizhenwei/atop into pizhenwei-llc-monitor - -commit 7cf3f3c6b68f1ec3073569ab1b4bd4365b6757bd -Merge: 1e4451b 57ff34f -Author: Gerlof Langeveld -Date: Tue Jan 11 14:10:48 2022 +0100 - - Merge pull request #183 from thesamesam/openrc-init - - Add OpenRC init scripts (atop, atopacct) - -commit 57ff34f028423f6b2a4bf6fbd0c4a1e98ad87dfc -Author: Sam James -Date: Sun Jan 9 08:00:25 2022 +0000 - - Add OpenRC init scripts (atop, atopacct) - - These have been used for some time in Gentoo but - should work fine on e.g. Alpine too (any distribution - using OpenRC). - - Signed-off-by: Sam James - -A atop.rc.openrc -A atopacct.rc.openrc - -commit 1e4451b66fdfadc9a1913db59a341f4039974398 +commit 5bc3edc64ca01dd46922b34402c67c6f286399aa Author: Gerlof Langeveld -Date: Sat Jan 8 13:07:20 2022 +0100 +Date: Sat Jan 7 14:27:52 2023 +0100 - New version 2.7.1 + Version 2.8.1 M version.h -commit 115b355cb52eee4b11ce00e5b01decde37796e90 -Author: Gerlof Langeveld -Date: Wed Jan 5 19:12:27 2022 +0100 - - Explicit type definition in atop.service (issue #180) - -M atop.service - -commit 9afc5ad3d714ea09f9ffdebd79b345fe223c7e20 -Author: Gerlof Langeveld -Date: Wed Jan 5 18:54:21 2022 +0100 - - Correct disk stats in atopsar (issue #182) - A wrong disk report is shown with the -d/-l/-f flags. - When the kernel supports the discard counter per disk, - output lines are empty in the disk report. - When the kernel doesnot support the discard counter per disk, - output lines often show a negative value for for the average - access time (avserv). - -M atopsar.c - -commit c4437bc58b1c205204b785493f8d306d7bf9e660 -Author: zhenwei pi -Date: Wed Dec 29 17:08:26 2021 +0800 - - Support LLC collection - - Since 2017, Linux started to support resctrl which can be used to - control QoS of CPU cache and monitor LLC(last level cache). - - End user can use on an Intel platform: - ~# mount -t resctrl resctrl -o mba_MBps /sys/fs/resctrl - Or on a AMD platform: - ~# mount -t resctrl resctrl -o cdp /sys/fs/resctrl - - Then we can find several directories like: - /sys/fs/resctrl/mon_data/mon_L3_XX - - These counters can be found in doc: - https://github.com/torvalds/linux/blob/master/Documentation/x86/resctrl.rst - - On AMD Rome/Milan, there are several dies in a socket, and each die - uses it's own L3 cache. With this patch, we can distinguish memory - bandwidth of each die to know workload is balanced or not. - - Or course, on a legacy platform, all the CPU cores share a single L3 - cache in a socket, we can know the memory bandwidth and cache usage - of the full socket. - - Test on AMD Milan(Zen3), atop shows: - LLC | tot 211.3G | loc 211.2G | LLC15 100% | - LLC | tot 185.0G | loc 308.1M | LLC00 100% | - LLC | tot 241.5M | loc 207.8M | LLC08 94% | - LLC | tot 130.1M | loc 94.5M | LLC05 20% | - LLC | tot 111.0M | loc 90.5M | LLC13 85% | - LLC | tot 117.1M | loc 83.0M | LLC03 11% | - LLC | tot 96.0M | loc 83.5M | LLC12 75% | - LLC | tot 106.6M | loc 56.1M | LLC01 42% | - LLC | tot 82.7M | loc 71.9M | LLC14 82% | - LLC | tot 80.8M | loc 69.0M | LLC11 82% | - LLC | tot 74.3M | loc 64.7M | LLC09 85% | - LLC | tot 70.8M | loc 59.2M | LLC10 77% | - LLC | tot 65.4M | loc 41.5M | LLC06 15% | - LLC | tot 50.5M | loc 28.1M | LLC07 16% | - LLC | tot 39.2M | loc 25.1M | LLC02 6% | - LLC | tot 38.7M | loc 20.8M | LLC04 4% | - - Signed-off-by: zhenwei pi - -M atop.c -M atop.h -M deviate.c -M parseable.c -M photosyst.c -M photosyst.h -M showgeneric.c -M showgeneric.h -M showlinux.c -M showlinux.h -M showsys.c - -commit ffb30c62ad5a3e7844d3d9004c174af58eb3dc60 -Author: Gerlof Langeveld -Date: Sat Jan 1 14:37:18 2022 +0100 - - Add information about service activation to README file - -M README - -commit fdf3526bd35c1a84dd11bb73110c1a1f4148e39d +commit a2c45992f59ce6110b24b22fc9bf65028197e96d Author: Gerlof Langeveld -Date: Fri Dec 31 11:25:13 2021 +0100 +Date: Sat Jan 7 12:21:03 2023 +0100 - Add directory to .gitignore + Solve compiler warnings about format-truncation -M .gitignore +M various.c -commit 5dbe750eca1e468694dc4d4d0d251a485f58ad74 +commit b93546d1ed03ec5b6e0c747a2571820129d60771 Author: Gerlof Langeveld -Date: Fri Dec 31 11:25:04 2021 +0100 +Date: Sat Jan 7 12:02:37 2023 +0100 - Clarify relation between atop/atopacctd in man page + Avoid buffer overflows during value formatting -M man/atop.1 +M various.c -commit 1b4f7d6d2e14e768f310fc6041c05c5dcc69cee7 +commit 490c73ce516bff6dd53786e2be29bbcbc4185071 Author: Gerlof Langeveld -Date: Fri Dec 31 11:24:00 2021 +0100 +Date: Sat Jan 7 12:00:36 2023 +0100 - Added license info + Correct NUMA conversion in logfiles from version 2.7 to 2.8 -M atopgpud -M netlink.c +M atopconvert.c -commit a67368badc8b639f23268e636a1a3d8787ee90c5 +commit ed17722fa50f3a0be4d1d4a86336180a38a69109 Author: Gerlof Langeveld -Date: Fri Dec 31 11:23:18 2021 +0100 +Date: Sat Jan 7 11:16:42 2023 +0100 - Added generic license info to README #179 + Added contributor -M README +M AUTHORS diff -Nru atop-2.8.1/debian/changelog atop-2.9.0/debian/changelog --- atop-2.8.1/debian/changelog 2023-01-23 13:45:02.000000000 +0000 +++ atop-2.9.0/debian/changelog 2023-10-05 02:25:12.000000000 +0000 @@ -1,3 +1,17 @@ +atop (2.9.0-1ubuntu1) mantic; urgency=medium + + * d/p/atopacctd_return_error.patch: apply upstream patch to fix SIGFPE in + acctprocnt() (LP: #1725896, LP: #2037910). + + -- Vladimir Petko Thu, 05 Oct 2023 15:25:12 +1300 + +atop (2.9.0-1) unstable; urgency=medium + + * new upstream version 2.9.0 + * disable mkdate invocation in Makefile + + -- Marc Haber Sat, 01 Jul 2023 16:37:19 +0200 + atop (2.8.1-1) unstable; urgency=medium * new upstream version 2.8.1 diff -Nru atop-2.8.1/debian/control atop-2.9.0/debian/control --- atop-2.8.1/debian/control 2023-01-23 13:45:02.000000000 +0000 +++ atop-2.9.0/debian/control 2023-10-05 02:25:12.000000000 +0000 @@ -1,7 +1,8 @@ Source: atop Section: admin Priority: optional -Maintainer: Marc Haber +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Marc Haber Uploaders: Marc Haber Build-Depends: debhelper-compat (= 13), zlib1g-dev, libncurses-dev Standards-Version: 4.6.2 diff -Nru atop-2.8.1/debian/patches/atopacctd_return_error.patch atop-2.9.0/debian/patches/atopacctd_return_error.patch --- atop-2.8.1/debian/patches/atopacctd_return_error.patch 1970-01-01 00:00:00.000000000 +0000 +++ atop-2.9.0/debian/patches/atopacctd_return_error.patch 2023-10-05 02:25:12.000000000 +0000 @@ -0,0 +1,31 @@ +Description: Avoid floating point exception when atopacctd fails + When the atopacctd service crashes, it may leave a 0-length shadow file. + atopacctd() routine tries to read it and fails. It returns 1 (success) + and sets maxshadowrec size to the size from the 'current' file. The rest + of the code assumes that the shadow file read was successful and tries + to use an empty acct structure, causing a division by zero. +Author: Gerlof Langeveld +Bug: https://github.com/Atoptool/atop/issues/277 +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/atop/+bug/2037910 +Applied-Upstream: https://github.com/Atoptool/atop/commit/f72f7c06278ec9ad2209975eca67c2e3c0b3a44b +Last-Update: 2023-10-08 +--- a/acctproc.c ++++ b/acctproc.c +@@ -430,7 +430,6 @@ atopacctd(int swon) + { + if ( swon && !acctvers(acctfd) ) + { +- + int maxcnt = 40; + + if ( fork() == 0 ) +@@ -453,7 +452,8 @@ atopacctd(int swon) + &semunlock, 1); + + regainrootprivs(); +- return 1; ++ maxshadowrec = 0; ++ return -1; // try other + } + } + diff -Nru atop-2.8.1/debian/patches/atop-pm atop-2.9.0/debian/patches/atop-pm --- atop-2.8.1/debian/patches/atop-pm 2023-01-23 13:45:02.000000000 +0000 +++ atop-2.9.0/debian/patches/atop-pm 2023-10-05 02:25:12.000000000 +0000 @@ -11,7 +11,7 @@ -PMPATHD = /usr/lib/systemd/system-sleep +PMPATHD = /lib/systemd/system-sleep - CFLAGS += -O2 -I. -Wall -Wno-stringop-truncation # -DNOPERFEVENT # -DHTTPSTATS + CFLAGS += -O2 -I. -Wall -Wno-stringop-truncation -Wmissing-prototypes -Wmissing-declarations # -DNOPERFEVENT # -DHTTPSTATS OBJMOD0 = version.o @@ -66,8 +66,8 @@ install: genericinstall chmod 0644 $(DESTDIR)$(SYSDPATH)/atop-rotate.service diff -Nru atop-2.8.1/debian/patches/atop-rotate-systemctl-path atop-2.9.0/debian/patches/atop-rotate-systemctl-path --- atop-2.8.1/debian/patches/atop-rotate-systemctl-path 2023-01-23 13:45:02.000000000 +0000 +++ atop-2.9.0/debian/patches/atop-rotate-systemctl-path 2023-10-05 02:25:12.000000000 +0000 @@ -8,5 +8,5 @@ [Service] Type=oneshot --ExecStart=/usr/bin/systemctl try-restart atop.service -+ExecStart=/bin/systemctl try-restart atop.service +-ExecStart=/usr/bin/systemctl restart atop.service ++ExecStart=/bin/systemctl restart atop.service diff -Nru atop-2.8.1/debian/patches/disable-mkdate atop-2.9.0/debian/patches/disable-mkdate --- atop-2.8.1/debian/patches/disable-mkdate 1970-01-01 00:00:00.000000000 +0000 +++ atop-2.9.0/debian/patches/disable-mkdate 2023-10-05 02:25:12.000000000 +0000 @@ -0,0 +1,24 @@ +Description: disable mkdate, keep versdate.h at original + this is supposed to help with reproducibility +Author: Marc Haber +Forwarded: not-needed +--- a/Makefile ++++ b/Makefile +@@ -48,7 +48,7 @@ atopcat: atopcat.o + $(CC) atopcat.o -o atopcat $(LDFLAGS) + + clean: +- rm -f *.o atop atopsar atopacctd atopconvert atopcat versdate.h ++ rm -f *.o atop atopsar atopacctd atopconvert atopcat + + distr: + rm -f *.o atop +@@ -179,7 +179,7 @@ genericinstall: atop atopacctd atopconve + ########################################################################## + + versdate.h: +- ./mkdate ++ #./mkdate + + atop.o: atop.h photoproc.h photosyst.h acctproc.h showgeneric.h + atopsar.o: atop.h photoproc.h photosyst.h diff -Nru atop-2.8.1/debian/patches/format-security-error atop-2.9.0/debian/patches/format-security-error --- atop-2.8.1/debian/patches/format-security-error 1970-01-01 00:00:00.000000000 +0000 +++ atop-2.9.0/debian/patches/format-security-error 2023-10-05 02:25:12.000000000 +0000 @@ -0,0 +1,32 @@ +Subject: fix format-security-errors +Origin: https://github.com/Atoptool/atop/commit/13a4178d1e00d429e56d2ff3334162933c320b9f +Forwarded: not-needed +--- a/drawbar.c ++++ b/drawbar.c +@@ -2055,7 +2055,7 @@ drawevent(struct perwindow *w, int line, + + line -= 1; + wattron(w->win, A_BOLD); +- mvwprintw(w->win, line, column, text); ++ mvwprintw(w->win, line, column, "%s", text); + wattroff(w->win, A_BOLD); + + colorswoff(w->win, color); +@@ -2105,7 +2105,7 @@ headergetch(time_t curtime, int nsecs, c + { + colorswon(headwin, statuscol); + wattron(headwin, A_REVERSE); +- mvwprintw(headwin, 0, statcol, statusmsg); ++ mvwprintw(headwin, 0, statcol, "%s", statusmsg); + wattroff(headwin, A_REVERSE); + colorswoff(headwin, statuscol); + } +@@ -2328,7 +2328,7 @@ getwininput(char *prompt, char *answer, + + // show the prompt + // +- mvwprintw(mywin, 1, 1, prompt); ++ mvwprintw(mywin, 1, 1, "%s", prompt); + + // prepare reading input + // diff -Nru atop-2.8.1/debian/patches/series atop-2.9.0/debian/patches/series --- atop-2.8.1/debian/patches/series 2023-01-23 13:45:02.000000000 +0000 +++ atop-2.9.0/debian/patches/series 2023-10-05 02:25:12.000000000 +0000 @@ -1,3 +1,5 @@ +disable-mkdate +format-security-error atop-rotate-systemctl-path dh_systemd_enable dh_installinit @@ -13,3 +15,4 @@ no-atopgpud handle-default-file default +atopacctd_return_error.patch diff -Nru atop-2.8.1/debian/patches/var-run atop-2.9.0/debian/patches/var-run --- atop-2.8.1/debian/patches/var-run 2023-01-23 13:45:02.000000000 +0000 +++ atop-2.9.0/debian/patches/var-run 2023-10-05 02:25:12.000000000 +0000 @@ -102,7 +102,7 @@ ** Below this top-directory the source file pacct_source is created and --- a/atopacctd.h +++ b/atopacctd.h -@@ -35,7 +35,7 @@ +@@ -38,7 +38,7 @@ /* ** name of the PID file */ @@ -111,7 +111,7 @@ /* ** directory containing the source accounting file and -@@ -43,7 +43,7 @@ +@@ -46,7 +46,7 @@ ** this directory can be overruled by a command line parameter (atopacctd) ** or by a keyword in the /etc/atoprc file (atop) */ @@ -122,7 +122,7 @@ ** accounting file (source file to which kernel writes records) --- a/man/atop.1 +++ b/man/atop.1 -@@ -2628,7 +2628,7 @@ output about the CPU utilization: +@@ -2825,7 +2825,7 @@ processes sorted on memory consumption: .SH FILES .PP .TP 5 @@ -131,7 +131,7 @@ Directory containing the process accounting shadow files that are used by .I atop -@@ -2687,7 +2687,7 @@ All binary system and process level data +@@ -2888,7 +2888,7 @@ All binary system and process level data in compressed format. .PP .TP 5 @@ -174,7 +174,7 @@ sequence number). --- a/man/atoprc.5 +++ b/man/atoprc.5 -@@ -211,7 +211,7 @@ daemon. In this directory, the daemon cr +@@ -231,7 +231,7 @@ daemon. In this directory, the daemon cr .B pacct_shadow.d in which files will be written containing the process accounting records. The default topdirectory is @@ -185,7 +185,7 @@ daemon is started with an alternative topdirectory as command line argument. --- a/netatopd.h +++ b/netatopd.h -@@ -28,7 +28,7 @@ +@@ -31,7 +31,7 @@ #define SEMAKEY 1541961 diff -Nru atop-2.8.1/debian/source/lintian-overrides atop-2.9.0/debian/source/lintian-overrides --- atop-2.8.1/debian/source/lintian-overrides 2023-01-23 13:45:02.000000000 +0000 +++ atop-2.9.0/debian/source/lintian-overrides 2023-10-05 02:25:12.000000000 +0000 @@ -7,4 +7,5 @@ atop source: patch-not-forwarded-upstream [debian/patches/lsb-init-functions] atop source: patch-not-forwarded-upstream [debian/patches/no-atopgpud] atop source: patch-not-forwarded-upstream [debian/patches/no-files-in-var-log] - +# I know, I have no idea what to test in an interactive tool +atop source: superficial-tests [debian/tests/control] diff -Nru atop-2.8.1/debian/tests/control atop-2.9.0/debian/tests/control --- atop-2.8.1/debian/tests/control 2023-01-23 13:45:02.000000000 +0000 +++ atop-2.9.0/debian/tests/control 2023-10-05 02:25:12.000000000 +0000 @@ -1,2 +1,3 @@ Tests: 01-numcpus +Restrictions: superficial diff -Nru atop-2.8.1/deviate.c atop-2.9.0/deviate.c --- atop-2.8.1/deviate.c 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/deviate.c 2023-05-13 08:20:27.000000000 +0000 @@ -529,6 +529,18 @@ devstat->cpu.blkdelay = subcount(curstat->cpu.blkdelay, prestat->cpu.blkdelay); + if (curstat->cpu.nvcsw >= prestat->cpu.nvcsw) + devstat->cpu.nvcsw = + subcount(curstat->cpu.nvcsw, prestat->cpu.nvcsw); + else + devstat->cpu.nvcsw = curstat->cpu.nvcsw; + + if (curstat->cpu.nivcsw >= prestat->cpu.nivcsw) + devstat->cpu.nivcsw = + subcount(curstat->cpu.nivcsw, prestat->cpu.nivcsw); + else + devstat->cpu.nivcsw = curstat->cpu.nivcsw; + devstat->dsk.rio = subcount(curstat->dsk.rio, prestat->dsk.rio); devstat->dsk.rsz = @@ -1053,7 +1065,7 @@ /* ** determine new j */ - if (pre->dsk.dsk[j].name) // existing matching entry + if (pre->dsk.dsk[j].name[0]) // existing matching entry j++; else j = realj; // empty entry: stick to old j @@ -1122,7 +1134,7 @@ /* ** determine new j */ - if (pre->dsk.mdd[j].name) // existing matching entry + if (pre->dsk.mdd[j].name[0]) // existing matching entry j++; else j = realj; // empty entry: stick to old j @@ -1191,7 +1203,7 @@ /* ** determine new j */ - if (pre->dsk.lvm[j].name) // existing matching entry + if (pre->dsk.lvm[j].name[0]) // existing matching entry j++; else j = realj; // empty entry: stick to old j diff -Nru atop-2.8.1/drawbar.c atop-2.9.0/drawbar.c --- atop-2.8.1/drawbar.c 1970-01-01 00:00:00.000000000 +0000 +++ atop-2.9.0/drawbar.c 2023-05-13 08:20:27.000000000 +0000 @@ -0,0 +1,2653 @@ +/* +** ATOP - System & Process Monitor +** +** The program 'atop' offers the possibility to view the activity of +** the system on system-level as well as process-level. +** +** This source-file contains function for bar graph representation of +** system-level statistics about processors, memory, disks and network +** interfaces. +** ========================================================================== +** Author: Gerlof Langeveld +** E-mail: gerlof.langeveld@atoptool.nl +** Date: March/April 2023 (initial) +** -------------------------------------------------------------------------- +** Copyright (C) 2023 Gerlof Langeveld +** +** This program is free software; you can redistribute it and/or modify it +** under the terms of the GNU General Public License as published by the +** Free Software Foundation; either version 2, or (at your option) any +** later version. +** +** This program is distributed in the hope that it will be useful, but +** WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +** -------------------------------------------------------------------------- +*/ + +///////////////////////////////////////////////////////////////////////////// +// Screen layout in bar graph mode will be based on one of these two models: +// +// ============ +// Memory model +// ============ +// This model is preferred when the number of disks and network interfaces +// is limited, because it shows more memory details. +// +// +---------------------------------------------------+ +// | ATOP - host
... elapsed | +// | | +// | | | +// | Processor bar graph | | +// | | | +// | | | +// | | | +// |---------------------------------| Memory graph | +// | | | | +// | | | | +// | Disk graph | Interface graph | | +// | | | | +// | | | | +// +---------------------------------------------------+ +// +// OR +// +// ============ +// I/O model +// ============ +// When many disks and/or network interfaces are present, more space +// is needed for these windows in the lower half of the screen. So the +// memory window only uses the upper half of the screen. +// +// +---------------------------------------------------+ +// | ATOP - host
... elapsed | +// | | +// | | | +// | | | +// | Processor bar graph | Memory graph | +// | | | +// | | | +// |---------------------------------------------------| +// | | | +// | | | +// | Disk bar graph | Interface bar graph | +// | | | +// | | | +// +---------------------------------------------------+ +// +// For every bar graph (processor, memory, disk and interface) a +// separate window is created. Apart from these four windows, +// other windows are created: +// +// 1. A window for the header line (always). +// +// 2. A window for the horizontal ruler line in between the upper +// and lower half of the screen (always). +// +// 3. A window for the vertical ruler between the disk and interface +// window in the lower half (always). +// +// 4. A window for the vertical ruler between the processor and memory +// window in the upper half (in case of I/O model) or a screen-size +// vertical ruler (in case of memory model). +// +// The choice between the memory model and I/O model is dynamically made +// based on the number of columns in the screen (terminal window) and the +// number of disks/interfaces to be presented. When the terminal window is +// horizontally scaled by the user, atop might switch from one model to +// the other. +///////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include + +#include "atop.h" +#include "showgeneric.h" +#include "photosyst.h" + +extern char usecolors; + + +// maximum X axis label length +// +#define MAXLABLEN 7 + +// number of columns in memory management bars +// +#define MEMORYBARSZ 11 +#define SWAPBARSZ 8 +#define EVENTBARSZ 10 + + +// four windows are created to show graphs +// +// - processor stats (left upper) +// - memory stats (right upper or right full) +// - disk stats (left lower) +// - interface stats (right lower) +// +// metadata for each of these windows: struct perwindow +// +struct perwindow { + WINDOW *win; + int nlines, ncols; +}; + +static struct perwindow wincpu, winmem, windsk, winnet; + +// additional windows for the header line and for line drawing +// +static WINDOW *headwin, *midline, *colupper, *collower; + +// struct for calling drawvertbars() +// +#define MAXCAT 5 // maximum number of categories within one bar +#define MAXHEIGHT 25 // maximum bar height in lines + +struct vertval { + int barval; // total value of bar + char *barlab; // bar label + char basecolor; // bar color or fill color + + char barmap[MAXHEIGHT]; // color map + char barchr[MAXHEIGHT]; // character map + + int numcat; // number of categories in bar + + struct { + int cval; // per-category value + int ccol; // per-category color + char clab; // per-category label + } category[MAXCAT]; +}; + + +// struct for calling drawnetbars() +// +struct netval { + count_t pvals; // send bytes-per-second + count_t pvalr; // recv bytes-per-second + int speed; // speed in Mbits/sec + int maxmbits; // bar scale + char *barlab; // bar label +}; + + +// header message +// +static char *headmsg = "Press '?' for help"; + + +// function prototypes +// +static int headergetch(time_t, int, char *, int); +static int wininit(struct sstat *); +static void winexit(void); +static void showhelp(void); +static int getwininput(char *, char *, int, char); +static void colorswon(WINDOW *, int); +static void colorswoff(WINDOW *, int); +static int severitycolor(char); +static char setseverity(long, long, long); +static float getwinratio(struct sstat *, char *); + +static void do_cpubars(struct sstat *, int, char, char); +static void do_dskbars(struct sstat *, int, char, char); +static void do_netbars(struct sstat *, int, char, char); + +static void sortvertbars(int, int, struct vertval **); +static int compvertval(const void *, const void *); + +static void sortnetbars(int, struct netval **); +static int compnetval(const void *, const void *); + +static void fillbarmaps(int, struct vertval *, float, int); + +static int drawvertbars(struct perwindow *, float, float, + int, int, struct vertval *, int, char *,char *, int); + +static int drawnetbars(struct perwindow *, int, struct netval *, + int, char *,char *); + +static int drawmemory(struct perwindow *w, struct sstat *, int, time_t, char); + +static int drawmemlines(struct perwindow *, int, int, int, int, + int, char *, char *); + +static int drawevent(struct perwindow *, int, int, int, + char *, char *, long); + + +///////////////////////////////////////////////////// +// entry point to display the deviation counters +// on system level in bar graph mode +///////////////////////////////////////////////////// +char +draw_samp(time_t curtime, int nsecs, struct sstat *sstat, + char flag, char sorted) +{ + static char winitialized, wassorted, initlabels, + swapinuse, ttyrescaled; + static time_t lasttime; + static int nrdisk, nrallintf, nrintf; + + int lastchar, i, newinterval, statuscol; + char *statusmsg = NULL, buf[32], lower=0, answer[16]; + + // when needed (re)initialize the windows for bar graphs + // + if (!winitialized || nrdisk != sstat->dsk.ndsk || + nrallintf != sstat->intf.nrintf ) + { + // determine the number of disks and network interfaces + // only the physical disks and network interfaces apply + // + nrdisk = sstat->dsk.ndsk; + nrallintf = sstat->intf.nrintf; + + for (i=0, nrintf=0; i < sstat->intf.nrintf; i++) + { + if (sstat->intf.intf[i].type != 'v') + nrintf++; + } + + // initialize graph windows + // + swapinuse = sstat->mem.totswap ? 1 : 0; + + if (winitialized) // already initialized -> first remove + winexit(); + + wininit(sstat); + + winitialized = 1; + } + + // verify if situation related to swap usage has been + // changed (in that case the memory window has + // to be redefined) + // + if (( sstat->mem.totswap && !swapinuse) || + (!sstat->mem.totswap && swapinuse) ) + { + swapinuse = sstat->mem.totswap ? 1 : 0; + winexit(); + wininit(sstat); + } + + // main loop: + // - draw bar graphs + // - wait for keystroke or alarm expiration + // + while (1) + { + initlabels = sorted != wassorted; + + if (!initlabels && lasttime != curtime && sorted) + initlabels = 1; + + // show processor graph + // + do_cpubars(sstat, nsecs, initlabels, barmono); + + // show disk graph + // + do_dskbars(sstat, nsecs, initlabels, barmono); + + // show network (interfaces) graph + // + do_netbars(sstat, nsecs, initlabels, lower); + + // show memory graph + // + drawmemory(&winmem, sstat, nsecs, curtime, flag); + + // reset label initialization + // + initlabels = 0; + wassorted = sorted; + + // verify if status message is required + // + statusmsg = NULL; + statuscol = FGCOLORBORDER; + + if (flag&RRBOOT) + statusmsg = "SINCE BOOT"; + + if (paused) // might overrule other message + statusmsg = "PAUSED"; + + if (ttyrescaled) + { + snprintf(buf, sizeof buf, " %dx%d ", LINES, COLS); + statusmsg = buf; + + ttyrescaled = 0; + + // show critical color when getting close to minimum + // screen width + // + if (COLS < MINCOLUMNS+5 || LINES < MINLINES+5) + statuscol = FGCOLORCRIT; + } + + // wait for keystroke or alarm expiration + // + switch (lastchar = headergetch(curtime, nsecs, statusmsg, statuscol)) + { + case ERR: // alarm expired? + case 0: + return lastchar; + + case MPROCGEN: + case MPROCMEM: + case MPROCDSK: + case MPROCNET: + case MPROCGPU: + case MPROCSCH: + case MPROCVAR: + case MPROCARG: + + case MBARGRAPH: + winexit(); // close windows + winitialized = 0; + + return lastchar; // switch to text mode + + case KEY_RESIZE: // terminal window resize? + winexit(); + + // when window gets too small for bar graph mode, + // switch to text mode + // + if (COLS < MINCOLUMNS || LINES < MINLINES) + { + winitialized = 0; + return MBARGRAPH; + } + + // terminal window size still fine: + // reinitialize all ncurses windows + // + wininit(sstat); + ttyrescaled = 1; + break; // redraw with current values + + case MSAMPNEXT: // manual trigger for next sample? + if (paused) + break; + + getalarm(0); + return lastchar; + + case MSAMPPREV: // manual trigger for previous sample? + if (!rawreadflag) + { + beep(); + break; + } + + if (paused) + break; + + getalarm(0); + return lastchar; + + case MRESET: // reset to begin? + getalarm(0); + paused = 0; + return lastchar; + + case MSAMPBRANCH: // branch to other time? + // only possible when viewing raw file + // + if (!rawreadflag) + { + beep(); + break; + } + + if (getwininput("Enter new time (format [YYYYMMDD]hhmm): ", + answer, sizeof answer, 1) >= 0) + { + begintime = cursortime; + + if ( !getbranchtime(answer, &begintime) ) + { + beep(); + begintime = 0; + break; // branch failed + } + + return lastchar; + } + + break; + + case MBARLOWER: // reset network scale? + lower = 1; + break; + + case MBARMONO: // categorized busy bars? + if (barmono) + barmono = 0; + else + barmono = 1; + break; + + case MPAUSE: // pause key (toggle)? + if (paused) + { + paused=0; + + if (!rawreadflag) + alarm(1); + } + else + { + paused=1; + alarm(0); // stop the clock + } + break; + + case MINTERVAL: // modify interval? + // not possible when viewing raw file + // + if (rawreadflag) + { + beep(); + break; + } + + alarm(0); // stop the clock + + if ( (newinterval = getwininput("Interval: ", answer, + sizeof answer, 1)) >= 0) + interval = newinterval; + + if (!paused) + alarm(1); // set short timer + + break; + + case MQUIT: // quit entirely? + winexit(); + move(LINES-1, 0); + clrtoeol(); + refresh(); + cleanstop(0); + + case MHELP1: // help wanted? + case MHELP2: + alarm(0); // stop the clock + + // show help lines + // + showhelp(); + + // reinitialize original windows + // + winexit(); + wininit(sstat); + + if (interval && !paused && !rawreadflag) + alarm(1); // force new sample + + break; + + default: // any other key pressed? + break; // ignore + } + } +} + +///////////////////////////////////////////////////// +// prepare the CPU specific bar graph +///////////////////////////////////////////////////// +static void +do_cpubars(struct sstat *sstat, int nsecs, char initlabels, char mono) +{ + static int labellen, numcpus, numlabs; + static char *labarea, *p; + static struct vertval *vertvals; + + count_t alltics; + int i; + char buf[16]; + + // check if the number of CPUs has been changed since + // previous sample and create X axis labels for all + // CPUs + // + if (numcpus != sstat->cpu.nrcpu || initlabels) + { + // remove old label space + // + if (vertvals) + { + free(vertvals); + free(labarea); + } + + // create new label space + // - for one CPU, one label is enough ('Avg') + // - for more than one CPU, one label is added ('Avg') + // + numcpus = sstat->cpu.nrcpu; + + numlabs = numcpus > 1 ? numcpus + 1 : 1; + + labellen = snprintf(buf, sizeof buf, "%d", numcpus); + + vertvals = malloc(numlabs * sizeof(struct vertval)); + ptrverify(vertvals, "Malloc failed for %ld vertval structs failed\n", numlabs); + + labarea = malloc(numlabs * (labellen+1)); + ptrverify(labarea, "Malloc failed for %ld CPU labels failed\n", numlabs); + + // create new X axis labels + // + if (numcpus == 1) + vertvals->barlab = "0"; + else + { + vertvals->barlab = "Avg "; + + for (i=0, p=labarea; i < numcpus; i++) + { + (vertvals+i+1)->barlab = p; + snprintf(p, labellen+1, "%-*d", labellen, + sstat->cpu.cpu[i].cpunr); + p += labellen+1; + } + } + } + + // calculate overall busy percentage and + // fill first busy value (average) + // + alltics = sstat->cpu.all.stime + + sstat->cpu.all.utime + + sstat->cpu.all.ntime + + sstat->cpu.all.itime + + sstat->cpu.all.wtime + + sstat->cpu.all.Itime + + sstat->cpu.all.Stime + + sstat->cpu.all.steal; + + vertvals->barval = 100 - (sstat->cpu.all.itime + sstat->cpu.all.wtime) + * 100 / alltics; + vertvals->basecolor = WHITE_BLUE0; + + if (!mono) + { + vertvals->category[0].ccol = COLORCPUSYS; + vertvals->category[0].clab = 'S'; + vertvals->category[0].cval = sstat->cpu.all.stime * 100 / + alltics; + + vertvals->category[1].ccol = COLORCPUUSR; + vertvals->category[1].clab = 'U'; + vertvals->category[1].cval = + (sstat->cpu.all.utime + + sstat->cpu.all.ntime - + sstat->cpu.all.guest) * 100 / alltics; + + vertvals->category[2].ccol = COLORCPUIDLE; + vertvals->category[2].clab = 'I'; + vertvals->category[2].cval = + (sstat->cpu.all.Stime + sstat->cpu.all.Itime) * 100 / + alltics; + + vertvals->category[3].ccol = COLORCPUSTEAL; + vertvals->category[3].clab = 's'; + vertvals->category[3].cval = + sstat->cpu.all.steal * 100 / alltics; + + vertvals->category[4].ccol = COLORCPUGUEST; + vertvals->category[4].clab = 'G'; + vertvals->category[4].cval = + sstat->cpu.all.guest * 100 / alltics; + + vertvals->numcat = 5; + } + else + { + vertvals->numcat = 0; + } + + // if more than one CPU: calculate per CPU + // + if (numcpus > 1) + { + // total ticks during last interval for CPU 0 + // + alltics = sstat->cpu.cpu[0].stime + + sstat->cpu.cpu[0].utime + + sstat->cpu.cpu[0].ntime + + sstat->cpu.cpu[0].itime + + sstat->cpu.cpu[0].wtime + + sstat->cpu.cpu[0].Itime + + sstat->cpu.cpu[0].Stime + + sstat->cpu.cpu[0].steal; + + // busy percentage per CPU + // + for (i=0; i < numcpus; i++) + { + (vertvals+i+1)->barval = + 100 - (sstat->cpu.cpu[i].itime + + sstat->cpu.cpu[i].wtime ) *100/alltics; + + if ((vertvals+i+1)->barval < 0) + (vertvals+i+1)->barval = 0; + + (vertvals+i+1)->basecolor = WHITE_BLUE0; + + if (!mono) + { + (vertvals+i+1)->category[0].ccol = COLORCPUSYS; + (vertvals+i+1)->category[0].clab = 'S'; + (vertvals+i+1)->category[0].cval = + sstat->cpu.cpu[i].stime * 100 / + alltics; + + (vertvals+i+1)->category[1].ccol = COLORCPUUSR; + (vertvals+i+1)->category[1].clab = 'U'; + (vertvals+i+1)->category[1].cval = + (sstat->cpu.cpu[i].utime + + sstat->cpu.cpu[i].ntime - + sstat->cpu.cpu[i].guest) *100/alltics; + + (vertvals+i+1)->category[2].ccol = COLORCPUIDLE; + (vertvals+i+1)->category[2].clab = 'I'; + (vertvals+i+1)->category[2].cval = + (sstat->cpu.cpu[i].Stime + + sstat->cpu.cpu[i].Itime) *100/alltics; + + (vertvals+i+1)->category[3].ccol = COLORCPUSTEAL; + (vertvals+i+1)->category[3].clab = 's'; + (vertvals+i+1)->category[3].cval = + sstat->cpu.cpu[i].steal *100/alltics; + + (vertvals+i+1)->category[4].ccol = COLORCPUGUEST; + (vertvals+i+1)->category[4].clab = 'G'; + (vertvals+i+1)->category[4].cval = + sstat->cpu.cpu[i].guest *100/alltics; + + (vertvals+i+1)->numcat = 5; + } + else + { + (vertvals+i+1)->numcat = 0; + } + } + } + + // draw bar graph showing busy percentages of CPUs + // + drawvertbars(&wincpu, 100.0, cpubadness, + numlabs, numcpus == 1 ? 0 : 1, vertvals, + labellen, "Busy%", "Processors", 0); +} + + +///////////////////////////////////////////////////// +// prepare the disk specific bar graph +///////////////////////////////////////////////////// +static void +do_dskbars(struct sstat *sstat, int nsecs, char initlabels, char mono) +{ + static int labellen, numdisks; + static char *labarea, *p; + static struct vertval *vertvals; + + count_t mstot; + int i, namlen; + + // check if the number of disks has been changed since + // previous sample and create X axis labels for all disks + // + if (numdisks != sstat->dsk.ndsk || initlabels) + { + // remove old label space + // + if (vertvals) + { + free(vertvals); + free(labarea); + } + + // create new label space + // + numdisks = sstat->dsk.ndsk; + + vertvals = malloc(numdisks * sizeof(struct vertval)); + ptrverify(vertvals, "Malloc failed for %ld vertval structs failed\n", numdisks); + + labarea = malloc(numdisks * (MAXLABLEN+1)); + ptrverify(labarea, "Malloc failed for %ld disk labels failed\n", numdisks); + + // create new X axis labels + // + for (i=0, labellen=0, p=labarea; i < numdisks; i++) + { + (vertvals+i)->barlab = p; + + namlen = strlen(sstat->dsk.dsk[i].name); + + if (labellen < namlen) + labellen = namlen; + + if (namlen > MAXLABLEN) + snprintf(p, MAXLABLEN+1, "%-*s", MAXLABLEN, + sstat->dsk.dsk[i].name+namlen-MAXLABLEN); + else + snprintf(p, MAXLABLEN+1, "%-*s", MAXLABLEN, + sstat->dsk.dsk[i].name); + + p += MAXLABLEN+1; + } + + if (labellen > MAXLABLEN) + labellen = MAXLABLEN; + } + + // calculate total number of milliseconds in the interval + // + mstot = (sstat->cpu.all.stime + sstat->cpu.all.utime + + sstat->cpu.all.ntime + sstat->cpu.all.itime + + sstat->cpu.all.wtime + sstat->cpu.all.Itime + + sstat->cpu.all.Stime + sstat->cpu.all.steal ) + * (count_t)1000 / hertz / sstat->cpu.nrcpu; + + if (!mstot) // avoid division by zero + mstot = 1; + + // per disk: fill total busy percentage and fill two + // sidebars for the ratio between reads and writes + // + for (i=0; i < numdisks; i++) + { + count_t totsect = sstat->dsk.dsk[i].nrsect + + sstat->dsk.dsk[i].nwsect; + int perc = sstat->dsk.dsk[i].io_ms *100/mstot; + + (vertvals+i)->barval = perc; // total disk busy% + (vertvals+i)->basecolor = WHITE_GREEN0; + + if (!mono) + { + if (!totsect) + totsect = 1; // avoid division by zero + + (vertvals+i)->category[0].cval = (sstat->dsk.dsk[i].nrsect * perc + totsect/2) / totsect; + (vertvals+i)->category[0].ccol = COLORDSKREAD; + (vertvals+i)->category[0].clab = 'R'; + + (vertvals+i)->category[1].cval = perc - (vertvals+i)->category[0].cval; + (vertvals+i)->category[1].ccol = COLORDSKWRITE; + (vertvals+i)->category[1].clab = 'W'; + + (vertvals+i)->numcat = 2; + } + else + { + (vertvals+i)->numcat = 0; + } + } + + drawvertbars(&windsk, 100.0, dskbadness, + numdisks, 0, vertvals, labellen, "Busy%", "Disks", 3); +} + +///////////////////////////////////////////////////// +// return the ratio between network interfaces +// and disks, and determine the window model +///////////////////////////////////////////////////// +static float +getwinratio(struct sstat *sstat, char *winmodel) +{ + int disklabellen, intflabellen, i, namlen, nrintf, nrdisk; + int dskcols, intcols, memcols; + float dsk2netratio; + + // determine disk label length + // + for (i=0, disklabellen=0, nrdisk=sstat->dsk.ndsk; i < nrdisk; i++) + { + namlen = strlen(sstat->dsk.dsk[i].name); + + if (disklabellen < namlen) + disklabellen = namlen; + } + + if (disklabellen > MAXLABLEN) + disklabellen = MAXLABLEN; + + // determine interface label length + // + for (i=0, intflabellen=0, nrintf=0; i < sstat->intf.nrintf; i++) + { + if (sstat->intf.intf[i].type != 'v') + { + nrintf++; + + namlen = strlen(sstat->intf.intf[i].name); + + if (intflabellen < namlen) + intflabellen = namlen; + } + } + + if (intflabellen > MAXLABLEN) + intflabellen = MAXLABLEN; + + // determine the number of columns needed + // for all disks and for all interfaces + // + dskcols = 7 + nrdisk * (disklabellen+1); + intcols = 1 + nrintf * (intflabellen+5); + + // determine the ratio between the size of the + // disk window and interface window + // + dsk2netratio = 1.0 * dskcols / intcols; + + // determine window model: + // 'm' - memory model (preferred) + // 'i' - I/O model when lots of disks and/or interfaces are present + // + memcols = 1 + MEMORYBARSZ + 2 + EVENTBARSZ + 1 + 1 + + (sstat->mem.totswap ? SWAPBARSZ+1 : 0); + + if (dskcols + intcols + 1 + memcols > COLS) + *winmodel = 'i'; + else + *winmodel = 'm'; + + return dsk2netratio; +} + +///////////////////////////////////////////////////// +// maintain hash list to register the current scale +// per network interface +///////////////////////////////////////////////////// +#define IFRESERVED 5 +#define ISNUM 16 // factor of 2! + +struct ifscale { + struct ifscale *next; + char *interface; + int curscale; +}; + +static struct ifscale *ishash[ISNUM]; + +// search the ifscale struct for a specific interface +// and return pointer +// +static struct ifscale * +getifscale(char *interface) +{ + int hash = 0; + struct ifscale *isp; + char *p = interface; + + for (; *p; p++) + hash += *p; + + for (isp=ishash[hash&(ISNUM-1)]; isp; isp=isp->next) + { + if ( strcmp(interface, isp->interface) == 0 ) + return isp; + } + + return NULL; // not found +} + +// create new ifscale struct for an interface, add it to +// a hash list and return pointer +// +static struct ifscale * +addifscale(char *interface, int scale) +{ + int len, hash = 0; + struct ifscale *isp; + char *p = interface; + + for (len=0; *p; p++, len++) + hash += *p; + + isp = malloc(sizeof(struct ifscale)); + ptrverify(isp, "Malloc failed for ifscale struct failed\n"); + + isp->interface = malloc(len+1); + ptrverify(isp->interface, "Malloc failed for ifscale name failed\n"); + strcpy(isp->interface, interface); + + isp->next = ishash[hash&(ISNUM-1)]; + isp->curscale = scale > winnet.nlines - IFRESERVED ? + scale : winnet.nlines - IFRESERVED; + + ishash[hash&(ISNUM-1)] = isp; + + return isp; +} + +// lower scale of all interfaces to the new scale (e.g. in case that +// the number of lines in the window has changed), but only if the +// old scale of an interface was zero or the given old scale (which +// is the initial scale related to the number of lines in the current +// window) +// +static void +lowerifscales(int oldlines, int newlines) +{ + int i; + struct ifscale *isp; + + for (i=0; i < ISNUM; i++) // all hash buckets + { + for (isp=ishash[i]; isp; isp=isp->next) + { + if (oldlines == 0 || + isp->curscale == oldlines-IFRESERVED) + isp->curscale = newlines - IFRESERVED; + } + } +} + +///////////////////////////////////////////////////// +// prepare the interface specific bar graph +///////////////////////////////////////////////////// +static void +do_netbars(struct sstat *sstat, int nsecs, char initlabels, char lower) +{ + static long totints, numints; + static char *labarea, *p; + static int labellen; + + static struct netval *netvals; + struct ifscale *isp; + + count_t ival, oval; + int i, j, namlen; + + // check if the number of interfaces has been changed since the + // previous sample and create X axis labels for all interfaces + // + if (totints != sstat->intf.nrintf || initlabels) + { + totints = sstat->intf.nrintf; + + // calculate how many physical interfaces (ethernet and wlan) + // + for (i=0, numints=0; i < totints; i++) + { + if (sstat->intf.intf[i].type != 'v') + numints++; + } + + // remove old label space + // + if (netvals) + { + free(netvals); + free(labarea); + } + + // create new label space + // + netvals = malloc(numints * sizeof(struct netval)); + ptrverify(netvals, "Malloc failed for %ld netvals structs failed\n", numints); + + labarea = malloc(numints * (MAXLABLEN+1)); + ptrverify(labarea, "Malloc failed for %ld interface labels failed\n", numints); + + // create new X axis labels + // + for (i=j=0, labellen=0, p=labarea; i < totints; i++) + { + if (sstat->intf.intf[i].type != 'v') + { + (netvals+j)->barlab = p; + + namlen = strlen(sstat->intf.intf[i].name); + + if (labellen < namlen) + labellen = namlen; + + if (namlen > MAXLABLEN) + snprintf(p, MAXLABLEN+1, "%-.*s", + MAXLABLEN, sstat->intf.intf[i].name); + else + snprintf(p, MAXLABLEN+1, "%s", + sstat->intf.intf[i].name); + + p += MAXLABLEN+1; + + j++; + } + } + + if (labellen > MAXLABLEN) + labellen = MAXLABLEN; + } + + // lower of all scales required by the user? + // + if (lower) + lowerifscales(0, winnet.nlines); + + // fill traffic values per physical interface + // + for (i=j=0; i < totints; i++) + { + if (sstat->intf.intf[i].type != 'v') + { + int maxmbits = 0; + + ival = sstat->intf.intf[i].rbyte/125/1000/nsecs; + oval = sstat->intf.intf[i].sbyte/125/1000/nsecs; + + (netvals+j)->pvalr = ival; + (netvals+j)->pvals = oval; + (netvals+j)->speed = sstat->intf.intf[i].speed; + + // determine minimum scale for bar graph + // + maxmbits = ival > oval ? ival : oval; + + // search for worst-case vertical scale so far and + // check if the new scale is larger --> exchange + // + // first verify if scale is known + // + if ( (isp = getifscale( (netvals+j)->barlab)) ) + { + if (isp->curscale < maxmbits) + isp->curscale = maxmbits; + } + else // first time: scale not known + { + isp = addifscale( (netvals+j)->barlab, + maxmbits); + } + + (netvals+j)->maxmbits = isp->curscale; + + j++; + } + } + + drawnetbars(&winnet, numints, netvals, + labellen, "Mbits/s", "Interfaces"); +} + + +///////////////////////////////////////////////////// +// draw vertical bars in a graph window +// mainly for CPUs and disks +///////////////////////////////////////////////////// +#define BARCHAR ' ' + +// arguments: +// - w pointer to struct perwindow +// - barscale maximum value for Y axis +// - hthreshold high threshold, i.e. critical value +// - numbars number of bars to draw +// - avgbar boolean: first value is for average bar? +// - vvp list of vertval structs with the bar values (numbars elements) +// - barlabsize length of label for each bar +// - ytitle title for Y axis +// - xtitle title for X axis +// - barwidth number of columns for one bar +// 0 = automatic (as many columns as possible, max. 3) +// 1 = single column bars with empty bar in between +// 2 = double column bars with empty bar in between +// 3 = triple column bars with empty bar in between +// +// returns: number of bars drawn +// +static int +drawvertbars(struct perwindow *w, + float barscale, float hthreshold, + int numbars, int avgbar, struct vertval *vvp, + int barlabsize, char *ytitle, char *xtitle, int barwidth) +{ + char buf[16], *ychar, horizontalxlab=0, barch; + int i, j, curline, curcol, barlines, realbars, + realcols, availcols, needcols; + int autoscale, color, labwidth = 0, spacing = 1; + float valperunit, level; + int ytitlelen = strlen(ytitle), xtitlelen = strlen(xtitle); + int ytitleline, xtitlespace; + int scalelen = snprintf(buf, sizeof buf, "%d", (int)barscale), + xindent; + void *vvporig = vvp; + + struct vertval *vp; + + // calculate indentation in front of first bar column + // considering line layout: + // - position 1: character of Y title + // - position 2: space + // - position 3: space + // - position 4..n: number of positions taken for Y label (scalelen) + // - position n+1: Y axis vertical line + // + xindent = 3 + scalelen + 1; + availcols = w->ncols - xindent; // number of columns for bars + + // verify if there is enough horizontal space in the + // window to show all per-bar X labels horizontally in one line + // instead of vertically in several lines + // + if (numbars*barlabsize+numbars-1 < availcols) + horizontalxlab = 1; + + // calculate effective number of lines for bar graph + // reserving 3 lines: + // - one line for x axis line + // - one line empty below per-bar labels + // - one line for x axis title + // + barlines = w->nlines - 3 - (horizontalxlab ? 1 : barlabsize); + + if (barlines <= 0) + return 0; + + if (barlines > MAXHEIGHT) + barlines = MAXHEIGHT; + + // calculate value represented by each bar graph line + // + valperunit = barscale / barlines; + + // determine the width of each bar + // + // variables involved: + // - realbars: how many bars can be drawn (realbars <= numbars) + // - realcols: how many screen columns will be used + // + autoscale = barwidth ? 0 : 1; + + if (autoscale) // define preferred bar width + barwidth = 3; + + while (1) + { + switch (barwidth) + { + // single bars and space between each bar + // + case 1: + needcols = numbars * 2 - 1; + realbars = needcols < availcols ? + numbars : (availcols+1)/2; + realcols = realbars * 2 - 1; + break; + + // double bars and space between each bar + // + case 2: + needcols = numbars * 3 - 1; + realbars = needcols <= availcols ? + numbars : (availcols+1)/3; + realcols = realbars * 3 - 1; + break; + + // triple bars and space between each bar + // + default: + needcols = numbars * 4 - 1; + realbars = needcols <= availcols ? + numbars : (availcols+1)/4; + realcols = realbars * 4 - 1; + } + + if (!autoscale || realbars == numbars || --barwidth < 1) + break; + } + + if (barwidth < 1) + barwidth = 1; + + // when all bars do not fit in the window width, + // sort the values in decreasing order to show + // the most relevant ones + // + if (availcols < needcols) + sortvertbars(numbars, avgbar, &vvp); + + // calculate horizontal position of X title + // (centered below bar columns) + // + if (horizontalxlab) + { + if (barlabsize < barwidth) + { + labwidth = barwidth; + } + else + { + labwidth = barlabsize; + spacing = barlabsize + 1 - barwidth; + realcols = realbars * barlabsize + realbars - 1; + } + } + + // calculate vertical position of Y title + // (centered left from bar lines) + // + if (ytitlelen > barlines) + ytitleline = 0; + else + ytitleline = (barlines - ytitlelen + 1) / 2; + + // create colormap and character map for each bar + // + fillbarmaps(numbars, vvp, valperunit, barlines); + + // wipe window contents + // + werase(w->win); + + // draw bar graph line-by-line + // + for (curline=0; curline < barlines; curline++) + { + int filler; + + // calculate value represented by this level and + // draw the high-threshold line if needed + // + level = (barlines - curline) * valperunit; + + if (level + valperunit/2 > hthreshold && + level - valperunit/2 <= hthreshold ) + filler = ACS_HLINE; + else + filler = ' '; + + // select the character that has to be printed from + // the vertical title + // + if (curline >= ytitleline && (curline-ytitleline) < ytitlelen) + ychar = ytitle+curline-ytitleline; + else + ychar = " "; + + // print vertical Y title character and Y axis value + // + mvwprintw(w->win, curline, 0, "%c %*d", *ychar, scalelen, + (int)level); + waddch(w->win, ACS_VLINE); + + // for each bar + // + for (curcol=0, vp=vvp; curcol < realbars; curcol++, vp++) + { + color = vp->barmap[barlines-curline-1]; + barch = vp->barchr[barlines-curline-1]; + + // print colored character(s) + // + if (color) + { + colorswon(w->win, color); + + switch (barwidth) + { + case 1: + waddch(w->win, barch); + break; + case 2: + waddch(w->win, barch); + waddch(w->win, BARCHAR); + break; + case 3: + waddch(w->win, BARCHAR); + waddch(w->win, barch); + waddch(w->win, BARCHAR); + } + + colorswoff(w->win, color); + } + else + { + // print fillers + // + if (filler != ' ') + colorswon(w->win, FGCOLORCRIT); + + for (i=0; i < barwidth; i++) + waddch(w->win, filler); + + if (filler != ' ') + colorswoff(w->win, FGCOLORCRIT); + } + + // add fillers between the bars + // + if (filler != ' ') + colorswon(w->win, FGCOLORCRIT); + + for (i=0; i < (curcol < realbars-1 ? + spacing : spacing-1); i++) + waddch(w->win, filler); + + if (filler != ' ') + colorswoff(w->win, FGCOLORCRIT); + } + } + + // print line for X axis + // + if (curline >= ytitleline && (curline-ytitleline) < ytitlelen) + ychar = ytitle+curline-ytitleline; + else + ychar = " "; + + mvwprintw(w->win, curline++, 0, "%c %*d", *ychar, scalelen, 0); + waddch(w->win, ACS_LLCORNER); + + for (i=0; i < realcols; i++) + waddch(w->win, ACS_HLINE); + + if (horizontalxlab) + { + // print X axis values horizontally (one line) + // + wmove(w->win, curline++, xindent); + + if (barlabsize == 1 && barwidth == 3) + waddch(w->win, ' '); // alignment + + for (i=0, vp=vvp; i < realbars; i++) + wprintw(w->win, "%-*.*s ", labwidth, barlabsize, + (vp+i)->barlab); + } + else + { + // print X axis values vertically + // + for (i=0; i < barlabsize; i++) + { + wmove(w->win, curline++, xindent); + + for (curcol=0, vp=vvp; curcol < realbars; curcol++,vp++) + { + waddch(w->win, *((vp->barlab)+i)); + + for (j=0; j < barwidth-1; j++) + waddch(w->win, BARCHAR); + + if (spacing) + waddch(w->win, ' '); + } + } + } + + // print X title centered under bar graph + // + curline++; // empty line + + if (xtitlelen > realcols) + xtitlespace = xindent + xtitlelen; + else + xtitlespace = xindent + (xtitlelen + realcols)/2; + + mvwprintw(w->win, curline++, 0, "%*s", xtitlespace, xtitle); + + wrefresh(w->win); + + if (vvporig != vvp) // reallocated by sortvertbars()? + free(vvp); + + return realbars; +} + +///////////////////////////////////////////////////// +// fill the color map and character map of each bar +// +// the color map describes a color code per bar line +// and the character map describes a character per +// bar line +///////////////////////////////////////////////////// +static void +fillbarmaps(int numbars, struct vertval *vvp, float valperunit, int barlines) +{ + int i, c, n, m; + struct vertval *vp; + char *mp, *cp; + + // for each bar, fill the color map and character map + // + for (i=0, vp=vvp; i < numbars; i++, vp++) + { + // initialize both maps + // + memset(vp->barmap, '\0', MAXHEIGHT); + memset(vp->barchr, BARCHAR, MAXHEIGHT); + + // when no separate categories defined, + // fill the entire bar with the base color + // + if (vp->numcat == 0) + { + m = (vp->barval + valperunit/2) / valperunit; + memset(vp->barmap, vp->basecolor, m); + continue; + } + + // for each bar category, fill the corresponding color + // in the color map and on the lowest position in the + // character map fill the category character + // + for (c=0, mp=vp->barmap, cp=vp->barchr; c < vp->numcat; c++) + { + // determine the number of color/character positions + // for this category + // + n = (vp->category[c].cval + valperunit/2) / valperunit; + + if (n > 0 && mp - vp->barmap + n < MAXHEIGHT) + { + // fill all color positions (lines) + // + memset(mp, vp->category[c].ccol, n); + mp += n; + + // fill one character position + // + *cp = vp->category[c].clab; + cp += n; + } + } + + // verify that all positions of the total bar value are + // filled; if not (due to rounding issues), add a filler + // + // rounding issues: + // suppose that the total percentage is 49, subdivided + // into percentage 22 for category 'read' and 27 for + // category 'write' + // when every bar line represents 5% the total number + // of bar lines should be 10 (49 rounded to 50) + // for the category 'read' 4 bar lines will be used + // (22 rounded to 20) and for the category 'write' + // 5 bar lines (27 rounded to 25) + // then 1 line should be filled with a neutral color + // + n = mp - vp->barmap; // number of units filled + m = (vp->barval + valperunit/2) / valperunit; // total units + + if (n < m && m < MAXHEIGHT) + memset(mp, vp->basecolor, m-n); + } +} + +///////////////////////////////////////////////////// +// draw vertical bars for network interfaces +///////////////////////////////////////////////////// +// arguments: +// - w pointer to struct perwindow +// - numbars number of bars to draw, i.e. number of interfaces +// - nvp pointer to struct containing traffic info per interface +// - barlabsize length of label per bar +// - ytitle title for Y axis +// - xtitle title for X axis +// +// returns: number of bars drawn +// +static int +drawnetbars(struct perwindow *w, int numbars, struct netval *nvp, + int barlabsize, char *ytitle, char *xtitle) +{ + char *ychar; + int i, ifbar, curline, barlines, realbars, color, perifcols; + float *valperline, level; + int ytitlelen = strlen(ytitle), xtitlelen=strlen(xtitle), + ytitleline; + void *nvporig = nvp; + + // define number of columns needed per interface + // considering layout: + // - position 1: space + // - position 2..7: six positions for Y value + // - position 8: Y axis vertical line + // - position 9..12: double column for transmit + receive + // + perifcols = 12; + + if ((w->ncols-1)/perifcols >= numbars) + realbars = numbars; // real number of interfaces + else + realbars = (w->ncols-1) / perifcols; + + // calculate effective number of lines for bar graph + // reserving 3 lines: + // - one line for x axis line + // - one line for speed + // - one line for x axis label + // - one line blank under labels + // - one line containing x title + // + barlines = w->nlines - IFRESERVED; + + if (barlines <= 0) + return 0; + + // when all network interfaces do not fit in the window width, + // sort the values in decreasing order to show + // the most relevant ones + // + if (numbars > realbars) + sortnetbars(numbars, &nvp); + + // calculate value represented by each bar graph line + // (different for each interface) + // + valperline = malloc(numbars * sizeof(float)); + ptrverify(valperline, "Malloc failed for %d values per line\n", + numbars); + + for (i=0; i < numbars; i++) + *(valperline+i) = (float)(nvp+i)->maxmbits / barlines; + + // calculate vertical position of y title + // (centered left from bar lines) + // + if (ytitlelen > barlines) + ytitleline = 0; + else + ytitleline = (barlines - ytitlelen + 1) / 2; + + // wipe window contents + // + werase(w->win); + + // draw bar graphs line-by-line + // + for (curline=0; curline < barlines; curline++) + { + // select the character that has to be printed from + // the vertical Y title + // + if (curline >= ytitleline && (curline-ytitleline) < ytitlelen) + ychar = ytitle+curline-ytitleline; + else + ychar = " "; + + // print vertical y title character + // + mvwaddch(w->win, curline, 0, *ychar); + + // print four columns per interface + // + for (ifbar=0; ifbar < realbars; ifbar++) + { + // calculate value represented by this level + // + level = (barlines - curline) * *(valperline+ifbar); + + wprintw(w->win, " %6d", (int)level); + + waddch(w->win, ACS_VLINE); + + // rounded receive bar reaches this level? + // + if ((nvp+ifbar)->pvalr + *(valperline+ifbar) / 2 >= level) + { + // print colored bar + // + color = COLORNETRECV; + + colorswon(w->win, color); + + if (curline == barlines-1) + { + wprintw(w->win, "RX"); + } + else + { + waddch(w->win, BARCHAR); + waddch(w->win, BARCHAR); + } + + colorswoff(w->win, color); + } + else + { + // print spaces + // + wprintw(w->win, " "); + } + + // rounded send second bar reaches this level? + // + if ((nvp+ifbar)->pvals + *(valperline+ifbar) / 2 >= level) + { + // print colored bar + // + color = COLORNETSEND; + colorswon(w->win, color); + + if (curline == barlines-1) + { + wprintw(w->win, "TX"); + } + else + { + waddch(w->win, BARCHAR); + waddch(w->win, BARCHAR); + } + + colorswoff(w->win, color); + } + else + { + // print space + // + wprintw(w->win, " "); + } + } + } + + // print lines for X axis + // + if (curline >= ytitleline && (curline-ytitleline) < ytitlelen) + ychar = ytitle+curline-ytitleline; + else + ychar = " "; + + mvwaddch(w->win, curline++, 0, *ychar); + + for (ifbar=0; ifbar < realbars; ifbar++) + { + wprintw(w->win, " %5d", 0); + waddch(w->win, ACS_LLCORNER); + + for (i=0; i < perifcols-8; i++) + waddch(w->win, ACS_HLINE); + } + + // print speed per interface + // + wmove(w->win, curline++, 1); + + for (ifbar=0; ifbar < realbars; ifbar++) + { + if ((nvp+ifbar)->speed) + wprintw(w->win, "%*dM", perifcols-1, + (nvp+ifbar)->speed); + else + wprintw(w->win, "%*sM", perifcols-1, "?"); + } + + // print horizontal label per interface bar + // + wmove(w->win, curline++, 1); + + for (ifbar=0; ifbar < realbars; ifbar++) + wprintw(w->win, "%*.*s", perifcols, barlabsize, + (nvp+ifbar)->barlab); + + // print X title centered under bar graph + // + curline++; // empty line + + mvwprintw(w->win, curline++, 0, "%*s", + 3+(realbars*perifcols)/2+(xtitlelen/2), xtitle); + + wrefresh(w->win); + + // free allocated memory + // + free(valperline); + + if (nvp != nvporig) + free(nvp); // allocated by sortnetbars() + + return realbars; +} + + +///////////////////////////////////////////////////// +// draw specific window with memory management info +///////////////////////////////////////////////////// +static int +drawmemory(struct perwindow *w, struct sstat *sstat, int nsecs, + time_t curtime, char flag) +{ + static time_t lastoomkills; + + long long totalmem, cachemem, shmemrss, tmpfsmem, + slabmem, freemem; + long long totalswp, shmemswp, freeswp; + char scanseverity, swapseverity, killseverity; + int curline=0, barlines, color; + int usedlines, freelines, cachelines, tmpfslines, + slablines, shmemlines; + int memorycol = 1, + swapcol = memorycol + MEMORYBARSZ + 1, + eventcol = swapcol + SWAPBARSZ + 2; + float valperunit; + char formatbuf[16]; + + // calculate all memory values, keeping in mind: + // - shmrss resident System V shared memory + // - shmem resident System V shared memory + resident tmpfs + // - cachemem page cache including shmem + // + totalmem = sstat->mem.physmem * pagesize; + cachemem = (sstat->mem.cachemem + sstat->mem.buffermem - + sstat->mem.shmem) * pagesize; + shmemrss = sstat->mem.shmrss * pagesize; + tmpfsmem = (sstat->mem.shmem - sstat->mem.shmrss) * pagesize; + slabmem = sstat->mem.slabmem * pagesize; + freemem = sstat->mem.freemem * pagesize; + + totalswp = sstat->mem.totswap * pagesize; + shmemswp = sstat->mem.shmswp * pagesize; + freeswp = sstat->mem.freeswap* pagesize; + + // determine severity for pagescans, swapouts and oomkills + // 'n' - normal, + // 'w' - warning, + // 'c' - critical + // + // for oomkills specifically: + // show warning level for 15 minutes after the last oomkill + // occurred (current time can be smaller than last time in + // case of 'T' key when viewing raw logs) + // + scanseverity = setseverity(sstat->mem.pgscans/nsecs, 100000, 1000); + swapseverity = setseverity(sstat->mem.swouts/nsecs, 500, 100); + + if (sstat->mem.oomkills <= 0) // no new oomkills? + { + if (curtime > lastoomkills && curtime - lastoomkills < 900) + killseverity = 'w'; + else + killseverity = 'n'; + } + else // new oomkills during last interval + { + killseverity = 'c'; + + if (flag&RRBOOT) + lastoomkills = curtime - nsecs; + else + lastoomkills = curtime; + } + + // calculate effective number of lines for bar graph + // + barlines = w->nlines - 2; + + if (barlines <= 5) + return 0; + + // calculate value represented by each bar graph line + // + valperunit = totalmem / barlines; + + // calculate number of lines for free, shared memory, + // tmpfs, slab and page cache + // + freelines = (freemem + valperunit/2) / valperunit; + shmemlines = (shmemrss + valperunit/2) / valperunit; + tmpfslines = (tmpfsmem + valperunit/2) / valperunit; + slablines = (slabmem + valperunit/2) / valperunit; + cachelines = (cachemem + valperunit/2) / valperunit; + usedlines = barlines - freelines - shmemlines - + tmpfslines - slablines - cachelines; + + // wipe window contents + // + werase(w->win); + + // draw lines for free memory + // + curline += drawmemlines(w, curline, memorycol, freelines, + MEMORYBARSZ, COLORMEMFREE, "free", NULL); + + // draw lines for cache memory + // + curline += drawmemlines(w, curline, memorycol, cachelines, + MEMORYBARSZ, COLORMEMCACH, "pagecache", NULL); + + // draw lines for tmpfs memory + // + curline += drawmemlines(w, curline, memorycol, tmpfslines, + MEMORYBARSZ, COLORMEMTMP, "tmpfs", NULL); + + // draw lines for shared memory + // + curline += drawmemlines(w, curline, memorycol, shmemlines, + MEMORYBARSZ, COLORMEMSHM, "sharedmem", NULL); + + // draw lines for slab memory + // + curline += drawmemlines(w, curline, memorycol, slablines, + MEMORYBARSZ, COLORMEMSLAB, "slab", "caches"); + + // draw lines for other used memory + // + if ((totalmem-cachemem-freemem)*100 / totalmem >= membadness) + color = COLORBAD; + else + color = COLORMEMUSED; + + curline += drawmemlines(w, curline, memorycol, usedlines, + MEMORYBARSZ, color, "processes", "&kernel"); + + // show memory size + // + mvwprintw(w->win, curline++, memorycol, "%*s", + MEMORYBARSZ-(MEMORYBARSZ-7+1)/2, + val2memstr(totalmem, formatbuf, MBFORMAT, 0, 0)); + + mvwprintw(w->win, curline, memorycol, "%*s", + MEMORYBARSZ-(MEMORYBARSZ-6)/2, "Memory"); + + wrefresh(w->win); + + // show swap space (if used) + // + if (totalswp) + { + // calculate value represented by each bar graph line + // + valperunit = totalswp / barlines; + + // calculate number of lines for free swap + // + freelines = (freeswp + (valperunit/2)) / valperunit; + shmemlines = (shmemswp + (valperunit/2)) / valperunit; + usedlines = barlines - shmemlines - freelines; + + // draw lines for free swap + // + curline = 0; + + curline += drawmemlines(w, curline, swapcol, freelines, + SWAPBARSZ, COLORMEMFREE, "free", NULL); + + // draw lines for swapped shared memory swap + // + curline += drawmemlines(w, curline, swapcol, shmemlines, + SWAPBARSZ, COLORMEMSHM, "shamem", NULL); + + // draw lines for occupied swap + // highly occupied swap is only an issue when also memory + // is highly occupied + // + if ((totalswp-freeswp) * 100 / totalswp >= swpbadness && + (totalmem-cachemem-freemem) * 100 / totalmem >= membadness) + color = COLORBAD; + else + color = COLORMEMUSED; + + curline += drawmemlines(w, curline, swapcol, usedlines, + SWAPBARSZ, color, "procs", "&tmpfs"); + + // show swap size + // + mvwprintw(w->win, curline++, swapcol, "%*s", + SWAPBARSZ-(SWAPBARSZ-7+1)/2, + val2memstr(totalswp, formatbuf, MBFORMAT, 0, 0)); + + mvwprintw(w->win, curline, swapcol, "%*s", + SWAPBARSZ-(SWAPBARSZ-4-1)/2, "Swap"); + } + else + { + eventcol = swapcol+1; + } + + // show events + // + mvwprintw(w->win, curline, eventcol, " Events "); + + if (barlines > 1) // show oomkilling? + curline = drawevent(w, curline, eventcol, + severitycolor(killseverity), + " oomkills ", " %8ld ", + sstat->mem.oomkills); + + if (barlines > 4) // show swapouts? + curline = drawevent(w, curline, eventcol, + severitycolor(swapseverity), + " swapouts ", "%7ld/s ", + sstat->mem.swouts/nsecs); + + if (barlines > 7) // show pagescans? + curline = drawevent(w, curline, eventcol, + severitycolor(scanseverity), + " pagscans ", "%7ld/s ", + sstat->mem.pgscans / nsecs); + + if (barlines > 10) // show swapins? + curline = drawevent(w, curline, eventcol, + COLORMEMBAR, + " swapins ", "%7ld/s ", + sstat->mem.swins / nsecs); + + if (barlines > 13) // show pageouts? + curline = drawevent(w, curline, eventcol, + COLORMEMBAR, + " pagouts ", "%7ld/s ", + sstat->mem.pgouts / nsecs); + + if (barlines > 16) // show pageins? + curline = drawevent(w, curline, eventcol, + COLORMEMBAR, + " pageins ", "%7ld/s ", + sstat->mem.pgins / nsecs); + + wrefresh(w->win); + + return 1; +} + +///////////////////////////////////////////////////// +// draw lines for specific memory category +///////////////////////////////////////////////////// +static int +drawmemlines(struct perwindow *w, int startline, int startcolumn, + int numlines, int width, int color, + char *cat1, char *cat2) +{ + int line=startline, catline, targetline=startline+numlines, len; + + if (numlines == 0) + return 0; + + if (usecolors) + wattron(w->win, COLOR_PAIR(color)); + + wattron(w->win, A_BOLD); + + for (catline=startline+(numlines-1)/2; line < targetline; line++) + { + wmove(w->win, line, startcolumn); + + if (line == catline) + { + len = strlen(cat1); + + if (len > width) + { + // truncate + // + wprintw(w->win, "%.*s", width, cat1); + } + else + { + int cw = width - (width-len+1)/2; + + wprintw(w->win, "%*s%*s", cw, cat1, width-cw, " "); + } + } + else + { + if (line == catline+1 && cat2) + { + len = strlen(cat2); + + if (len > width) + { + wprintw(w->win, "%.*s", width, cat2); + } + else + { + int cw = width - (width-len+1)/2; + + wprintw(w->win, "%*s%*s", cw, + cat2, width-cw, " "); + } + } + else + { + wprintw(w->win, "%*s", width, " "); + } + } + } + + wattroff(w->win, A_BOLD); + + if (usecolors) + wattroff(w->win, COLOR_PAIR(color)); + + return numlines; +} + +///////////////////////////////////////////////////// +// draw lines for specific memory event +///////////////////////////////////////////////////// +static int +drawevent(struct perwindow *w, int line, int column, int color, + char *text, char *format, long value) +{ + colorswon(w->win, color); + + line -= 2; + + if (value >= 0) + mvwprintw(w->win, line, column, format, value); + else + mvwprintw(w->win, line, column, " ? "); + + line -= 1; + wattron(w->win, A_BOLD); + mvwprintw(w->win, line, column, text); + wattroff(w->win, A_BOLD); + + colorswoff(w->win, color); + + return line; +} + +///////////////////////////////////////////////////// +// fill the header line (separate window) +// and wait for keyboard input event +///////////////////////////////////////////////////// +static int +headergetch(time_t curtime, int nsecs, char *statusmsg, int statuscol) +{ + int colsunused, fill1, fill2, fill3, statcol; + int headlen = strlen(headmsg); + char buf[64], timestr[16], datestr[16]; + int seclen = val2elapstr(nsecs, buf); + + convdate(curtime, datestr); /* date to ascii string */ + convtime(curtime, timestr); /* time to ascii string */ + + // calculate subdivision of areas in header line + // + colsunused = COLS - 35 - seclen - utsnodenamelen - headlen; + fill1 = colsunused / 6; + fill2 = (colsunused - fill1) / 2; + fill3 = colsunused - fill1 - fill2; + + // fill header line + // + werase(headwin); + wattron(headwin, A_REVERSE); + wprintw(headwin, "ATOP - %s %*s%s %s%*s%s%*s%s elapsed", + utsname.nodename, + fill1, " ", datestr, timestr, + fill2, " ", headmsg, + fill3, " ", buf); + + wattroff(headwin, A_REVERSE); + + // display specific status if needed + // + statcol = 27 + utsnodenamelen + fill1 + 2; + + if (statusmsg) + { + colorswon(headwin, statuscol); + wattron(headwin, A_REVERSE); + mvwprintw(headwin, 0, statcol, statusmsg); + wattroff(headwin, A_REVERSE); + colorswoff(headwin, statuscol); + } + + wrefresh(headwin); + + // wait for keystroke + // + return mvwgetch(headwin, 1, 0); +} + + +///////////////////////////////////////////////////// +// create all windows +///////////////////////////////////////////////////// +static int +wininit(struct sstat *sstat) +{ + int lpw, c4c, c4m, c4d, c4n, i, avail; + float col, dsk2netratio; + char winmodel; + + // determine the ratio between the size of the + // disk window and interface window + // + // determine window model: + // 'm' - memory model (preferred) + // 'i' - I/O model when lots of disks and/or interfaces are present + // + dsk2netratio = getwinratio(sstat, &winmodel); + + // cleanup underlying standard screen + // + werase(stdscr); + refresh(); + + // calculate number of lines for a half-screen bar graph window + // + lpw = (LINES-1) / 2 - 1; // lines per window + + // calculate number of columns for the windows in the upper half + // + // - memory window gets fixed horizontal size (columns), + // either with or without swap bar + // + // - cpu window gets rest of the colums in upper half + // + c4m = MEMORYBARSZ + EVENTBARSZ + 4; + c4m += sstat->mem.totswap ? SWAPBARSZ+1 : 0; + + c4c = COLS - c4m - 1; // cpu: rest of columns + + // calculate number of columns for windows in lower half + // + // - width of the disk and the interface windows will be + // calculated according to the requested ratio + // depending of the model, the full screen width can be used + // (I/O model) or the remaining width without the memory columns + // (memory model) + // + avail = COLS - (winmodel == 'm' ? c4m + 1: 0); // available columns + + col = avail / (dsk2netratio+1.0); + c4d = col * dsk2netratio; // columns for disk + c4n = avail - c4d - 1; // columns for interfaces + + // create window of two lines for the header line + // (second line only meant to 'park' the cursor) + // + headwin = newwin(2, COLS, 0, 0); + + // create window of one line as horizonal ruler between the + // upper and lower half, and draw horizontal ruler + // + avail = winmodel=='m' ? COLS - c4m : COLS; + + midline = newwin(1, avail, lpw+2, 0); + + colorswon(midline, FGCOLORBORDER); + + for (i=0; i < avail; i++) + { + if (i == c4c && c4c != c4d) + { + waddch(midline, ACS_BTEE); + continue; + } + + if (i == c4d) + { + if (c4c != c4d) + waddch(midline, ACS_TTEE); + else + waddch(midline, ACS_PLUS); + continue; + } + + waddch(midline, ACS_HLINE); + } + + colorswoff(midline, FGCOLORBORDER); + + wrefresh(midline); + + // create window of one column for vertical ruler + // (half or full) and draw vertical ruler + // + avail = winmodel=='m' ? LINES : lpw+1; // available lines + + colupper = newwin(avail, 1, 1, c4c); + + colorswon(colupper, FGCOLORBORDER); + + for (i=0; i < avail; i++) + if (i == lpw+1) + waddch(colupper, ACS_RTEE); + else + waddch(colupper, ACS_VLINE); + + colorswoff(colupper, FGCOLORBORDER); + + wrefresh(colupper); + + // create window of one column for vertical ruler + // in the lower half and draw vertical ruler + // + collower = newwin(LINES-lpw-3, 1, lpw+3, c4d); + + colorswon(collower, FGCOLORBORDER); + + for (i=0; i < lpw+1; i++) + waddch(collower, ACS_VLINE); + + colorswoff(collower, FGCOLORBORDER); + + wrefresh(collower); + + // create four windows for the resource graphs + // and fill dimensions + // + wincpu.nlines = lpw; + wincpu.ncols = c4c; + wincpu.win = newwin(wincpu.nlines, wincpu.ncols, 2, 0); + + winmem.nlines = winmodel == 'i' ? lpw : LINES-2; + winmem.ncols = c4m; + winmem.win = newwin(winmem.nlines, winmem.ncols, 2, c4c+1); + + lpw = LINES - 3 - lpw; // recalc for extra line in case of odd lines + + windsk.nlines = lpw; + windsk.ncols = c4d; + windsk.win = newwin(windsk.nlines, windsk.ncols, + wincpu.nlines+3, 0); + + lowerifscales(winnet.nlines, lpw); // lower initial scales + + winnet.nlines = lpw; + winnet.ncols = c4n; + winnet.win = newwin(winnet.nlines, winnet.ncols, + wincpu.nlines+3, c4d+1); + + wrefresh(wincpu.win); + wrefresh(winmem.win); + wrefresh(windsk.win); + wrefresh(winnet.win); + + return 1; +} + + +///////////////////////////////////////////////////// +// delete all windows +///////////////////////////////////////////////////// +static void +winexit(void) +{ + delwin(wincpu.win); + delwin(winmem.win); + delwin(windsk.win); + delwin(winnet.win); + + delwin(colupper); + delwin(collower); + delwin(midline); + delwin(headwin); +} + + +///////////////////////////////////////////////////// +// create a separate window to request the user +// to enter a value +// +// arguments +// - prompt pointer to prompt string +// - answer pointer to buffer in which +// the answer will be returned +// - maxanswer maximum size of answer buffer +// - numerical boolean: convert value to integer? +// +// return value: +// if 'numerical' is true, integer value or +// -1 when input was not numeric +// +// if 'numerical' is false, value 0 or +// -1 when no input was given +///////////////////////////////////////////////////// +static int +getwininput(char *prompt, char *answer, int maxanswer, char numerical) +{ + WINDOW *mywin; + int inumval = -1, numcols = strlen(prompt) + maxanswer + 1; + + // create a boxed window of three lines + // for the conversation + // + mywin = newwin(3, numcols, (LINES-3)/3, (COLS-numcols)/3); + + box(mywin, ACS_VLINE, ACS_HLINE); + + // show the prompt + // + mvwprintw(mywin, 1, 1, prompt); + + // prepare reading input + // + echo(); // switch echoing on + answer[0] = 0; + + if (wgetnstr(mywin, answer, maxanswer-1) != ERR) + { + // conversion to integer required? + // + if (numerical) + { + if (answer[0]) // data entered? + { + if ( numeric(answer) ) + { + inumval = atoi(answer); + } + else + { + beep(); + wmove(mywin, 1, 1); + wclrtoeol(mywin); + box(mywin, ACS_VLINE, ACS_HLINE); + mvwprintw(mywin, 1, 1, "Not numeric!"); + wrefresh(mywin); + sleep(2); + } + } + } + else + { + inumval = 0; + } + } + else + { + beep(); + } + + noecho(); + delwin(mywin); + + return inumval; +} + + +///////////////////////////////////////////////////// +// create a separate window with help text and +// wait for any keyboard input +///////////////////////////////////////////////////// +#define HELPLINES 25 +#define HELPCOLS 70 + +static void +showhelp(void) +{ + WINDOW *helpwin; + int line=1, inputkey; + + // create centered window for help text + // + // notice that this window is bigger than the required + // minimum size of the terminal + // + helpwin = newwin(HELPLINES, HELPCOLS, + (LINES-HELPLINES)/2, (COLS-HELPCOLS)/2); + + if (!helpwin) // window allocation failed? + return; + + box(helpwin, ACS_VLINE, ACS_HLINE); + + // show help text + // + mvwprintw(helpwin, line++, 2, "Display mode:"); + mvwprintw(helpwin, line++, 2, + " '%c' - text mode: keep same process info", MBARGRAPH); + mvwprintw(helpwin, line++, 2, + " '%c' - text mode: generic info", MPROCGEN); + mvwprintw(helpwin, line++, 2, + " '%c' - text mode: memory details", MPROCMEM); + + if (supportflags & IOSTAT) + mvwprintw(helpwin, line++, 2, + " '%c' - text mode: disk details", MPROCDSK); + + if (supportflags & NETATOP) + mvwprintw(helpwin, line++, 2, + " '%c' - text mode: network details", MPROCNET); + + if (supportflags & GPUSTAT) + mvwprintw(helpwin, line++, 2, + " '%c' - text mode: GPU details", MPROCGPU); + + mvwprintw(helpwin, line++, 2, + " '%c' - text mode: scheduling and thread-group info", + MPROCSCH); + mvwprintw(helpwin, line++, 2, + " '%c' - text mode: various info", MPROCVAR); + mvwprintw(helpwin, line++, 2, + " '%c' - text mode: full command line per process", + MPROCARG); + + line++; + + // show context dependent help text for raw file viewing or + // live measurement + // + if (rawreadflag) + { + mvwprintw(helpwin, line++, 2, "Raw file viewing:"); + mvwprintw(helpwin, line++, 2, + " '%c' - show next sample in raw file", MSAMPNEXT); + mvwprintw(helpwin, line++, 2, + " '%c' - show previous sample in raw file", MSAMPPREV); + mvwprintw(helpwin, line++, 2, + " '%c' - rewind to begin of raw file", MRESET); + mvwprintw(helpwin, line++, 2, + " '%c' - branch to certain time in raw file", + MSAMPBRANCH); + } + else + { + mvwprintw(helpwin, line++, 2, "Control:"); + mvwprintw(helpwin, line++, 2, + " '%c' - change interval timer (0 = only manual trigger)", MINTERVAL); + mvwprintw(helpwin, line++, 2, + " '%c' - manual trigger to force next sample", + MSAMPNEXT); + mvwprintw(helpwin, line++, 2, + " '%c' - reset counters to boot time values", MRESET); + mvwprintw(helpwin, line++, 2, + " '%c' - pause button to freeze current sample (toggle)", MPAUSE); + } + + line++; + mvwprintw(helpwin, line++, 2, "General:"); + mvwprintw(helpwin, line++, 2, + " '%c' - reset network scale (otherwise keeps highest level)", MBARLOWER); + mvwprintw(helpwin, line++, 2, + " '%c' - busy bars with/without categories (toggle)", + MBARMONO); + mvwprintw(helpwin, line++, 2, + " '%c' - quit this program", MQUIT); + + line++; + mvwprintw(helpwin, line++, 2, + "Select one of these keys (except '%c') or ", MQUIT); + mvwprintw(helpwin, line++, 2, + "any other key to leave help..."); + + wrefresh(helpwin); + + // wait for any keystroke + // + inputkey = wgetch(helpwin); + + // push this keystroke back to be received by the main loop + // + if (inputkey != MQUIT) + ungetch(inputkey); + + // remove help window + delwin(helpwin); +} + +///////////////////////////////////////////////////// +// switch certain color on +///////////////////////////////////////////////////// +static void +colorswon(WINDOW *win, int color) +{ + if (usecolors) + wattron(win, COLOR_PAIR(color)); + else + wattron(win, A_REVERSE); +} + +///////////////////////////////////////////////////// +// switch certain color off +///////////////////////////////////////////////////// +static void +colorswoff(WINDOW *win, int color) +{ + if (usecolors) + wattroff(win, COLOR_PAIR(color)); + else + wattroff(win, A_REVERSE); +} + +///////////////////////////////////////////////////// +// return background color depending on severity +///////////////////////////////////////////////////// +static int +severitycolor(char severity) +{ + int color; + + switch (severity) + { + case 'n': // normal + color = COLOROKAY; + break; + + case 'w': // warning + color = COLORWARN; + break; + + case 'c': // critical + color = COLORBAD; + break; + + default: + color = 0; + } + + return color; +} + +///////////////////////////////////////////////////// +// return character to represent the severity +///////////////////////////////////////////////////// +// return value +// - n normal +// - w warning +// - c critical +// +static char +setseverity(long val, long cthreshold, long wthreshold) +{ + if (val < wthreshold) + return 'n'; + + if (val < cthreshold) + return 'w'; + + return 'c'; +} + +///////////////////////////////////////////////////// +// sort bar values in descending order +// for CPU and disk stats +///////////////////////////////////////////////////// +static void +sortvertbars(int nbars, int avgbar, struct vertval **valpp) +{ + // copy original array to be sorted + // + struct vertval *sortlist = malloc(sizeof(struct vertval) * nbars); + ptrverify(sortlist, "Malloc failed for %d sortitems\n", nbars); + + memcpy(sortlist, *valpp, sizeof(struct vertval) * nbars); + + // sort the copied list + // + qsort(sortlist+avgbar, nbars-avgbar, sizeof(struct vertval), + compvertval); + + *valpp = sortlist; +} + +///////////////////////////////////////////////////// +// function to be called by qsort in sortvertbars() +///////////////////////////////////////////////////// +static int +compvertval(const void *a, const void *b) +{ + const struct vertval *sia = a; + const struct vertval *sib = b; + + if (sia->barval > sib->barval) + return -1; + + if (sia->barval < sib->barval) + return 1; + + return 0; +} + +///////////////////////////////////////////////////// +// sort network bar values in descending order +// for network stats +///////////////////////////////////////////////////// +static void +sortnetbars(int nbars, struct netval **valpp) +{ + // copy original array to be sorted + // + struct netval *sortlist = malloc(sizeof(struct netval) * nbars); + ptrverify(sortlist, "Malloc failed for %d sortitems\n", nbars); + + memcpy(sortlist, *valpp, sizeof(struct netval) * nbars); + + // sort the copied list + // + qsort(sortlist, nbars, sizeof(struct netval), compnetval); + + *valpp = sortlist; +} + +///////////////////////////////////////////////////// +// function to be called by qsort in sortnetbars() +///////////////////////////////////////////////////// +static int +compnetval(const void *a, const void *b) +{ + const struct netval *nva = a; + const struct netval *nvb = b; + long long v1, v2; + + v1 = nva->pvals + nva->pvalr; + v2 = nvb->pvals + nvb->pvalr; + + if (v1 > v2) + return -1; + + if (v1 < v2) + return 1; + + return 0; +} diff -Nru atop-2.8.1/ifprop.c atop-2.9.0/ifprop.c --- atop-2.8.1/ifprop.c 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/ifprop.c 2023-05-13 08:20:27.000000000 +0000 @@ -310,7 +310,7 @@ int sockfd; #ifdef ETHTOOL_GLINKSETTINGS - struct ethtool_link_settings *ethlink; // preferred! + struct ethtool_link_settings *ethlink = NULL; // preferred! #endif struct ethtool_cmd ethcmd; // deprecated @@ -375,8 +375,6 @@ ethernet = 1; speed = ethlink->speed; duplex = ethlink->duplex; - - free(ethlink); } else #endif @@ -436,6 +434,9 @@ } } +#ifdef ETHTOOL_GLINKSETTINGS + free(ethlink); +#endif close(sockfd); return 1; diff -Nru atop-2.8.1/ifprop.h atop-2.9.0/ifprop.h --- atop-2.8.1/ifprop.h 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/ifprop.h 2023-05-13 08:20:27.000000000 +0000 @@ -26,6 +26,9 @@ ** -------------------------------------------------------------------------- */ +#ifndef __IFPROP__ +#define __IFPROP__ + struct ifprop { char type; /* type: 'e' - ethernet */ /* 'w' - wireless */ @@ -39,3 +42,5 @@ int getifprop(struct ifprop *); void initifprop(void); + +#endif diff -Nru atop-2.8.1/json.c atop-2.9.0/json.c --- atop-2.8.1/json.c 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/json.c 2023-05-13 08:20:27.000000000 +0000 @@ -49,35 +49,36 @@ #include "atop.h" #include "photosyst.h" #include "photoproc.h" +#include "json.h" #define LEN_HP_SIZE 64 #define LINE_BUF_SIZE 1024 -static void json_print_CPU(); -static void json_print_cpu(); -static void json_print_CPL(); -static void json_print_GPU(); -static void json_print_MEM(); -static void json_print_SWP(); -static void json_print_PAG(); -static void json_print_PSI(); -static void json_print_LVM(); -static void json_print_MDD(); -static void json_print_DSK(); -static void json_print_NFM(); -static void json_print_NFC(); -static void json_print_NFS(); -static void json_print_NET(); -static void json_print_IFB(); -static void json_print_NUM(); -static void json_print_NUC(); -static void json_print_LLC(); -static void json_print_PRG(); -static void json_print_PRC(); -static void json_print_PRM(); -static void json_print_PRD(); -static void json_print_PRN(); -static void json_print_PRE(); +static void json_print_CPU(char *, struct sstat *, struct tstat *, int); +static void json_print_cpu(char *, struct sstat *, struct tstat *, int); +static void json_print_CPL(char *, struct sstat *, struct tstat *, int); +static void json_print_GPU(char *, struct sstat *, struct tstat *, int); +static void json_print_MEM(char *, struct sstat *, struct tstat *, int); +static void json_print_SWP(char *, struct sstat *, struct tstat *, int); +static void json_print_PAG(char *, struct sstat *, struct tstat *, int); +static void json_print_PSI(char *, struct sstat *, struct tstat *, int); +static void json_print_LVM(char *, struct sstat *, struct tstat *, int); +static void json_print_MDD(char *, struct sstat *, struct tstat *, int); +static void json_print_DSK(char *, struct sstat *, struct tstat *, int); +static void json_print_NFM(char *, struct sstat *, struct tstat *, int); +static void json_print_NFC(char *, struct sstat *, struct tstat *, int); +static void json_print_NFS(char *, struct sstat *, struct tstat *, int); +static void json_print_NET(char *, struct sstat *, struct tstat *, int); +static void json_print_IFB(char *, struct sstat *, struct tstat *, int); +static void json_print_NUM(char *, struct sstat *, struct tstat *, int); +static void json_print_NUC(char *, struct sstat *, struct tstat *, int); +static void json_print_LLC(char *, struct sstat *, struct tstat *, int); +static void json_print_PRG(char *, struct sstat *, struct tstat *, int); +static void json_print_PRC(char *, struct sstat *, struct tstat *, int); +static void json_print_PRM(char *, struct sstat *, struct tstat *, int); +static void json_print_PRD(char *, struct sstat *, struct tstat *, int); +static void json_print_PRN(char *, struct sstat *, struct tstat *, int); +static void json_print_PRE(char *, struct sstat *, struct tstat *, int); /* ** table with possible labels and the corresponding @@ -559,7 +560,7 @@ "\"nrsect\": %lld, " "\"nwrite\": %lld, " "\"nwsect\": %lld, " - "\"avque\": %lld}, " + "\"avque\": %lld, " "\"inflight\": %lld}", ss->dsk.lvm[i].name, ss->dsk.lvm[i].io_ms, @@ -1027,6 +1028,8 @@ "\"isproc\": %d, " "\"rundelay\": %lld, " "\"blkdelay\": %lld, " + "\"nvcsw\": %llu, " + "\"nivcsw\": %llu, " "\"sleepavg\": %d}", ps->gen.pid, ps->cpu.utime, @@ -1038,6 +1041,8 @@ !!ps->gen.isproc, ps->cpu.rundelay/1000000, ps->cpu.blkdelay*1000/hertz, + ps->cpu.nvcsw, + ps->cpu.nivcsw, ps->cpu.sleepavg); } diff -Nru atop-2.8.1/Makefile atop-2.9.0/Makefile --- atop-2.8.1/Makefile 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/Makefile 2023-05-13 08:20:27.000000000 +0000 @@ -20,11 +20,11 @@ PMPATH2 = /usr/lib64/pm-utils/sleep.d PMPATHD = /usr/lib/systemd/system-sleep -CFLAGS += -O2 -I. -Wall -Wno-stringop-truncation # -DNOPERFEVENT # -DHTTPSTATS +CFLAGS += -O2 -I. -Wall -Wno-stringop-truncation -Wmissing-prototypes -Wmissing-declarations # -DNOPERFEVENT # -DHTTPSTATS OBJMOD0 = version.o OBJMOD1 = various.o deviate.o procdbase.o OBJMOD2 = acctproc.o photoproc.o photosyst.o rawlog.o ifprop.o parseable.o -OBJMOD3 = showgeneric.o showlinux.o showsys.o showprocs.o +OBJMOD3 = showgeneric.o drawbar.o showlinux.o showsys.o showprocs.o OBJMOD4 = atopsar.o netatopif.o gpucom.o json.o ALLMODS = $(OBJMOD0) $(OBJMOD1) $(OBJMOD2) $(OBJMOD3) $(OBJMOD4) @@ -48,7 +48,7 @@ $(CC) atopcat.o -o atopcat $(LDFLAGS) clean: - rm -f *.o atop atopsar atopacctd atopconvert atopcat + rm -f *.o atop atopsar atopacctd atopconvert atopcat versdate.h distr: rm -f *.o atop @@ -197,6 +197,7 @@ showlinux.o: atop.h photoproc.h photosyst.h showgeneric.h showlinux.h showsys.o: atop.h photoproc.h photosyst.h showgeneric.h showprocs.o: atop.h photoproc.h photosyst.h showgeneric.h showlinux.h +drawbar.o: atop.h photosyst.h showgeneric.h version.o: version.c version.h versdate.h gpucom.o: atop.h photoproc.h photosyst.h diff -Nru atop-2.8.1/man/atop.1 atop-2.9.0/man/atop.1 --- atop-2.8.1/man/atop.1 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/man/atop.1 2023-05-13 08:20:27.000000000 +0000 @@ -1,68 +1,226 @@ -.TH ATOP 1 "December 2022" "Linux" +.TH ATOP 1 "April 2023" "Linux" .SH NAME .B atop - Advanced System & Process Monitor + .SH SYNOPSIS -Interactive Usage: -.P -.B atop -[\-g|\-m|\-d|\-n|\-u|\-p|\-s|\-c|\-v|\-o|\-y|\-Y] [\-C|\-M|\-D|\-N|\-A] [\-afFG1xR] [\-L linelen] [\-Plabel[,label]... [-Z] [\-Jlabel[,label]...] -[ -.I interval -[ -.I samples -]] -.P -Writing and reading raw logfiles: -.P -.B atop -\-w -.I rawfile -[\-a] [\-S] -[ -.I interval -[ -.I samples -]] -.br -.B atop -\-r [ -.I rawfile -] [\-b -.I [YYYYMMDD]hhmm -] [\-e -.I [YYYYMMDD]hhmm -] [\-g|\-m|\-d|\-n|\-u|\-p|\-s|\-c|\-v|\-o|\-y|\-Y] [\-C|\-M|\-D|\-N|\-A] [\-fFG1xR] [\-L linelen] [\-Plabel[,label]... [-Z] [\-Jlabel[,label]...] +Live measurement in bar graph mode: +.PP +.TP 5 +.B \ atop -B[H] [interval [samples]] +.PP +Live measurement in text mode: +.PP +.TP 5 +.B \ atop [\-g|\-m|\-d|\-n|\-u|\-p|\-s|\-c|\-v|\-o|\-y|\-Y] [\-C|\-M|\-D|\-N|\-A] [\-fFG1xR] [interval [samples]] +.PP +Live generation of parsable output (white-space separated or JSON): +.PP +.TP 5 +.B \ atop [\-Plabel[,label]... [-Z]] [\-Jlabel[,label]...] [interval [samples]] +.PP +Write raw log files: +.PP +.TP 5 +.B \ atop \-w rawfile [\-a] [\-S] [interval [samples]] +.PP +Analyze raw log files in bar graph mode: +.PP +.TP 5 +.B \ atop \-B[H]r [rawfile|yyy...] [\-b [YYYYMMDD]hhmm] [\-e [YYYYMMDD]hhmm] +.PP +Analyze raw log files in text mode: +.PP +.TP 5 +.B \ atop \-r [rawfile|yyy...] [\-b [YYYYMMDD]hhmm] [\-e [YYYYMMDD]hhmm] [\-g|\-m|\-d|\-n|\-u|\-p|\-s|\-c|\-v|\-o|\-y|\-Y] [\-C|\-M|\-D|\-N|\-A] [\-fFG1xR] +.PP +Generate parsable output from raw log files (white-space separated or JSON): +.PP +.TP 5 +.B \ atop \-r [rawfile|yyy...] [\-b [YYYYMMDD]hhmm] [\-e [YYYYMMDD]hhmm] [\-Plabel[,label]... [-Z]] [\-Jlabel[,label]...] + .SH DESCRIPTION The program .I atop is an interactive monitor to view the load on a Linux system. -It shows the occupation of the most critical hardware resources -(from a performance point of view) on system level, i.e. cpu, memory, disk -and network. -.br -It also shows which processes are responsible for the indicated -load with respect to cpu and memory load on process level. -Disk load is shown per process if "storage accounting" is active in the kernel. -Network load is shown per process if the kernel module `netatop' -has been installed. -.PP -The initial screen shows if +Every +.I interval +seconds (default: 10 seconds) information is gathered about the +resource occupation on system level of the most critical hardware +resources (from a performance point of view), +i.e. CPUs, memory, disks and network interfaces. Besides, +information is gathered about the processes (or threads) that +are responsible for the utilization of the CPUs, memory and disks. +Network load per process is shown only when the +.I netatop +kernel module has been installed. +.SH BAR GRAPH MODE +When running .I atop -runs with restricted view (unprivileged) or unrestricted view (privileged). -In case of restricted view +you can choose to view the system load in bar graph mode or in text mode. +In bar graph mode the resource utilization of CPUs, memory, disks and network +interfaces is shown via (character-based) bar graphs, but only on system level. +When you want to view more detailed information on system level or when you +want to view the resource consumption on process or thread level, you can switch +to text mode by pressing the 'B' key. Alternatively, you can use the 'B' key +(again) to switch from text mode to bar graph mode. +.br +By default, .I atop -does not have the privileges (root identity or necessary capabilities) to -retrieve all counter values on system level and on process level. +starts in text mode unless the +.I -B +flag is used or unless 'B' has been configured as a default flag in the +.I .atoprc +file (for further information about default flags, refer to the +.B atoprc +man page). .PP -Every -.I interval -(default: 10 seconds) information is shown about the resource occupation -on system level (cpu, memory, disks and network layers), followed -by a list of processes which have been active during the last interval -(note that all processes that were unchanged during the last interval +In bar graph mode the terminal will be subdivided into four character-based +windows, i.e. one window for each hardware resource: +.PP +.TP 5 +.B Processors +The first bar shows the average busy percentage of all CPUs with +the bar label 'Avg' (might be abbreviated to 'Av' or even just 'A'). +The subsequent bars show the busy percentages of single CPUs. +.br +When there is not enough horizontal space to show all CPUs, only the +most busy CPUs per sample will be shown after the width of each bar +has been reduced to a minimum. + +By default, the categories of CPU consumption are shown by different +colors in the bars, marked with a character 'S' (system mode), 'U' +(user mode), 'I' (interrupt handling), 's' (steal) and 'G' +(guest, i.e. consumed by virtual machines). +.br +The top of the bar might consist of an unmarked color representing +a 'neutral' category. Suppose that the scale unit is 5% per line +and the total busy percentage is 54% consisting of two categories of 27%. +The two categories will be rounded to 25% (5 lines of 5% each) but the +total busy percentage will be rounded to 55% (11 lines of 5%). +Then the top line will represent a 'neutral' category. +.br +By pressing the 'H' key or by starting +.I atop +with the '-H' flag, no categories are shown. + +A red line is drawn in the bar graph as critical threshold. +By default this value is 90% and can be modified by the 'cpucritperc' +option in the configuration file (see separate +.B atoprc +man page). When this value is set to zero, no threshold line will be drawn. +.TP 5 +.B Memory and swap space +Memory is presented as a column in which the +specific categories of memory consumption are shown. These categories +are (code, data and stack of) processes/kernel, slab caches +(i.e. dynamically allocated kernel memory), shared memory, tmpfs, +page cache and free memory. +.br +Swap space (if present) is also presented as a column in which the +categories processes/tmpfs, shared memory and free space are shown. + +At the right side memory-related event counters are shown. +.br +The bottom three counters are colored green when there is no memory pressure. +When considerable activity is noticed such counter might be colored orange and +with high activity red. +.br +When memory pressure starts, usually memory page scanning will be activated +first. When pressure increases, memory pages of processes might be swapped +out to swap space (if present). +.br +The 'oomkills' counter (Out Of Memory killing) is most serious: +it reflects the number of processes that are killed due to lack of memory +(and swap). Therefore this counter shows the absolute number (not per second) +of processes being killed during the last interval and will immediately +be colored red when it is 1 or more. Besides, after +.I atop +has noticed OOM killing the 'oomkills' counter remains orange for the next +15 minutes, just in case that you have missed the OOM killing event itself. +.br +When there is enough vertical space in the memory window, event counters +are shown about the number of memory pages being swapped in, +the number of memory pages paged out to block devices and +the number of memory pages paged in from block devices. + +Memory and swap space consumption will preferably be shown in a +character-based window that vertically uses the entire screen for +optimal granularity. However, when there are a lot of disks and/or +network interfaces the memory and swap space consumption will be shown +in a character-based window that only uses the upper half of the screen. +.TP 5 +.B Disks +For each disk the busy percentage is shown as a bar. +.br +When there is not enough horizontal space to show all disks, only the +most busy disks per sample will be shown. + +By default, categories of disk consumption are shown by different colors +in the bars, marked with a character 'R' (read) and 'W' +(write). +.br +The top of the bar might consist of an unmarked color representing +a 'neutral' category. Suppose that the scale unit is 5% per line +and the total busy percentage is 54% consisting of two categories of 27%. +The two categories will be rounded to 25% (5 lines of 5% each) but the +total busy percentage will be rounded to 55% (11 lines of 5%). +Then the top line will represent a 'neutral' category. +.br +By pressing the 'H' key or by starting +.I atop +with the '-H' flag, no categories are shown. + +A red line is drawn in the bar graph as critical threshold. +By default this value is 90% and can be modified by the 'dskcritperc' +option in the configuration file (see separate +.B atoprc +man page). When this value is set to zero, no threshold line will be drawn. +.TP 5 +.B Interfaces +For each non-virtual network interface a double bar graph is shown with +a dedicated scale that reflects the traffic rate. One of the bars shows +the transmit rate ('TX') and the other bar the receive rate ('RX'). +The traffic scale of each network interface remains at its highest level. +All interface scales can be reset during the measurement by pressing +the 'L' key. + +Most often the real speed (maximum bandwidth) of network interfaces is +not known, e.g. in case of the network interfaces of virtual machines. +Therefore it is not possible to show the interface utilization as a +percentage. However, when the real speed of an interface is known it will +be shown underneath the concerning bar graph. + +When there is not enough horizontal space to show all network interfaces, +only the most busy interfaces per sample will be shown. +.PP +Usually the bar graphs will not be sorted on busy percentage when there +is enough horizontal space. However, after switching from text mode to +bar graph mode the bar graphs might have been sorted because this was +needed for the presentation in text mode. The next interval in bar graph +mode shows the bars unsorted again unless the window width is unsufficient +for all bars. +.PP +The remaining part of this manual page mainly describes the information +shown in text mode. +When certain descriptions also apply to bar graph mode it will be +mentioned explicitly. + +.SH TEXT MODE IN GENERAL +The initial screen in text mode shows if +.I atop +runs with restricted view (unprivileged user) or unrestricted view +(privileged user). In case of restricted view +.I atop +does not have the privileges (no root identity nor the necessary capabilities) +to retrieve all counter values on system level and on process level. +.PP +With every interval information is shown about the resource occupation +on system level (CPU, memory, disks and network layers), followed +by a list of processes which have been active during the last interval. +Notice that all processes that were unchanged during the last interval are not shown, unless the key 'a' has been pressed or unless sorting on -memory occupation is done). +memory occupation is done (then inactive processes are relevant as well). If the list of active processes does not entirely fit on the screen, only the top of the list is shown (sorted in order of activity). .br @@ -76,7 +234,7 @@ is started, it checks whether the standard output channel is connected to a screen, or to a file/pipe. In the first case it produces screen control codes (via the ncurses library) and behaves interactively; in the second case -it produces flat ASCII-output. +it produces flat text output. .PP In interactive mode, the output of .I atop @@ -90,14 +248,14 @@ If the window is resized vertically, lines of the process/thread list will be added or removed automatically. .PP -Furthermore in interactive mode the output of +In interactive mode the output of .I atop can be controlled by pressing particular keys. However it is also possible to specify such key as .B flag on the command line. In that case .I atop -switches to the indicated mode on beforehand; this mode can +switches to the indicated mode on beforehand. This mode can be modified again interactively. Specifying such key as flag is especially useful when running .I atop @@ -112,9 +270,9 @@ .I atop reads the kernel administration to obtain information about all running processes. -However, it is likely that during the interval also processes have terminated. +However, it is likely that processes have terminated during the interval. These processes might have consumed system resources during -this interval as well before they terminated. +this interval before they terminated. Therefore, .I atop tries to read the process accounting records that contain the accounting @@ -212,10 +370,10 @@ process is alive. Whenever the last .I atop -process stops (either by pressing `q' or by `kill \-15'), it deactivates the +process stops (either by pressing 'q' or by 'kill \-15'), it deactivates the process accounting mechanism again. Therefore you should never terminate .I atop -by `kill \-9', because then it has no chance to stop process accounting. +by 'kill \-9', because then it has no chance to stop process accounting. As a result, the accounting file may consume a lot of disk space after a while. .br @@ -239,30 +397,30 @@ .I atop does not run with root-privileges, it does not show information about finished processes. -It indicates this situation with the message -message `no procacct` in the top-right corner (instead of the counter that +It indicates this situation with the +message 'no procacct' in the top-right corner (instead of the counter that shows the number of exited processes). .PP When during one interval a lot of processes have finished, .I atop might grow tremendously in memory when reading all process accounting -records at the end of the interval. To avoid such excessive growth, +records at the end of the interval. To avoid such excessive growth .I atop will never read more than 50 MiB with process information from the -process accounting file per interval (approx. 70000 finished processes). +process accounting file per interval (approx. 54000 finished processes). In interactive mode a warning is given whenever processes have been skipped for this reason. .PP .SH COLORS For the resource consumption on system level, .I atop -uses colors to indicate that a critical occupation percentage has -been (almost) reached. +uses colors in text mode to indicate that a critical occupation +percentage has been (almost) reached. A critical occupation percentage means that is likely that this load causes a noticeable negative performance influence for applications using this resource. The critical percentage depends on the type of resource: e.g. the performance influence of a disk with a busy percentage of 80% -might be more noticeable for applications/user than a CPU with a busy +might be more noticeable for applications/users than a CPU with a busy percentage of 90%. .br Currently @@ -272,56 +430,64 @@ .PP .TP 5 .B \ Processor -A busy percentage of 90% or higher is considered `critical'. +A busy percentage of 90% or higher is considered 'critical' +(also in bar graph mode). .TP 5 .B \ Disk -A busy percentage of 70% or higher is considered `critical'. +A busy percentage of 90% or higher is considered 'critical'. .TP 5 .B \ Network A busy percentage of 90% or higher for the load of an interface is -considered `critical'. +considered 'critical'. .TP 5 .B \ Memory -An occupation percentage of 90% is considered `critical'. +An occupation percentage of 90% is considered 'critical'. Notice that this occupation percentage is the accumulated memory -consumption of the kernel (including slab) and all processes; the -memory for the page cache (`cache' and `buff' in the MEM-line) and the -reclaimable part of the slab (`slrec`) is not implied! -.br -If the number of pages swapped out (`swout' in the PAG-line) is larger -than 10 per second, the memory resource is considered `critical'. -A value of at least 1 per second is considered `almost critical'. +consumption of the kernel (including slab) and all processes. The +memory for the page cache ('cache' and 'buff' in the MEM-line) and the +reclaimable part of the slab ('slrec') is not implied! +.br +If the number of pages swapped out ('swout' in the PAG-line) is larger +than 10 per second, the memory resource is considered 'critical'. +A value of at least 1 per second is considered 'almost critical'. .br -If the committed virtual memory exceeds the limit (`vmcom' and `vmlim' +If the committed virtual memory exceeds the limit ('vmcom' and 'vmlim' in the SWP-line), the SWP-line is colored due to overcommitting the system. .TP 5 .B \ Swap -An occupation percentage of 80% is considered `critical' -because swap space might be completely exhausted in the near future; -it is not critical from a performance point-of-view. +An occupation percentage of 80% is considered 'critical' +because swap space might be completely exhausted in the near future. +It is not critical from a performance point-of-view. .PP These default values can be modified in the configuration file -(see separate man-page of atoprc). +(see separate +.B atoprc +man page). .PP When a resource exceeds its critical occupation percentage, the concerning values in the screen line are colored red by default. .br -When a resource exceeded (default) 80% of its critical percentage +When a resource exceeds (by default) 80% of its critical percentage (so it is almost critical), the concerning values in the screen line -are colored cyan by default. This `almost critical percentage' (one value -for all resources) can be modified in the configuration file -(see separate man-page of atoprc). +are colored cyan by default. This 'almost critical percentage' (one value +for all resources) can be also modified in the configuration file +(see separate +.B atoprc +man page). .br The default colors red and cyan can be modified in the configuration file -as well (see separate man-page of atoprc). +as well (see separate +.B atoprc +man page). .PP -With the key 'x' (or flag \-x), the use of colors can be suppressed. +With the key 'x' (or flag \-x), the use of colors can be suppressed +in text mode. The use of colors is however mandatory in case of bar graph mode. .SH NETATOP MODULE Per-process and per-thread network activity can be measured by the .I netatop kernel module. You can download this kernel module from the website (mentioned at the end of this manual page) and install it on your -system if the kernel version is 2.6.24 or newer. +system. .br When .I atop @@ -332,7 +498,7 @@ obtains the relevant network counters from this module and shows the number of sent and received packets per process/thread in the generic screen. Besides, detailed counters can be requested by -pressing the `n' key. +pressing the 'n' key. .br When the .I netatopd @@ -362,19 +528,14 @@ The .I atopgpud daemon is written in Python, so a Python interpreter should be installed -on the target system. The Python code of the daemon is compatible with -Python version 2 and version 3. +on the target system. For the gathering of the statistics, the .I pynvml module is used by the daemon. Be sure that this module is installed on the target system before activating the daemon, by running the -command as root -.I pip -(the command +command .I pip -might be exchanged by -.I pip3 -in case of Python3): +as root user: .PP .B \ pip install nvidia-ml-py .PP @@ -398,8 +559,10 @@ .I atop interactively (no output redirection), keys can be pressed to control the output. In general, lower case keys can be used to show other information for -the active processes and upper case keys can be used to influence the -sort order of the active process/thread list. +the active processes while certain upper case keys can be used to influence the +sort order of the active process/thread list. Some of these keys can also +be used to switch from bar graph mode to particular detailed process information +in text mode. .PP .TP 5 .B g @@ -407,24 +570,20 @@ Per process the following fields are shown in case of a window-width of 80 positions: -process-id, cpu consumption during +process-id, CPU consumption during the last interval in system and user mode, the virtual and resident memory growth of the process. - -The subsequent columns depend on the used kernel: .br -When the kernel supports "storage accounting" (>= 2.6.20), the data -transfer for read/write on disk, the status and exit code are -shown for each process. -When the kernel does not support -"storage accounting", the username, number of threads in the -thread group, the status and exit code are shown. +The data transfer per process for read/write on disk can only be shown +when +.I atop +runs with root privileges. .br When the kernel module 'netatop' is loaded, the data transfer for send/receive of network packets is shown for each process. .br The last columns contain the state, the occupation percentage for the -chosen resource (default: cpu) and the process name. +chosen resource (default: CPU) and the process name. When more than 80 positions are available, other information is added. .PP @@ -432,7 +591,7 @@ .B m Show memory related output. -Per process the following fields are shown in case of a window-width +Per process the following fields are shown in case of a window width of 80 positions: process-id, minor and major memory faults, size of virtual shared text, total virtual @@ -448,8 +607,9 @@ .B d Show disk-related output. -When "storage accounting" is active in the kernel, the following -fields are shown: +When +.I atop +runs with root privileges, the following fields are shown: process-id, amount of data read from disk, amount of data written to disk, amount of data that was written but has been withdrawn again (WCANCL), disk occupation percentage and process name. @@ -458,7 +618,7 @@ .B n Show network related output. -Per process the following fields are shown in case of a window-width +Per process the following fields are shown in case of a window width of 80 positions: process-id, thread-id, total bandwidth for received packets, @@ -469,7 +629,7 @@ number of sent UDP packets with the average size per packet (in bytes), the network occupation percentage and process name. .br -This information can only be shown when kernel module `netatop' is installed. +This information can only be shown when kernel module 'netatop' is installed. When more than 80 positions are available, other information is added. .PP @@ -477,7 +637,7 @@ .B s Show scheduling characteristics. -Per process the following fields are shown in case of a window-width +Per process the following fields are shown in case of a window width of 80 positions: process-id, number of threads in state 'running' (R), @@ -494,7 +654,7 @@ .B v Show various process characteristics. -Per process the following fields are shown in case of a window-width +Per process the following fields are shown in case of a window width of 80 positions: process-id, user name and group, start date and time, status (e.g. exit code if the process has finished), @@ -515,15 +675,14 @@ Show cgroup v2 information. Per process the following fields are shown: -process-id, -`cpu.weight' of the cgroup the process belongs to, -`cpu.max' value (recalculated as percentage) of the cgroup the process belongs to, -most restrictive `cpu.max' value found in the upper directories, -`memory.max' value of the cgroup the process belongs to, -most restrictive `memory.max' value found in the upper directories, -`memory.swap.max' value of the cgroup the process belongs to, -most restrictive `memory.swap.max' value found in the upper directories, -the command name, and +process-id, 'cpu.weight' of the cgroup the process +belongs to, 'cpu.max' value (recalculated as percentage) of the cgroup +the process belongs to, most restrictive 'cpu.max' value found in the +upper directories, 'memory.max' value of the cgroup the process belongs to, +most restrictive 'memory.max' value found in the upper +directories, 'memory.swap.max' value of the cgroup the process belongs to, +most restrictive 'memory.swap.max' value found in the +upper directories, the command name, and the cgroup path name (horizontally scrollable). .PP .TP 5 @@ -584,59 +743,65 @@ Show the process activity accumulated per user. Per user the following fields are shown: number of processes active -or terminated during last interval (or in total if combined with command `a'), -accumulated cpu consumption during last interval in system and user mode, +or terminated during last interval (or in total if combined with command 'a'), +accumulated CPU consumption during last interval in system and user mode, the current virtual and resident memory space consumed by active processes -(or all processes of the user if combined with command `a'). +(or all processes of the user if combined with command 'a'). .br -When "storage accounting" is active in the kernel, +When +.I atop +runs with root privileges, the accumulated read and write throughput on disk is shown. -When the kernel module `netatop' has been installed, -the number of received and sent network packets are shown. +When the kernel module 'netatop' has been installed, +the accumulated number of received and sent network packets is shown. .br The last columns contain the accumulated occupation percentage for the -chosen resource (default: cpu) and the user name. +chosen resource (default: CPU) and the user name. .PP .TP 5 .B p Show the process activity accumulated per program (i.e. process name). Per program the following fields are shown: number of processes active -or terminated during last interval (or in total if combined with command `a'), -accumulated cpu consumption during last interval in system and user mode, +or terminated during last interval (or in total if combined with command 'a'), +accumulated CPU consumption during last interval in system and user mode, the current virtual and resident memory space consumed by active processes -(or all processes of the user if combined with command `a'). +(or all processes of the user if combined with command 'a'). .br -When "storage accounting" is active in the kernel, +When +.I atop +runs with root privileges, the accumulated read and write throughput on disk is shown. -When the kernel module `netatop' has been installed, -the number of received and sent network packets are shown. +When the kernel module 'netatop' has been installed, +the accumulated number of received and sent network packets is shown. .br The last columns contain the accumulated occupation percentage for the -chosen resource (default: cpu) and the program name. +chosen resource (default: CPU) and the program name. .PP .TP 5 .B j Show the process activity accumulated per Docker container. Per container the following fields are shown: number of processes active -or terminated during last interval (or in total if combined with command `a'), -accumulated cpu consumption during last interval in system and user mode, +or terminated during last interval (or in total if combined with command 'a'), +accumulated CPU consumption during last interval in system and user mode, the current virtual and resident memory space consumed by active processes -(or all processes of the user if combined with command `a'). +(or all processes of the user if combined with command 'a'). .br -When "storage accounting" is active in the kernel, +When +.I atop +runs with root privileges, the accumulated read and write throughput on disk is shown. -When the kernel module `netatop' has been installed, -the number of received and sent network packets are shown. +When the kernel module 'netatop' has been installed, +the accumulated number of received and sent network packets is shown. .br The last columns contain the accumulated occupation percentage for the -chosen resource (default: cpu) and the Docker container id (CID). +chosen resource (default: CPU) and the Docker container id (CID). .PP .TP 5 .B C -Sort the current list in the order of cpu consumption (default). -The one-but-last column changes to ``CPU''. +Sort the current list in the order of CPU consumption (default). +The one-but-last column changes to 'CPU'. .PP .TP 5 .B E @@ -646,30 +811,30 @@ .I atopgpud daemon runs under root privileges) or the order of GPU memory occupation). -The one-but-last column changes to ``GPU''. +The one-but-last column changes to 'GPU'. .PP .TP 5 .B M Sort the current list in the order of resident memory consumption. -The one-but-last column changes to ``MEM''. In case of sorting on memory, +The one-but-last column changes to 'MEM'. In case of sorting on memory, the full process list will be shown (not only the active processes). .PP .TP 5 .B D Sort the current list in the order of disk accesses issued. -The one-but-last column changes to ``DSK''. +The one-but-last column changes to 'DSK'. .PP .TP 5 .B N Sort the current list in the order of network bandwidth (received and transmitted). -The one-but-last column changes to ``NET''. +The one-but-last column changes to 'NET'. .PP .TP 5 .B A Sort the current list automatically in the order of the most busy system resource during this interval. -The one-but-last column shows either ``ACPU'', ``AMEM'', ``ADSK'' or ``ANET'' +The one-but-last column shows either 'ACPU', 'AMEM', 'ADSK' or 'ANET' (the preceding 'A' indicates automatic sorting-order). The most busy resource is determined by comparing the weighted busy-percentages of the system resources, as described earlier in @@ -678,8 +843,11 @@ This option remains valid until another sorting-order is explicitly selected again. .br -A sorting-order for disk is only possible when "storage accounting" is active. -A sorting-order for network is only possible when the kernel module `netatop' +A sorting order for disk is only possible when +.I atop +runs with root privileges. +.br +A sorting order for network is only possible when the kernel module 'netatop' is loaded. .PP Miscellaneous interactive commands: @@ -721,12 +889,16 @@ information about the current list of processes. Whenever the pause key is pressed again, atop will continue with a next sample. +.br +The pause key can be used in text mode and bar graph mode. .PP .TP 5 .B i Modify the interval timer (default: 10 seconds). If an interval timer of 0 is entered, the interval timer is switched off. In that case a new sample can only be triggered manually by pressing the key 't'. +.br +The interval can be modified in text mode and bar graph mode. .PP .TP 5 .B t @@ -737,6 +909,8 @@ can be used as a stopwatch to measure the load being caused by a particular application transaction, without knowing on beforehand how many seconds this transaction will last. +.br +This key can be used in text mode and bar graph mode. When viewing the contents of a raw file this key can be used to show the next sample from the file. This key can also be used when viewing raw data @@ -746,17 +920,23 @@ .B T When viewing the contents of a raw file this key can be used to show the previous sample from the file, however not when reading raw data from a pipe. +.br +This key can be used in text mode and bar graph mode. .PP .TP 5 .B b When viewing the contents of a raw file, this key can be used to branch to a certain timestamp within the file either forward or backward. When viewing raw data from a pipe only forward branches are possible. +.br +This key can be used in text mode and bar graph mode. .PP .TP 5 .B r Reset all counters to zero to see the system and process activity since boot again. +.br +This key can be used in text mode and bar graph mode. When viewing the contents of a raw file, this key can be used to rewind to the beginning of the file again (except when reading raw data from a pipe). @@ -843,7 +1023,7 @@ .PP .TP 5 .B a -The `all/active' key can be used to toggle between only showing/accumulating +The 'all/active' key can be used to toggle between only showing/accumulating the processes that were active during the last interval (default) or showing/accumulating all processes. .br @@ -881,7 +1061,7 @@ .PP .TP 5 .B 1 -Show relevant counters as an average per second (in the format `..../s') +Show relevant counters as an average per second (in the format '..../s') instead of as a total during the interval (toggle). .br Whether this key is active or not can be seen in the header line. @@ -912,6 +1092,8 @@ .TP 5 .B q Quit the program. +.br +This key can be used in text mode and bar graph mode. .PP .TP 5 .B PgDn @@ -952,9 +1134,10 @@ If this file already exists and is recognized as a raw data file, .I atop will append new samples to the file (starting with a sample which reflects -the activity since boot); if the file does not exist, it will be created. +the activity since boot). If the file does not exist, it will be created. .br -All information about processes and threads is stored in the raw file. +All information about system, processes and thread activity is stored in +the raw file. .br The interval (default: 10 seconds) and number of samples (default: infinite) can be passed as last arguments. Instead of the number of samples, the flag @@ -985,12 +1168,13 @@ The samples from the file can be viewed interactively by using the key 't' to show the next sample, the key 'T' to show the previous sample, the key 'b' to branch to a particular time or the key 'r' to rewind to -the begin of the file. +the begin of the file. These keys can be used in text mode as well as +in bar graph mode. .br When output is redirected to a file or pipe, .B atop prints all samples in plain ASCII. The default line length is 80 characters -in that case; with the flag +in that case. With the flag .B -L followed by an alternate line length, more (or less) columns will be shown. .br @@ -1029,7 +1213,7 @@ Unfortunately, it is not always possible to keep the format of the raw files compatible in newer versions of .B atop -especially when lots of new counters have to be maintained. +especially when many new counters have to be maintained. Therefore, the program .B atopconvert is installed to convert a raw file created by an older @@ -1044,49 +1228,47 @@ .SH OUTPUT DESCRIPTION The first sample shows the system level activity since boot (the elapsed time in the header shows the time since boot). -Note that particular counters could have reached their maximum -value (several times) and started by zero again, -so do not rely on these figures. -.PP -For every sample -.I atop -first shows the lines related to system level activity. If a particular -system resource has not been used during the interval, the entire line -related to this resource is suppressed. So the number of system level lines -may vary for each sample. +.PP +In text mode, +.I atop +first shows the lines related to system level activity for every sample. +If a particular system resource has not been used during the interval, +the entire line related to this resource is suppressed. So the number of +system level lines may vary for each sample. .br After that a list is shown of processes which have been active during the last -interval. This list is by default sorted on cpu consumption, but this order +interval. This list is sorted on CPU consumption by default, but this order can be changed by the keys which are previously described. .PP If values have to be shown by .I atop which do not fit in the column width, -another format is used. If e.g. a cpu-consumption of 233216 milliseconds -should be shown in a column width of 4 positions, it is shown as `233s' +another format is used. If e.g. a CPU consumption of 233216 milliseconds +should be shown in a column width of 4 positions, it is shown as '233s' (in seconds). For large memory figures, another unit is chosen if the value does not fit -(Mb instead of Kb, Gb instead of Mb, Tb instead of Gb, ...). +(Mb instead of Kb, Gb instead of Mb, Tb instead of Gb, etcetera). For other values, a kind of exponent notation is used (value 123456789 shown in a column of 5 positions gives 123e6). .SH OUTPUT DESCRIPTION - SYSTEM LEVEL -The system level information consists of the following output lines: +The system level information in text mode consists +of the following output lines: .PP .TP 5 .B PRC Process and thread level totals. .br -This line contains the total cpu time consumed -in system mode (`sys') and in user mode (`user'), -the total number of processes present at this moment (`#proc'), -the total number of threads present at this moment in state `running' (`#trun'), -`sleeping interruptible' (`#tslpi') and `sleeping uninterruptible' (`#tslpu'), -the number of zombie processes (`#zombie'), -the number of clone system calls (`clones'), and +This line contains the total CPU time consumed +in system mode ('sys') and in user mode ('user'), +the total number of processes present at this moment ('#proc'), +the total number of threads present at this moment in state 'running' +('#trun'), 'sleeping interruptible' ('#tslpi') and 'sleeping uninterruptible' ('#tslpu'), +the number of zombie processes ('#zombie'), +the number of clone system calls ('clones'), and the number of processes that ended during the interval -(`#exit') when process accounting is used. Instead of `#exit` the last +('#exit') when process accounting is used. Instead of '#exit' the last column may indicate that process accounting could not be activated -(`no procacct`). +('no procacct'). .br If the screen-width does not allow all of these counters, only a relevant subset is shown. @@ -1098,39 +1280,39 @@ At least one line is shown for the total occupation of all CPUs together. .br In case of a multi-processor system, an additional line is shown -for every individual processor (with `cpu' in lower case), +for every individual processor (with 'cpu' in lower case), sorted on activity. Inactive CPUs will not be shown by default. -The lines showing the per-cpu occupation contain the cpu number in +The lines showing the per-cpu occupation contain the CPU number in the field combined with the wait percentage. -Every line contains the percentage of cpu time spent in -kernel mode by all active processes (`sys'), -the percentage of cpu time consumed in user mode (`user') for all +Every line contains the percentage of CPU time spent in +kernel mode by all active processes ('sys'), +the percentage of CPU time consumed in user mode ('user') for all active processes (including processes running with a nice value larger than -zero), the percentage of cpu time spent for interrupt handling (`irq') -including softirq, the percentage of unused cpu time while no processes -were waiting for disk I/O (`idle'), and -the percentage of unused cpu time while at least one process was waiting -for disk I/O (`wait'). +zero), the percentage of CPU time spent for interrupt handling ('irq') +including softirq, the percentage of unused CPU time while no processes +were waiting for disk I/O ('idle'), and +the percentage of unused CPU time while at least one process was waiting +for disk I/O ('wait'). .br -In case of per-cpu occupation, the cpu number and -the wait percentage (`w') for that cpu. +In case of per-cpu occupation, the CPU number and +the wait percentage ('w') for that CPU. The number of lines showing the per-cpu occupation can be limited. -For virtual machines, the steal-percentage (`steal') shows -the percentage of cpu time stolen by other virtual machines +For virtual machines, the steal-percentage ('steal') shows +the percentage of CPU time stolen by other virtual machines running on the same hardware. .br For physical machines hosting one or more virtual machines, -the guest-percentage (`guest') shows -the percentage of cpu time used by the virtual machines. Notice that +the guest percentage ('guest') shows +the percentage of CPU time used by the virtual machines. Notice that this percentage overlaps the user percentage! When PMC performance monitoring counters are supported by the CPU and the kernel (and .I atop runs with root privileges), the number of instructions per -CPU cycle (`ipc') is shown. +CPU cycle ('ipc') is shown. The first sample always shows the value 'initial', because the counters are just activated at the moment that .I atop @@ -1148,7 +1330,7 @@ it is likely that the CPU is instruction-bound (more/faster cores might be helpful to improve performance). .br -Furthermore, per CPU the effective number of cycles (`cycl') is shown. +Furthermore, per CPU the effective number of cycles ('cycl') is shown. This value can reach the current CPU frequency if such CPU is 100% busy. When an idle CPU is halted, the number of effective cycles can be (considerably) lower than the current frequency. @@ -1166,23 +1348,22 @@ .br See also: http://www.brendangregg.com/blog/2017-05-09/cpu-utilization-is-wrong.html - In case of frequency scaling, all previously mentioned CPU percentages are relative to the used scaling of the CPU during the interval. If a CPU has been active for e.g. 50% in user mode during the interval while the frequency scaling of that CPU was 40%, only 20% of the full capacity of the CPU has been used in user mode. .br -In case that the kernel module `cpufreq_stats' is active -(after issuing `modprobe cpufreq_stats'), the +In case that the kernel module 'cpufreq_stats' is active +(after issuing 'modprobe cpufreq_stats'), the .I average -frequency (`avgf') and the +frequency ('avgf') and the .I average -scaling percentage (`avgscal') is shown. Otherwise the +scaling percentage ('avgscal') is shown. Otherwise the .I current -frequency (`curf') and the +frequency ('curf') and the .I current -scaling percentage (`curscal') is shown at the moment that the sample +scaling percentage ('curscal') is shown at the moment that the sample is taken. Notice that .I average @@ -1202,10 +1383,10 @@ This line contains the load average figures reflecting the number of threads that are available to run on a CPU (i.e. part of the runqueue) or that are waiting for disk I/O. These figures are averaged over -1 (`avg1'), 5 (`avg5') and 15 (`avg15') minutes. +1 ('avg1'), 5 ('avg5') and 15 ('avg15') minutes. .br -Furthermore the number of context switches (`csw'), the number -of serviced interrupts (`intr') and the number of available CPUs are shown. +Furthermore the number of context switches ('csw'), the number +of serviced interrupts ('intr') and the number of available CPUs are shown. If the screen-width does not allow all of these counters, only a relevant subset is shown. @@ -1222,12 +1403,12 @@ In the first column of every line, the bus-id (last nine characters) and the GPU number are shown. The subsequent columns show the percentage of time that one or more kernels -were executing on the GPU (`gpubusy'), the percentage of time that global -(device) memory was being read or written (`membusy'), the occupation -percentage of memory (`memocc'), the total memory (`total'), the memory -being in use at the moment of the sample (`used'), the average memory -being in use during the sample time (`usavg'), the number of processes -being active on the GPU at the moment of the sample (`#proc'), and +were executing on the GPU ('gpubusy'), the percentage of time that global +(device) memory was being read or written ('membusy'), the occupation +percentage of memory ('memocc'), the total memory ('total'), the memory +being in use at the moment of the sample ('used'), the average memory +being in use during the sample time ('usavg'), the number of processes +being active on the GPU at the moment of the sample ('#proc'), and the type of GPU. If the screen-width does not allow all of these counters, @@ -1240,25 +1421,25 @@ Memory occupation (two lines). .br These lines contain the total amount of physical memory -(`tot'), the amount of memory which is currently free (`free'), +('tot'), the amount of memory which is currently free ('free'), the amount of memory in use as page cache including -the total resident shared memory (`cache'), the amount of memory within the -page cache that has to be flushed to disk (`dirty'), the amount -of memory used for filesystem meta data (`buff'), the amount of -memory being used for kernel mallocs (`slab'), the amount of -slab memory that is reclaimable (`slrec'), the resident size of shared -memory including tmpfs (`shmem'), the resident size of shared memory (`shrss') -the amount of shared memory that is currently swapped (`shswp'), -the amount of memory that is currently used for page tables (`pgtab'), -the number of NUMA nodes in this system (`numnode'), +the total resident shared memory ('cache'), the amount of memory within the +page cache that has to be flushed to disk ('dirty'), the amount +of memory used for filesystem meta data ('buff'), the amount of +memory being used for kernel mallocs ('slab'), the amount of +slab memory that is reclaimable ('slrec'), the resident size of shared +memory including tmpfs ('shmem'), the resident size of shared memory ('shrss') +the amount of shared memory that is currently swapped ('shswp'), +the amount of memory that is currently used for page tables ('pgtab'), +the number of NUMA nodes in this system ('numnode'), the amount of memory that is currently claimed by vmware's -balloon driver (`vmbal'), +balloon driver ('vmbal'), the amount of memory that is currently claimed by the ARC (cache) -of ZFSonlinux (`zfarc'), -the amount of memory that is claimed for huge pages (`hptot'), -the amount of huge page memory that is really in use (`hpuse'), -the amount of memory that is used for TCP sockets (`tcps'), and -the amount of memory that is used for UDP sockets (`udps'). +of ZFSonlinux ('zfarc'), +the amount of memory that is claimed for huge pages ('hptot'), +the amount of huge page memory that is really in use ('hpuse'), +the amount of memory that is used for TCP sockets ('tcps'), and +the amount of memory that is used for UDP sockets ('udps'). If the screen-width does not allow all of these counters, only a relevant subset is shown. @@ -1267,16 +1448,16 @@ .B SWP Swap occupation and overcommit info. .br -This line contains the total amount of swap space on disk (`tot'), -the amount of free swap space (`free'), -the size of the swap cache (`swcac'), -the total size of compressed storage in zswap (`zpool`), -the total size of the compressed pages stored in zswap (`zstor'), -the total size of the memory used for KSM (`ksuse`, i.e. shared), and -the total size of the memory saved (deduped) by KSM (`kssav`, i.e. sharing). +This line contains the total amount of swap space on disk ('tot'), +the amount of free swap space ('free'), +the size of the swap cache ('swcac'), +the total size of compressed storage in zswap ('zpool'), +the total size of the compressed pages stored in zswap ('zstor'), +the total size of the memory used for KSM ('ksuse', i.e. shared), and +the total size of the memory saved (deduped) by KSM ('kssav', i.e. sharing). .br -Furthermore the committed virtual memory space (`vmcom') and the maximum -limit of the committed space (`vmlim', which is by default swap size +Furthermore the committed virtual memory space ('vmcom') and the maximum +limit of the committed space ('vmlim', which is by default swap size plus 50% of memory size) is shown. The committed space is the reserved virtual space for all allocations of private memory space for processes. The kernel only verifies whether the @@ -1287,11 +1468,11 @@ .B LLC Last-Level Cache of CPU info. .br -This line contains the total memory bandwidth of LLC (`tot'), -the bandwidth of the local NUMA node (`loc'), and -the percentage of LLC in use (`LLCXX YY%'). +This line contains the total memory bandwidth of LLC ('tot'), +the bandwidth of the local NUMA node ('loc'), and +the percentage of LLC in use ('LLCXX YY%'). -Note that this feature depends on the `resctrl` pseudo filesystem. +Note that this feature depends on the 'resctrl' pseudo filesystem. Be sure that the kernel is built with the relevant config and take care that the pseudo-filesystem is mounted: @@ -1305,42 +1486,43 @@ .B NUM Memory utilization per NUMA node (not shown for single NUMA node). .br -This line shows the total amount of physical memory of this node (`tot'), -the amount of free memory (`free'), the amount of memory for cached file data -(`file'), modified cached file data (`dirty'), recently used memory (`activ'), -less recently used memory (`inact'), memory being used for kernel mallocs -(`slab'), the amount of slab memory that is reclaimable (`slrec'), -shared memory including tmpfs (`shmem'), total huge pages (`hptot') and -the fragmentation percentage (`frag'). +This line shows the total amount of physical memory of this node ('tot'), +the amount of free memory ('free'), the amount of memory for cached file data +('file'), modified cached file data ('dirty'), recently used memory ('activ'), +less recently used memory ('inact'), memory being used for kernel mallocs +('slab'), the amount of slab memory that is reclaimable ('slrec'), +shared memory including tmpfs ('shmem'), total huge pages ('hptot') and +the fragmentation percentage ('frag'). .PP .TP 5 .B NUC CPU utilization per NUMA node (not shown for single NUMA node). .br This line shows the utilization percentages of all CPUs related to this -NUMA node, categorized for system mode (`sys'), user mode (`user'), -user mode for niced processes (`niced'), idle mode (`idle'), -wait mode (`w' preceded by the node number), irq mode (`irq'), -softirq mode (`sirq'), steal mode (`steal'), and guest mode (`guest') +NUMA node, categorized for system mode ('sys'), user mode ('user'), +user mode for niced processes ('niced'), idle mode ('idle'), +wait mode ('w' preceded by the node number), irq mode ('irq'), +softirq mode ('sirq'), steal mode ('steal'), and guest mode ('guest') overlapping user mode. .PP .TP 5 .B PAG Paging frequency. .br -This line contains the number of scanned pages (`scan') due to the fact -that free memory drops below a particular threshold, the number -times that the kernel tries to reclaim pages due to an urgent need (`stall'), -the number of process stalls to run memory compaction to allocate -huge pages (`compact'), the number of NUMA pages migrated (`numamig'), and -the total number of memory pages migrated successfully e.g. between -NUMA nodes or for compaction (`migrate') are shown. -.br -Also the number of memory pages the system read from block devices (`pgin'), -the number of memory pages the system wrote to block devices (`pgout'), -the number of memory pages the system read from swap space (`swin'), -the number of memory pages the system wrote to swap space (`swout'), and -the number of out-of-memory kills (`oomkill'). +This line contains the number of scanned pages ('scan') due to the fact +that free memory drops below a particular threshold, the number of +reclaimed pages('steal') due to the fact that free memory drops below +a particular threshold, the number times that the kernel tries to reclaim +pages due to an urgent need ('stall'),the number of process stalls to run +memory compaction to allocate huge pages ('compact'), the number of NUMA +pages migrated ('numamig'), and the total number of memory pages migrated +successfully e.g. between NUMA nodes or for compaction ('migrate') are shown. +.br +Also the number of memory pages the system read from block devices ('pgin'), +the number of memory pages the system wrote to block devices ('pgout'), +the number of memory pages the system read from swap space ('swin'), +the number of memory pages the system wrote to swap space ('swout'), and +the number of out-of-memory kills ('oomkill'). .PP .TP 5 .B PSI @@ -1352,11 +1534,11 @@ percentages refer to 'full' meaning a loss of overall throughput due to resource overload. .br -The values `cpusome', `memsome', `memfull', `iosome' and `iofull' +The values 'cpusome', 'memsome', 'memfull', 'iosome' and 'iofull' show the pressure percentage during the entire interval. .br -The values `cs' (cpu some), `ms' (memory some), `mf' (memory full), -`is' (I/O some) and `if' (I/O full) each show +The values 'cs' (cpu some), 'ms' (memory some), 'mf' (memory full), 'is' +(I/O some) and 'if' (I/O full) each show three percentages separated by slashes: pressure percentage over the last 10, 60 and 300 seconds. .PP @@ -1367,19 +1549,19 @@ Per active unit one line is produced, sorted on unit activity. Such line shows the name (e.g. VolGroup00-lvtmp for a logical volume or sda for a hard disk), the percentage of elapsed time during which I/O requests -were issued to the device (`busy') (note that for devices serving requests in +were issued to the device ('busy') (note that for devices serving requests in parallel, such as RAID arrays, SSD and NVMe, this number does not reflect their performance limits), the number of read requests issued -(`read'), the number of write requests issued (`write'), -the number of discard requests issued (`discrd') if supported by kernel version, -the number of KiBytes per read (`KiB/r'), -the number of KiBytes per write (`KiB/w'), -the number of KiBytes per discard (`KiB/d') if supported by kernel version, -the number of MiBytes per second throughput for reads (`MBr/s'), -the number of MiBytes per second throughput for writes (`MBw/s'), -requests issued to the device driver but not completed (`inflt'), -the average queue depth while busy (`avq') -and the average number of milliseconds needed by a request (`avio') +('read'), the number of write requests issued ('write'), +the number of discard requests issued ('discrd') if supported by kernel version, +the number of KiBytes per read ('KiB/r'), +the number of KiBytes per write ('KiB/w'), +the number of KiBytes per discard ('KiB/d') if supported by kernel version, +the number of MiBytes per second throughput for reads ('MBr/s'), +the number of MiBytes per second throughput for writes ('MBw/s'), +requests issued to the device driver but not completed ('inflt'), +the average queue depth while busy ('avq') +and the average number of milliseconds needed by a request ('avio') for seek, latency and data transfer. .br If the screen-width does not allow all of these counters, @@ -1395,45 +1577,45 @@ Network Filesystem (NFS) mount at the client side. .br For each NFS-mounted filesystem, a line is shown that contains -the mounted server directory, the name of the server (`srv'), -the total number of bytes physically read from the server (`read') and -the total number of bytes physically written to the server (`write'). +the mounted server directory, the name of the server ('srv'), +the total number of bytes physically read from the server ('read') and +the total number of bytes physically written to the server ('write'). Data transfer is subdivided in -the number of bytes read via normal read() system calls (`nread'), -the number of bytes written via normal read() system calls (`nwrit'), -the number of bytes read via direct I/O (`dread'), -the number of bytes written via direct I/O (`dwrit'), -the number of bytes read via memory mapped I/O pages (`mread'), and -the number of bytes written via memory mapped I/O pages (`mwrit'). +the number of bytes read via normal read() system calls ('nread'), +the number of bytes written via normal read() system calls ('nwrit'), +the number of bytes read via direct I/O ('dread'), +the number of bytes written via direct I/O ('dwrit'), +the number of bytes read via memory mapped I/O pages ('mread'), and +the number of bytes written via memory mapped I/O pages ('mwrit'). .PP .TP 5 .B NFC Network Filesystem (NFS) client side counters. .br This line contains the number of RPC calls issues by local processes -(`rpc'), the number of read RPC calls (`read`) and -write RPC calls (`rpwrite') issued to the NFS server, -the number of RPC calls being retransmitted (`retxmit') -and the number of authorization refreshes (`autref'). +('rpc'), the number of read RPC calls ('read') and +write RPC calls ('rpwrite') issued to the NFS server, +the number of RPC calls being retransmitted ('retxmit') +and the number of authorization refreshes ('autref'). .PP .TP 5 .B NFS Network Filesystem (NFS) server side counters. .br This line contains the number of RPC calls received from -NFS clients (`rpc'), -the number of read RPC calls received (`cread`), -the number of write RPC calls received (`cwrit'), -the number of Megabytes/second returned to read requests by clients (`MBcr/s`), -the number of Megabytes/second passed in write requests by clients (`MBcw/s`), -the number of network requests handled via TCP (`nettcp'), -the number of network requests handled via UDP (`netudp'), -the number of reply cache hits (`rchits'), -the number of reply cache misses (`rcmiss') and -the number of uncached requests (`rcnoca'). +NFS clients ('rpc'), +the number of read RPC calls received ('cread'), +the number of write RPC calls received ('cwrit'), +the number of Megabytes/second returned to read requests by clients ('MBcr/s'), +the number of Megabytes/second passed in write requests by clients ('MBcw/s'), +the number of network requests handled via TCP ('nettcp'), +the number of network requests handled via UDP ('netudp'), +the number of reply cache hits ('rchits'), +the number of reply cache misses ('rcmiss') and +the number of uncached requests ('rcnoca'). Furthermore some error counters indicating the number of requests -with a bad format (`badfmt') or a bad authorization (`badaut'), and a -counter indicating the number of bad clients (`badcln'). +with a bad format ('badfmt') or a bad authorization ('badaut'), and a +counter indicating the number of bad clients ('badcln'). .PP .TP 5 .B NET @@ -1444,18 +1626,18 @@ .br For the transport layer, counters are shown concerning the number of received TCP segments -including those received in error (`tcpi'), +including those received in error ('tcpi'), the number of transmitted TCP segments excluding -those containing only retransmitted octets (`tcpo'), -the number of UDP datagrams received (`udpi'), -the number of UDP datagrams transmitted (`udpo'), -the number of active TCP opens (`tcpao'), -the number of passive TCP opens (`tcppo'), -the number of TCP output retransmissions (`tcprs'), -the number of TCP input errors (`tcpie'), -the number of TCP output resets (`tcpor'), -the number of UDP no ports (`udpnp'), and -the number of UDP input errors (`udpie'). +those containing only retransmitted octets ('tcpo'), +the number of UDP datagrams received ('udpi'), +the number of UDP datagrams transmitted ('udpo'), +the number of active TCP opens ('tcpao'), +the number of passive TCP opens ('tcppo'), +the number of TCP output retransmissions ('tcprs'), +the number of TCP input errors ('tcpie'), +the number of TCP output resets ('tcpor'), +the number of UDP no ports ('udpnp'), and +the number of UDP input errors ('udpie'). .br If the screen-width does not allow all of these counters, only a relevant subset is shown. @@ -1463,13 +1645,13 @@ These counters are related to IPv4 and IPv6 combined. For the IP layer, counters are shown concerning the number of IP datagrams -received from interfaces, including those received in error (`ipi'), +received from interfaces, including those received in error ('ipi'), the number of IP datagrams that local higher-layer protocols offered for -transmission (`ipo'), the number of received IP datagrams which were -forwarded to other interfaces (`ipfrw'), the number of IP datagrams which -were delivered to local higher-layer protocols (`deliv'), -the number of received ICMP datagrams (`icmpi'), and -the number of transmitted ICMP datagrams (`icmpo'). +transmission ('ipo'), the number of received IP datagrams which were +forwarded to other interfaces ('ipfrw'), the number of IP datagrams which +were delivered to local higher-layer protocols ('deliv'), +the number of received ICMP datagrams ('icmpi'), and +the number of transmitted ICMP datagrams ('icmpo'). .br If the screen-width does not allow all of these counters, only a relevant subset is shown. @@ -1485,19 +1667,19 @@ per second; for full duplex the interface speed is compared with the highest of either the transmitted or the received bits. When the interface speed can not be determined (e.g. for the loopback -interface), `---' is shown instead of the percentage. +interface), '---' is shown instead of the percentage. .br -Furthermore the number of received packets (`pcki'), -the number of transmitted packets (`pcko'), -the line speed of the interface (`sp'), -the effective amount of bits received per second (`si'), -the effective amount of bits transmitted per second (`so'), -the number of collisions (`coll'), -the number of received multicast packets (`mlti'), -the number of errors while receiving a packet (`erri'), -the number of errors while transmitting a packet (`erro'), -the number of received packets dropped (`drpi'), and -the number of transmitted packets dropped (`drpo'). +Furthermore the number of received packets ('pcki'), +the number of transmitted packets ('pcko'), +the line speed of the interface ('sp'), +the effective amount of bits received per second ('si'), +the effective amount of bits transmitted per second ('so'), +the number of collisions ('coll'), +the number of received multicast packets ('mlti'), +the number of errors while receiving a packet ('erri'), +the number of errors while transmitting a packet ('erro'), +the number of received packets dropped ('drpi'), and +the number of transmitted packets dropped ('drpo'). .br If the screen-width does not allow all of these counters, only a relevant subset is shown. @@ -1518,21 +1700,23 @@ maximum port speed. .br Furthermore the number of received packets divided by the -number of lanes (`pcki'), -the number of transmitted packets divided by the number of lanes (`pcko'), -the maximum line speed (`sp'), -the effective amount of bits received per second (`si'), -the effective amount of bits transmitted per second (`so'), and -the number of lanes (`lanes'). +number of lanes ('pcki'), +the number of transmitted packets divided by the number of lanes ('pcko'), +the maximum line speed ('sp'), +the effective amount of bits received per second ('si'), +the effective amount of bits transmitted per second ('so'), and +the number of lanes ('lanes'). .br If the screen-width does not allow all of these counters, only a relevant subset is shown. .br The number of lines showing the Infiniband ports can be limited. .SH OUTPUT DESCRIPTION - PROCESS LEVEL -Following the system level information, the processes are shown from which the +Following the system level information, a list of processes is shown +in text mode from which the resource utilization has changed during the last interval. These processes -might have used cpu time or issued disk or network requests. However a process +might have used CPU time or might have issued disk or network requests. +However a process is also shown if part of it has been paged out due to lack of memory (while the process itself was in sleep state). .PP @@ -1552,20 +1736,20 @@ .B BANDWI Total bandwidth for received TCP and UDP packets consumed by this process (bits-per-second). -This value can be compared with the value `si' +This value can be compared with the value 'si' on interface level (used bandwidth per interface). .br -This information will only be shown when the kernel module `netatop' +This information will only be shown when the kernel module 'netatop' is loaded. .PP .TP 9 .B BANDWO Total bandwidth for sent TCP and UDP packets consumed by this process (bits-per-second). -This value can be compared with the value `so' +This value can be compared with the value 'so' on interface level (used bandwidth per interface). .br -This information will only be shown when the kernel module `netatop' +This information will only be shown when the kernel module 'netatop' is loaded. .PP .TP 9 @@ -1576,24 +1760,24 @@ .B CGROUP Path name of the cgroup (version 2) to which this process belongs. This path name is relative to the cgroup root directory, which -is usually `/sys/fs/cgroup'. +is usually '/sys/fs/cgroup'. .PP .TP 9 .B CID Container ID (Docker) of 12 hexadecimal digits, referring to the container in which the process/thread is running. If a process has been started and finished during the last -interval, a `?' is shown because the container ID is not part of +interval, a '?' is shown because the container ID is not part of the standard process accounting record. .PP .TP 9 .B CMD The name of the process. This name can be surrounded by "less/greater than" -signs (`') which means that the process has finished during the last +signs ('') which means that the process has finished during the last interval. .br -Behind the abbreviation `CMD' in the header line, the current page number and +Behind the abbreviation 'CMD' in the header line, the current page number and the total number of pages of the process/thread list are shown. .PP .TP 9 @@ -1602,7 +1786,7 @@ the command line exceeds the length of the screen line, the arrow keys -> and <- can be used for horizontal scroll. .br -Behind the verb `COMMAND-LINE' in the header line, the current page number +Behind the verb 'COMMAND-LINE' in the header line, the current page number and the total number of pages of the process/thread list are shown. .PP .TP 9 @@ -1612,12 +1796,12 @@ .PP .TP 9 .B CPUMAX -The `cpu.max' value of the cgroup (version 2) to which this process belongs, +The 'cpu.max' value of the cgroup (version 2) to which this process belongs, calculated as percentage of one CPU. .PP .TP 9 .B CPUMAXR -The most restrictive (i.e. effective) `cpu.max' value defined by the +The most restrictive (i.e. effective) 'cpu.max' value defined by the upper directories of the cgroup (version 2) to which this process belongs, calculated as percentage of one CPU. .PP @@ -1628,13 +1812,13 @@ .PP .TP 9 .B CPUWGT -The `cpu.weight' value of the cgroup (version 2) to which this process belongs. +The 'cpu.weight' value of the cgroup (version 2) to which this process belongs. .PP .TP 9 .B CTID Container ID (OpenVZ). If a process has been started and finished during the last -interval, a `?' is shown because the container ID is not part of +interval, a '?' is shown because the container ID is not part of the standard process accounting record. .PP .TP 9 @@ -1653,12 +1837,12 @@ .TP 9 .B ENDATE Date that the process has been finished. If the process is still running, -this field shows `active'. +this field shows 'active'. .PP .TP 9 .B ENTIME Time that the process has been finished. If the process is still running, -this field shows `active'. +this field shows 'active'. .PP .TP 9 .B ENVID @@ -1670,8 +1854,8 @@ .PP .TP 9 .B EXC -The exit code of a terminated process (second position of column `ST' is E) -or the fatal signal number (second position of column `ST' is S or C). +The exit code of a terminated process (second position of column 'ST' is E) +or the fatal signal number (second position of column 'ST' is S or C). .PP .TP 9 .B FSGID @@ -1736,7 +1920,7 @@ .PP .TP 9 .B MEMMAX -The `memory.max' value of the cgroup (version 2) to which this process belongs. +The 'memory.max' value of the cgroup (version 2) to which this process belongs. .PP .TP 9 .B MEMNOW @@ -1744,7 +1928,7 @@ .PP .TP 9 .B MMMAXR -The most restrictive (i.e. effective) `memory.max' value defined by the +The most restrictive (i.e. effective) 'memory.max' value defined by the upper directories of the cgroup (version 2) to which this process belongs. .PP .TP 9 @@ -1758,7 +1942,7 @@ is produced by all processes (i.e. consumed network bandwidth of all processes during the last interval). .br -This information will only be shown when kernel module `netatop' is loaded. +This information will only be shown when kernel module 'netatop' is loaded. .PP .TP 9 .B NICE @@ -1766,15 +1950,25 @@ scale from -20 (high priority) to +19 (low priority). .PP .TP 9 +.B NIVCSW +Number of times the process/thread was context-switched involuntarily, +in case that the time slice expired. +.PP +.TP 9 .B NPROCS The number of active and terminated processes accumulated for this user or program. .PP .TP 9 +.B NVCSW +Number of times that the process/thread was context-switched voluntarily in +case of a blocking system call, e.g. to wait for an I/O operation to complete. +.PP +.TP 9 .B PID Process-id. If a process has been started and finished during the last -interval, a `?' is shown because the process-id is not part of +interval, a '?' is shown because the process-id is not part of the standard process accounting record. .PP .TP 9 @@ -1826,8 +2020,6 @@ .PP .TP 9 .B RDDSK -When the kernel maintains standard io statistics (>= 2.6.20): -.br The read data transfer issued physically on disk (so reading from the disk cache is not accounted for). .br @@ -1862,7 +2054,7 @@ .TP 9 .B RNET The number of TCP- and UDP packets received by this process. -This information will only be shown when kernel module `netatop' is installed. +This information will only be shown when kernel module 'netatop' is installed. .br If a process has finished during the last interval, no value is shown since network counters are not part of the standard process accounting record. @@ -1891,13 +2083,12 @@ .PP .TP 9 .B S -The current state of the (main) thread: `R' for running -(currently processing or in the runqueue), `S' for sleeping interruptible -(wait for an event to occur), -`D' for sleeping non-interruptible, `Z' for zombie (waiting to be synchronized -with its parent process), `T' for stopped (suspended or traced), `W' for -swapping, and `E' (exit) for processes which have finished during the last -interval. +The current state of the (main) thread: 'R' for running +(currently processing or in the runqueue), 'S' for sleeping interruptible +(wait for an event to occur), 'D' for sleeping non-interruptible, 'Z' for +zombie (waiting to be synchronized with its parent process), 'T' for +stopped (suspended or traced), 'W' for swapping, and 'E' (exit) for +processes which have finished during the last interval. .PP .TP 9 .B SGID @@ -1906,7 +2097,7 @@ .TP 9 .B SNET The number of TCP and UDP packets transmitted by this process. -This information will only be shown when the kernel module `netatop' +This information will only be shown when the kernel module 'netatop' is loaded. .PP .TP 9 @@ -1924,18 +2115,18 @@ The value .I E means 'exit' on the process' own initiative; the exit code is displayed -in the column `EXC'. +in the column 'EXC'. .br The value .I S means that the process has been terminated unvoluntarily -by a signal; the signal number is displayed in the in the column `EXC'. +by a signal; the signal number is displayed in the in the column 'EXC'. .br The value .I C means that the process has been terminated unvoluntarily by a signal, producing a core dump in its current directory; -the signal number is displayed in the column `EXC'. +the signal number is displayed in the column 'EXC'. .PP .TP 9 .B STDATE @@ -1951,7 +2142,7 @@ .PP .TP 9 .B SWPMAX -The `memory.swap.max' value of the cgroup (version 2) to which this +The 'memory.swap.max' value of the cgroup (version 2) to which this process belongs. .PP .TP 9 @@ -1960,7 +2151,7 @@ .PP .TP 9 .B SWMAXR -The most restrictive (i.e. effective) `memory.swap.max' value defined by the +The most restrictive (i.e. effective) 'memory.swap.max' value defined by the upper directories of the cgroup (version 2) to which this process belongs. .PP .TP 9 @@ -1971,25 +2162,25 @@ .TP 9 .B TCPRASZ The average size of a received TCP buffer in bytes. -This information will only be shown when the kernel module `netatop' +This information will only be shown when the kernel module 'netatop' is loaded. .PP .TP 9 .B TCPRCV The number of TCP packets received for this process. -This information will only be shown when the kernel module `netatop' +This information will only be shown when the kernel module 'netatop' is loaded. .PP .TP 9 .B TCPSASZ The average size of a transmitted TCP buffer in bytes. -This information will only be shown when the kernel module `netatop' +This information will only be shown when the kernel module 'netatop' is loaded. .PP .TP 9 .B TCPSND The number of TCP packets transmitted for this process. -This information will only be shown when the kernel module `netatop' +This information will only be shown when the kernel module 'netatop' is loaded. .PP .TP 9 @@ -2029,25 +2220,25 @@ .TP 9 .B UDPRASZ The average size of a received UDP packet in bytes. -This information will only be shown when the kernel module `netatop' +This information will only be shown when the kernel module 'netatop' is loaded. .PP .TP 9 .B UDPRCV The number of UDP packets received by this process. -This information will only be shown when the kernel module `netatop' +This information will only be shown when the kernel module 'netatop' is loaded. .PP .TP 9 .B UDPSASZ The average size of a transmitted UDP packets in bytes. -This information will only be shown when the kernel module `netatop' +This information will only be shown when the kernel module 'netatop' is loaded. .PP .TP 9 .B UDPSND The number of UDP packets transmitted by this process. -This information will only be shown when the kernel module `netatop' +This information will only be shown when the kernel module 'netatop' is loaded. .PP .TP 9 @@ -2077,7 +2268,7 @@ .B VPID Virtual process-id (within an OpenVZ container). If a process has been started and finished during the last -interval, a `?' is shown because the virtual process-id is not part of +interval, a '?' is shown because the virtual process-id is not part of the standard process accounting record. .PP .TP 9 @@ -2112,8 +2303,6 @@ .PP .TP 9 .B WRDSK -When the kernel maintains standard io statistics (>= 2.6.20): -.br The write data transfer issued physically on disk (so writing to the disk cache is not accounted for). This counter is maintained for the application process that writes its @@ -2128,8 +2317,6 @@ .PP .TP 9 .B WCANCL -When the kernel maintains standard io statistics (>= 2.6.20): -.br The write data transfer previously accounted for this process or another process that has been cancelled. Suppose that a process writes new data to a file and that data is removed @@ -2137,11 +2324,11 @@ Then the original process shows the written data as WRDSK, while the process that removes/truncates the file shows the unflushed removed data as WCANCL. -.SH PARSEABLE OUTPUT +.SH PARSABLE OUTPUT With the flag .B -P followed by a list of one or more labels (comma-separated), -parseable output is produced for each sample. +parsable output is produced for each sample. The labels that can be specified for system-level statistics correspond to the labels (first verb of each line) that can be found in the interactive output: @@ -2149,13 +2336,13 @@ "DSK", "NFM", "NFC", "NFS", "NET", "IFB", "LLC", "NUM" and "NUC". .br For process-level statistics special labels are available: -"PRG" (general), "PRC" (cpu), "PRE" (GPU), "PRM" (memory), "PRD" +"PRG" (general), "PRC" (CPU), "PRE" (GPU), "PRM" (memory), "PRD" (disk, only if "storage accounting" is active) and "PRN" (network, only if the kernel module 'netatop' has been installed). .br With the label "ALL", all system and process level statistics are shown. .PP -The command and command line in the parseable output might contain spaces +The command and command line in the parsable output might contain spaces and are therefore by default surrounded by parenthesis. However, since a space is often used as separator between the fields by parsing tools, with the additional flag @@ -2460,8 +2647,9 @@ filesystem uid, filesystem gid, elapsed time of terminated process (hertz), is_process (y/n), OpenVZ virtual pid (VPID), OpenVZ container id (CTID), Docker container id (CID), -indication if the task is newly started during this interval ('N'), and -cgroup v2 path name (between parenthesis or underscores for spaces). +indication if the task is newly started during this interval ('N'), +cgroup v2 path name (between parenthesis or underscores for spaces), and +end time (epoch or 0 if still active). .TP 9 .B PRC For every process one line is shown. @@ -2477,8 +2665,12 @@ runqueue delay in nanoseconds for this thread or for all threads (in case of process), wait channel of this thread (between parenthesis or underscores for spaces), block I/O delay (clockticks), -cgroup v2 `cpu.max' calculated as percentage (-3 means no cgroup v2 support, -2 means undefined and -1 means maximum), and -cgroup v2 most restrictive `cpu.max' in upper directories calculated as percentage (-3 means no cgroup v2 support, -2 means undefined and -1 means maximum). +cgroup v2 'cpu.max' calculated as percentage (-3 means no cgroup v2 support, +-2 means undefined and -1 means maximum), +cgroup v2 most restrictive 'cpu.max' in upper directories calculated as percentage +(-3 means no cgroup v2 support, -2 means undefined and -1 means maximum), +number of voluntary context switches, and +number of involuntary context switches. .TP 9 .B PRE For every process one line is shown. @@ -2514,10 +2706,14 @@ TGID (group number of related tasks/threads), is_process (y/n), proportional set size (KiB) if in 'R' option is specified, virtually locked memory space (KiB), -cgroup v2 `memory.max' in KiB (-3 means no cgroup v2 support, -2 means undefined and -1 means maximum), -cgroup v2 most restrictive `memory.max' in upper directories in KiB (-3 means no cgroup v2 support, -2 means undefined and -1 means maximum), -cgroup v2 `memory.swap.max' in KiB (-3 means no cgroup v2 support, -2 means undefined and -1 means maximum), and -cgroup v2 most restrictive `memory.swap.max' in upper directories in KiB (-3 means no cgroup v2 support, -2 means undefined and -1 means maximum). +cgroup v2 'memory.max' in KiB (-3 means no cgroup v2 support, +-2 means undefined and -1 means maximum), +cgroup v2 most restrictive 'memory.max' in upper directories in KiB +(-3 means no cgroup v2 support, -2 means undefined and -1 means maximum), +cgroup v2 'memory.swap.max' in KiB (-3 means no cgroup v2 support, +-2 means undefined and -1 means maximum), and +cgroup v2 most restrictive 'memory.swap.max' in upper directories in KiB +(-3 means no cgroup v2 support, -2 means undefined and -1 means maximum). .TP 9 .B PRD For every process one line is shown. @@ -2533,11 +2729,6 @@ cancelled number of written sectors, TGID (group number of related tasks/threads), obsoleted value ('n'), and is_process (y/n). -.br -If the standard I/O statistics (>= 2.6.20) are not used, -the disk I/O counters per process are not relevant. -The counters 'number of reads on disk' and 'number of writes on disk' are -obsoleted anyhow. .TP 9 .B PRN For every process one line is shown. @@ -2564,13 +2755,13 @@ With the flag .B -J followed by a list of one or more labels (comma-separated), JSON output -is produced for each sample. The syntax and name of JSON labels are -the same as for the parseable output. +is produced for each sample. The syntax and name of JSON labels are +the same as for the parsable output. .SH SIGNALS By sending the SIGUSR1 signal to .I atop a new sample will be forced, even if the current timer interval -has not exceeded yet. The behavior is similar to pressing the `t` key +has not exceeded yet. The behavior is similar to pressing the 't' key in an interactive session. .PP By sending the SIGUSR2 signal to @@ -2579,17 +2770,16 @@ .I atop will terminate. .SH EXAMPLES -To monitor the current system load interactively with an interval of 5 seconds: +To monitor the current system load in text mode with an interval of +(default) 10 seconds: .PP .TP 12 -.B \ atop 5 +.B \ atop .PP -To monitor the system load and write it to a file (in plain ASCII) -with an interval of one minute during half an hour with active -processes sorted on memory consumption: +To monitor the current system load as bar graphs with an interval of 5 seconds: .PP .TP 12 -.B \ atop -M 60 30 > /log/atop.mem +.B \ atop -B 5 .PP Store information about the system and process activity in binary compressed form to a file with an interval of ten minutes during an hour: @@ -2601,7 +2791,7 @@ .PP .B \ atop -r /tmp/atop.raw .PP -View the processor and disk utilization of this file in parseable format: +View the processor and disk utilization of this file in parsable format: .PP .B \ atop -PCPU,DSK -r /tmp/atop.raw .PP @@ -2614,16 +2804,23 @@ .PP .B \ atop -r yy .PP -View the contents of the standard logfile of 2014, June 7 from +View the contents of the standard logfile of 2023, April 15 from 02:00 PM onwards interactively: .PP -.B \ atop -r 20140607 -b 1400 +.B \ atop -r 20230415 -b 1400 .PP -Concatenate all raw log files of January 2020 and generate parsable +Concatenate all raw log files of March 2023 and generate parsable output about the CPU utilization: .PP .TP 12 -.B \ atopcat /var/log/atop/atop_202001?? | atop -r - -PCPU +.B \ atopcat /var/log/atop/atop_202303?? | atop -r - -PCPU +.PP +To monitor the system load and write it to a file (in plain ASCII) +with an interval of one minute during half an hour with active +processes sorted on memory consumption: +.PP +.TP 12 +.B \ atop -M 60 30 > /log/atop.mem .PP .SH FILES .PP @@ -2645,12 +2842,16 @@ .TP 5 .B /etc/atoprc Configuration file containing system-wide default values. -See related man-page. +For further information about the default values, refer to the +.B atoprc +man page). .PP .TP 5 .B ~/.atoprc Configuration file containing personal default values. -See related man-page. +For further information about the default values, refer to the +.B atoprc +man page). .PP .TP 5 .B /etc/default/atop diff -Nru atop-2.8.1/man/atoprc.5 atop-2.9.0/man/atoprc.5 --- atop-2.8.1/man/atoprc.5 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/man/atoprc.5 2023-05-13 08:20:27.000000000 +0000 @@ -1,4 +1,4 @@ -.TH ATOPRC 5 "December 2022" "Linux" +.TH ATOPRC 5 "April 2023" "Linux" .SH NAME .B atoprc - atop/atopsar related rcfile @@ -31,7 +31,8 @@ A list of default flags for .B atop can be defined here. The flags which are allowed -are 'g', 'm', 'd', 'n', 'u', 'p', 's', 'c', 'v', 'C', 'M', 'D', 'N', 'A', +are 'B', 'H', 'g', 'm', 'd', 'n', 'u', 'p', 's', 'c', 'v', +\&'C', 'M', 'D', 'N', 'A', \&'a', 'y', 'Y', 'f', 'F', 'G', 'R', '1', 'e', 'E' and 'x'. .PP .TP 4 @@ -90,7 +91,8 @@ .I atop command). This percentage is used to determine -a weighted percentage for line coloring and sorting of active processes. +a weighted percentage for line coloring and sorting of active processes +in text mode. When this value is zero, no line coloring or automatic sorting is performed for this resource. .PP @@ -101,7 +103,8 @@ .I atop command). This percentage is used to determine -a weighted percentage for line coloring and sorting of active processes. +a weighted percentage for line coloring and sorting of active processes +in text mode. When this value is zero, no line coloring or automatic sorting is performed for this resource. .PP @@ -112,7 +115,8 @@ .I atop command). This percentage is used to determine -a weighted percentage for line coloring and sorting of active processes. +a weighted percentage for line coloring and sorting of active processes +in text mode. When this value is zero, no line coloring or automatic sorting is performed for this resource. .PP @@ -123,7 +127,8 @@ .I atop command). This percentage is used to determine -a weighted percentage for line coloring and sorting of active processes. +a weighted percentage for line coloring and sorting of active processes +in text mode. When this value is zero, no line coloring or automatic sorting is performed for this resource. .PP @@ -134,7 +139,8 @@ .I atop command). This percentage is used to determine -a weighted percentage for line coloring and sorting of active processes. +a weighted percentage for line coloring and sorting of active processes +in text mode. When this value is zero, no line coloring or automatic sorting is performed for this resource. .PP @@ -146,7 +152,8 @@ .I atop command). This threshold is used in combination with 'memcritperc' to determine a -weighted percentage for line coloring and sorting of active processes. +weighted percentage for line coloring and sorting of active processes +in text mode. When this value is zero, no line coloring or automatic sorting is performed for this resource. .PP @@ -161,8 +168,19 @@ performed. .PP .TP 4 +.B cpubarwidth +Number of columns used per bar in the processor bar graph. +The default value is 0 which means that the bar width will +be scaled automatically (the wider the terminal, the more +columns per bar upto a maximum of three). +With the value 1, 2 or 3 the number of bars can be statically +pinned to that number of columns, with one column of white +space in between the bars. +.PP +.TP 4 .B colorinfo -Definition of color name for information messages (default: green). +Definition of color name for information messages (default: green) +in text mode. .br Allowed colors are: red green yellow blue magenta cyan black white. .PP @@ -175,13 +193,15 @@ .PP .TP 4 .B coloralmost -Definition of color name for almost critical resources (default: cyan). +Definition of color name for almost critical resources (default: cyan) +in text mode. .br Allowed colors are: red green yellow blue magenta cyan black white. .PP .TP 4 .B colorcritical -Definition of color name for critical resources (default: red). +Definition of color name for critical resources (default: red) +in text mode. .br Allowed colors are: red green yellow blue magenta cyan black white. .PP diff -Nru atop-2.8.1/mkdate atop-2.9.0/mkdate --- atop-2.8.1/mkdate 1970-01-01 00:00:00.000000000 +0000 +++ atop-2.9.0/mkdate 2023-06-26 11:08:39.000000000 +0000 @@ -0,0 +1,10 @@ +#!/bin/sh + +# Make a new versdate.h with the current date filled +# +CURDATE=$(date +%Y/%m/%d\ %H:%M:%S) + +echo "#ifndef __ATOP_VERSDATA__" > versdate.h +echo "#define __ATOP_VERSDATA__" >> versdate.h +echo "#define ATOPDATE \"$CURDATE\"" >> versdate.h +echo "#endif" >> versdate.h diff -Nru atop-2.8.1/netatopd.h atop-2.9.0/netatopd.h --- atop-2.8.1/netatopd.h 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/netatopd.h 2023-05-13 08:20:27.000000000 +0000 @@ -26,6 +26,9 @@ ** -------------------------------------------------------------------------- */ +#ifndef __NETATOPD__ +#define __NETATOPD__ + #define SEMAKEY 1541961 #define NETEXITFILE "/var/run/netatop.log" @@ -38,3 +41,5 @@ u_int16_t ntplen; // length of netpertask structure pid_t mypid; // PID of netatopd itself }; + +#endif diff -Nru atop-2.8.1/netatop.h atop-2.9.0/netatop.h --- atop-2.8.1/netatop.h 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/netatop.h 2023-05-13 08:20:27.000000000 +0000 @@ -26,6 +26,9 @@ ** -------------------------------------------------------------------------- */ +#ifndef __NETATOP__ +#define __NETATOP__ + #define COMLEN 16 struct taskcount { @@ -73,3 +76,5 @@ // get counters for thread: input is 'id' (tid) #define NETATOP_GETCNT_PID (NETATOP_BASE_CTL+5) + +#endif diff -Nru atop-2.8.1/netlink.c atop-2.9.0/netlink.c --- atop-2.8.1/netlink.c 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/netlink.c 2023-05-13 08:20:27.000000000 +0000 @@ -31,6 +31,8 @@ #include #include +#include "atop.h" + /* ** generic macro's */ diff -Nru atop-2.8.1/netstats.h atop-2.9.0/netstats.h --- atop-2.8.1/netstats.h 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/netstats.h 2023-05-13 08:20:27.000000000 +0000 @@ -26,6 +26,9 @@ ** -------------------------------------------------------------------------- */ +#ifndef __NETSTATS__ +#define __NETSTATS__ + /* ** structures defined from the output of /proc/net/snmp and /proc/net/snmp6 */ @@ -167,3 +170,5 @@ count_t Udp6InErrors; count_t Udp6OutDatagrams; }; + +#endif diff -Nru atop-2.8.1/parseable.c atop-2.9.0/parseable.c --- atop-2.8.1/parseable.c 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/parseable.c 2023-05-13 08:20:27.000000000 +0000 @@ -39,39 +39,40 @@ #include "photoproc.h" #include "parseable.h" -void print_CPU(); -void print_cpu(); -void print_CPL(); -void print_GPU(); -void print_MEM(); -void print_SWP(); -void print_PAG(); -void print_PSI(); -void print_LVM(); -void print_MDD(); -void print_DSK(); -void print_NFM(); -void print_NFC(); -void print_NFS(); -void print_NET(); -void print_IFB(); -void print_NUM(); -void print_NUC(); -void print_LLC(); - -void print_PRG(); -void print_PRC(); -void print_PRM(); -void print_PRD(); -void print_PRN(); -void print_PRE(); +void print_CPU(char *, struct sstat *, struct tstat *, int); +void print_cpu(char *, struct sstat *, struct tstat *, int); +void print_CPL(char *, struct sstat *, struct tstat *, int); +void print_GPU(char *, struct sstat *, struct tstat *, int); +void print_MEM(char *, struct sstat *, struct tstat *, int); +void print_SWP(char *, struct sstat *, struct tstat *, int); +void print_PAG(char *, struct sstat *, struct tstat *, int); +void print_PSI(char *, struct sstat *, struct tstat *, int); +void print_LVM(char *, struct sstat *, struct tstat *, int); +void print_MDD(char *, struct sstat *, struct tstat *, int); +void print_DSK(char *, struct sstat *, struct tstat *, int); +void print_NFM(char *, struct sstat *, struct tstat *, int); +void print_NFC(char *, struct sstat *, struct tstat *, int); +void print_NFS(char *, struct sstat *, struct tstat *, int); +void print_NET(char *, struct sstat *, struct tstat *, int); +void print_IFB(char *, struct sstat *, struct tstat *, int); +void print_NUM(char *, struct sstat *, struct tstat *, int); +void print_NUC(char *, struct sstat *, struct tstat *, int); +void print_LLC(char *, struct sstat *, struct tstat *, int); + +void print_PRG(char *, struct sstat *, struct tstat *, int); +void print_PRC(char *, struct sstat *, struct tstat *, int); +void print_PRM(char *, struct sstat *, struct tstat *, int); +void print_PRD(char *, struct sstat *, struct tstat *, int); +void print_PRN(char *, struct sstat *, struct tstat *, int); +void print_PRE(char *, struct sstat *, struct tstat *, int); +static void calc_freqscale(count_t, count_t, count_t, count_t *, int *); static char *spaceformat(char *, char *); static int cgroupv2max(int, int); /* ** table with possible labels and the corresponding -** print-function for parseable output +** print-function for parsable output */ struct labeldef { char *label; @@ -184,7 +185,7 @@ } /* -** produce parseable output for an interval +** produce parsable output for an interval */ char parseout(time_t curtime, int numsecs, @@ -238,7 +239,7 @@ /* ** print functions for system-level statistics */ -void +static void calc_freqscale(count_t maxfreq, count_t cnt, count_t ticks, count_t *freq, int *freqperc) { @@ -741,7 +742,7 @@ exitcode = (ps->gen.excode >> 8) & 0xff; printf("%s %d %s %c %d %d %d %d %d %ld %s %d %d %d %d " - "%d %d %d %d %d %d %ld %c %d %d %s %c %s\n", + "%d %d %d %d %d %d %ld %c %d %d %s %c %s %ld\n", hp, ps->gen.pid, spaceformat(ps->gen.name, namout), @@ -769,7 +770,9 @@ ps->gen.ctid, ps->gen.container[0] ? ps->gen.container:"-", ps->gen.excode & ~(INT_MAX) ? 'N' : '-', - spaceformat(ps->gen.cgpath, pathout)); + spaceformat(ps->gen.cgpath, pathout), + ps->gen.state == 'E' ? + ps->gen.btime + ps->gen.elaps/hertz : 0); } } @@ -782,7 +785,7 @@ for (i=0; i < nact; i++, ps++) { printf("%s %d %s %c %u %lld %lld %d %d %d %d %d %d %d %c " - "%llu %s %llu %d %d\n", + "%llu %s %llu %d %d %llu %llu\n", hp, ps->gen.pid, spaceformat(ps->gen.name, namout), @@ -802,7 +805,9 @@ spaceformat(ps->cpu.wchan, wchanout), ps->cpu.blkdelay, cgroupv2max(ps->gen.isproc, ps->cpu.cgcpumax), - cgroupv2max(ps->gen.isproc, ps->cpu.cgcpumaxr)); + cgroupv2max(ps->gen.isproc, ps->cpu.cgcpumaxr), + ps->cpu.nvcsw, + ps->cpu.nivcsw); } } diff -Nru atop-2.8.1/parseable.h atop-2.9.0/parseable.h --- atop-2.8.1/parseable.h 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/parseable.h 2023-05-13 08:20:27.000000000 +0000 @@ -25,7 +25,12 @@ ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ** -------------------------------------------------------------------------- */ +#ifndef __PARSEABLE__ +#define __PARSEABLE__ + int parsedef(char *); char parseout(time_t, int, struct devtstat *, struct sstat *, int, unsigned int, char); + +#endif diff -Nru atop-2.8.1/photoproc.c atop-2.9.0/photoproc.c --- atop-2.8.1/photoproc.c 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/photoproc.c 2023-05-13 08:20:27.000000000 +0000 @@ -245,6 +245,14 @@ curtask->cpu.blkdelay = 0; /* + ** nvcsw and nivcsw on process level only + ** concerns the delays of the main thread; + ** totalize the delays of all threads + */ + curtask->cpu.nvcsw = 0; + curtask->cpu.nivcsw = 0; + + /* ** open underlying task directory */ if ( chdir("task") == 0 ) @@ -301,13 +309,20 @@ if (getwchan) procwchan(curthr); - // totalize delays of all threads + // totalize values of all threads curtask->cpu.rundelay += procschedstat(curthr); curtask->cpu.blkdelay += curthr->cpu.blkdelay; + curtask->cpu.nvcsw += + curthr->cpu.nvcsw; + + curtask->cpu.nivcsw += + curthr->cpu.nivcsw; + + // continue gathering strcpy(curthr->gen.container, curtask->gen.container); @@ -369,7 +384,7 @@ unsigned long counttasks(void) { - unsigned long nr=0; + unsigned long nrproc=0, nrthread=0; char linebuf[256]; FILE *fp; DIR *dirp; @@ -383,7 +398,7 @@ { if ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { - if ( sscanf(linebuf, "%*f %*f %*f %*d/%lu", &nr) < 1) + if ( sscanf(linebuf, "%*f %*f %*f %*d/%lu", &nrthread) < 1) mcleanstop(53, "wrong /proc/loadavg\n"); } else @@ -412,7 +427,7 @@ ** count subdirectory names under /proc starting with a digit */ if (isdigit(entp->d_name[0])) - nr++; + nrproc++; } closedir(dirp); @@ -420,7 +435,11 @@ if ( chdir(origdir) == -1) mcleanstop(53, "cannot change to %s\n", origdir); - return nr; + if (nrthread < nrproc) + mcleanstop(53, "#threads (%ld) < #procs (%ld)\n", + nrthread, nrproc); + + return nrproc + nrthread; } /* @@ -631,8 +650,15 @@ continue; } - if (memcmp(line, "SigQ:", 5)==0) - break; + if (memcmp(line, "voluntary_ctxt_switches:", 24)==0) { + sscanf(line, "voluntary_ctxt_switches: %lld", &(curtask->cpu.nvcsw)); + continue; + } + + if (memcmp(line, "nonvoluntary_ctxt_switches:", 27)==0) { + sscanf(line, "nonvoluntary_ctxt_switches: %lld", &(curtask->cpu.nivcsw)); + continue; + } } fclose(fp); diff -Nru atop-2.8.1/photoproc.h atop-2.9.0/photoproc.h --- atop-2.8.1/photoproc.h 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/photoproc.h 2023-05-13 08:20:27.000000000 +0000 @@ -23,6 +23,9 @@ ** See the GNU General Public License for more details. */ +#ifndef __PHOTOPROC__ +#define __PHOTOPROC__ + #define PNAMLEN 15 #define CMDLEN 255 #define CGRLEN 64 @@ -83,7 +86,9 @@ char wchan[16]; /* wait channel string */ count_t rundelay; /* schedstat rundelay (nanosec) */ count_t blkdelay; /* blkio delay (ticks) */ - count_t cfuture[3]; /* reserved for future use */ + count_t nvcsw; /* voluntary cxt switch counts */ + count_t nivcsw; /* involuntary csw counts */ + count_t cfuture[1]; /* reserved for future use */ } cpu; /* DISK STATISTICS */ @@ -198,3 +203,5 @@ unsigned long photoproc(struct tstat *, int); unsigned long counttasks(void); + +#endif diff -Nru atop-2.8.1/photosyst.c atop-2.9.0/photosyst.c --- atop-2.8.1/photosyst.c 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/photosyst.c 2023-05-13 08:20:27.000000000 +0000 @@ -93,6 +93,8 @@ }; static int perfevents = PERF_EVENTS_AUTO; +static long perf_event_open(struct perf_event_attr *, pid_t, + int, int, unsigned long); static void getperfevents(struct cpustat *); #endif @@ -103,6 +105,10 @@ static int isdisk(unsigned int, unsigned int, char *, struct perdsk *, int); +static struct bitmask *numa_allocate_cpumask(void); +static void numa_bitmask_free(struct bitmask *); +static int numa_parse_bitmap_v2(char *, struct bitmask *); + static struct ipv6_stats ipv6_tmp; static struct icmpv6_stats icmpv6_tmp; static struct udpv6_stats udpv6_tmp; @@ -202,8 +208,8 @@ * Allocate a bitmask for cpus, of a size large enough to * match the kernel's cpumask_t. */ -struct bitmask * -numa_allocate_cpumask() +static struct bitmask * +numa_allocate_cpumask(void) { int ncpus = CPUMASK_SZ; struct bitmask *bmp; @@ -219,7 +225,7 @@ return bmp; } -void +static void numa_bitmask_free(struct bitmask *bmp) { if (bmp == 0) @@ -230,7 +236,7 @@ return; } -int +static int numa_parse_bitmap_v2(char *line, struct bitmask *mask) { int i; @@ -592,13 +598,37 @@ continue; } - if ( strncmp("pgscan_", nam, 7) == EQ) + if ( strncmp("pgscan_kswapd", nam, 13) == EQ) + { + si->mem.pgscans += cnts[0]; + continue; + } + + if ( strncmp("pgscan_direct", nam, 13) == EQ) { si->mem.pgscans += cnts[0]; continue; } - if ( strncmp("pgsteal_", nam, 8) == EQ) + if ( strncmp("pgscan_khugepaged", nam, 17) == EQ) + { + si->mem.pgscans += cnts[0]; + continue; + } + + if ( strncmp("pgsteal_kswapd", nam, 14) == EQ) + { + si->mem.pgsteal += cnts[0]; + continue; + } + + if ( strncmp("pgsteal_direct", nam, 14) == EQ) + { + si->mem.pgsteal += cnts[0]; + continue; + } + + if ( strncmp("pgsteal_khugepaged", nam, 18) == EQ) { si->mem.pgsteal += cnts[0]; continue; @@ -2129,68 +2159,6 @@ return NONTYPE; } -/* -** LINUX SPECIFIC: -** Determine boot-time of this system (as number of jiffies since 1-1-1970). -*/ -unsigned long long -getbootlinux(long hertz) -{ - int cpid; - char tmpbuf[1280]; - FILE *fp; - unsigned long startticks; - unsigned long long bootjiffies = 0; - struct timespec ts; - - /* - ** dirty hack to get the boottime, since the - ** Linux 2.6 kernel (2.6.5) does not return a proper - ** boottime-value with the times() system call :-( - */ - if ( (cpid = fork()) == 0 ) - { - /* - ** child just waiting to be killed by parent - */ - pause(); - } - else - { - /* - ** parent determines start-time (in jiffies since boot) - ** of the child and calculates the boottime in jiffies - ** since 1-1-1970 - */ - (void) clock_gettime(CLOCK_REALTIME, &ts); // get current - bootjiffies = 1LL * ts.tv_sec * hertz + - 1LL * ts.tv_nsec * hertz / 1000000000LL; - - snprintf(tmpbuf, sizeof tmpbuf, "/proc/%d/stat", cpid); - - if ( (fp = fopen(tmpbuf, "r")) != NULL) - { - if ( fscanf(fp, "%*d (%*[^)]) %*c %*d %*d %*d %*d " - "%*d %*d %*d %*d %*d %*d %*d %*d " - "%*d %*d %*d %*d %*d %*d %lu", - &startticks) == 1) - { - bootjiffies -= startticks; - } - - fclose(fp); - } - - /* - ** kill the child and get rid of the zombie - */ - kill(cpid, SIGKILL); - (void) wait((int *)0); - } - - return bootjiffies; -} - /* ** get stats of all InfiniBand ports below @@ -2716,7 +2684,7 @@ return perfevents == PERF_EVENTS_ENABLE; } -long +static long perf_event_open(struct perf_event_attr *hwevent, pid_t pid, int cpu, int groupfd, unsigned long flags) { diff -Nru atop-2.8.1/photosyst.h atop-2.9.0/photosyst.h --- atop-2.8.1/photosyst.h 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/photosyst.h 2023-05-13 08:20:27.000000000 +0000 @@ -449,4 +449,5 @@ void photosyst (struct sstat *); void deviatsyst(struct sstat *, struct sstat *, struct sstat *, long); void totalsyst (char, struct sstat *, struct sstat *); +void do_perfevents(char *, char *); #endif diff -Nru atop-2.8.1/prev/photoproc_29.h atop-2.9.0/prev/photoproc_29.h --- atop-2.8.1/prev/photoproc_29.h 1970-01-01 00:00:00.000000000 +0000 +++ atop-2.9.0/prev/photoproc_29.h 2023-05-13 08:20:27.000000000 +0000 @@ -0,0 +1,124 @@ +/* +** structure containing only relevant process-info extracted +** from kernel's process-administration +*/ +struct tstat_29 { + /* GENERAL TASK INFO */ + struct gen_29 { + int tgid; /* threadgroup identification */ + int pid; /* process identification */ + int ppid; /* parent process identification*/ + int ruid; /* real user identification */ + int euid; /* eff. user identification */ + int suid; /* saved user identification */ + int fsuid; /* fs user identification */ + int rgid; /* real group identification */ + int egid; /* eff. group identification */ + int sgid; /* saved group identification */ + int fsgid; /* fs group identification */ + int nthr; /* number of threads in tgroup */ + char name[PNAMLEN+1];/* process name string */ + char isproc; /* boolean: process level? */ + char state; /* process state ('E' = exited) */ + int excode; /* process exit status */ + time_t btime; /* process start time (epoch) */ + time_t elaps; /* process elaps time (hertz) */ + char cmdline[CMDLEN+1];/* command-line string */ + int nthrslpi; /* # threads in state 'S' */ + int nthrslpu; /* # threads in state 'D' */ + int nthrrun; /* # threads in state 'R' */ + + int ctid; /* OpenVZ container ID */ + int vpid; /* OpenVZ virtual PID */ + + int wasinactive; /* boolean: task inactive */ + + char container[16]; /* Docker container id (12 pos) */ + char cgpath[CGRLEN]; /* cgroup v2 path name */ + } gen; + + /* CPU STATISTICS */ + struct cpu_29 { + count_t utime; /* time user text (ticks) */ + count_t stime; /* time system text (ticks) */ + int nice; /* nice value */ + int prio; /* priority */ + int rtprio; /* realtime priority */ + int policy; /* scheduling policy */ + int curcpu; /* current processor */ + int sleepavg; /* sleep average percentage */ + int cgcpuweight; /* cgroup cpu.weight */ + int cgcpumax; /* cgroup cpu.max percentage */ + int cgcpumaxr; /* restrictive percentage */ + int ifuture[3]; /* reserved for future use */ + char wchan[16]; /* wait channel string */ + count_t rundelay; /* schedstat rundelay (nanosec) */ + count_t blkdelay; /* blkio delay (ticks) */ + count_t cfuture[3]; /* reserved for future use */ + } cpu; + + /* DISK STATISTICS */ + struct dsk_29 { + count_t rio; /* number of read requests */ + count_t rsz; /* cumulative # sectors read */ + count_t wio; /* number of write requests */ + count_t wsz; /* cumulative # sectors written */ + count_t cwsz; /* cumulative # written sectors */ + /* being cancelled */ + count_t cfuture[4]; /* reserved for future use */ + } dsk; + + /* MEMORY STATISTICS */ + struct mem_29 { + count_t minflt; /* number of page-reclaims */ + count_t majflt; /* number of page-faults */ + count_t vexec; /* virtmem execfile (Kb) */ + count_t vmem; /* virtual memory (Kb) */ + count_t rmem; /* resident memory (Kb) */ + count_t pmem; /* resident memory (Kb) */ + count_t vgrow; /* virtual growth (Kb) */ + count_t rgrow; /* resident growth (Kb) */ + count_t vdata; /* virtmem data (Kb) */ + count_t vstack; /* virtmem stack (Kb) */ + count_t vlibs; /* virtmem libexec (Kb) */ + count_t vswap; /* swap space used (Kb) */ + count_t vlock; /* virtual locked (Kb) */ + count_t cgmemmax; /* cgroup memory.max (Kb) */ + count_t cgmemmaxr; /* restrictive memory.max (Kb) */ + count_t cgswpmax; /* cgroup memory.swap.max (Kb) */ + count_t cgswpmaxr; /* restrictive swap.max (Kb) */ + count_t cfuture[3]; /* reserved for future use */ + } mem; + + /* NETWORK STATISTICS */ + struct net_29 { + count_t tcpsnd; /* number of TCP-packets sent */ + count_t tcpssz; /* cumulative size packets sent */ + count_t tcprcv; /* number of TCP-packets recved */ + count_t tcprsz; /* cumulative size packets rcvd */ + count_t udpsnd; /* number of UDP-packets sent */ + count_t udpssz; /* cumulative size packets sent */ + count_t udprcv; /* number of UDP-packets recved */ + count_t udprsz; /* cumulative size packets sent */ + count_t avail1; /* */ + count_t avail2; /* */ + count_t cfuture[4]; /* reserved for future use */ + } net; + + struct gpu_29 { + char state; // A - active, E - Exit, '\0' - no use + char cfuture[3]; // + short nrgpus; // number of GPUs for this process + int32_t gpulist; // bitlist with GPU numbers + + int gpubusy; // gpu busy perc process lifetime -1 = n/a + int membusy; // memory busy perc process lifetime -1 = n/a + count_t timems; // milliseconds accounting -1 = n/a + // value 0 for active process, + // value > 0 after termination + + count_t memnow; // current memory consumption in KiB + count_t memcum; // cumulative memory consumption in KiB + count_t sample; // number of samples + } gpu; +}; diff -Nru atop-2.8.1/prev/photosyst_29.h atop-2.9.0/prev/photosyst_29.h --- atop-2.8.1/prev/photosyst_29.h 1970-01-01 00:00:00.000000000 +0000 +++ atop-2.9.0/prev/photosyst_29.h 2023-05-13 08:20:27.000000000 +0000 @@ -0,0 +1,413 @@ +#define MAXCPU_29 2048 +#define MAXDSK_29 1024 +#define MAXNUMA_29 1024 +#define MAXLVM_29 2048 +#define MAXMDD_29 256 +#define MAXINTF_29 128 +#define MAXCONTAINER_29 128 +#define MAXNFSMOUNT_29 64 +#define MAXIBPORT_29 32 +#define MAXGPU_29 32 +#define MAXGPUBUS_29 12 +#define MAXGPUTYPE_29 12 +#define MAXLLC_29 256 + +#define MAXDKNAM_29 32 +#define MAXIBNAME_29 12 + +/************************************************************************/ +struct memstat_29 { + count_t physmem; // number of physical pages + count_t freemem; // number of free pages + count_t buffermem; // number of buffer pages + count_t slabmem; // number of slab pages + count_t cachemem; // number of cache pages + count_t cachedrt; // number of cache pages (dirty) + + count_t totswap; // number of pages in swap + count_t freeswap; // number of free swap pages + + count_t pgscans; // number of page scans + count_t pgsteal; // number of page steals + count_t allocstall; // try to free pages forced + count_t swouts; // number of pages swapped out + count_t swins; // number of pages swapped in + count_t tcpsock; // number of pages allocated by TCP sockets + count_t udpsock; // number of pages allocated by UDP sockets + + count_t commitlim; // commit limit in pages + count_t committed; // number of reserved pages + + count_t shmem; // tot shmem incl. tmpfs (pages) + count_t shmrss; // resident shared memory (pages) + count_t shmswp; // swapped shared memory (pages) + + count_t slabreclaim; // reclaimable slab (pages) + + count_t tothugepage; // total huge pages (huge pages) + count_t freehugepage; // free huge pages (huge pages) + count_t hugepagesz; // huge page size (bytes) + + count_t vmwballoon; // vmware claimed balloon pages + count_t zfsarcsize; // zfsonlinux ARC size (pages) + count_t swapcached; // swap cache (pages) + count_t ksmsharing; // saved i.e. deduped memory (pages) + count_t ksmshared; // current size shared pages (pages) + count_t zswstored; // zswap stored pages (pages) + count_t zswtotpool; // total pool size (pages) + count_t oomkills; // number of oom killings + count_t compactstall; // counter for process stalls + count_t pgmigrate; // counter for migrated successfully (pages) + count_t numamigrate; // counter for numa migrated (pages) + count_t pgouts; // total number of pages written to block device + count_t pgins; // total number of pages read from block device + count_t pagetables; // page tables of processes (pages) + count_t cfuture[4]; // reserved for future use +}; + +/************************************************************************/ + +struct mempernuma_29 { + int numanr; + float frag; // fragmentation level for this numa + count_t totmem; // number of physical pages for this numa + count_t freemem; // number of free pages for this numa + count_t filepage; // number of file pages for this numa + count_t dirtymem; // number of cache pages (dirty) for this numa + count_t slabmem; // number of slab pages for this numa + count_t slabreclaim; // reclaimable slab (pages) for this numa + + count_t active; // number of pages used more recently for this numa + count_t inactive; // number of pages less recently used for this numa + + count_t shmem; // tot shmem incl. tmpfs (pages) for this numa + count_t tothp; // total huge pages (huge pages) for this numa +}; + +struct memnuma_29 { + count_t nrnuma; /* the counts of numa */ + struct mempernuma_29 numa[MAXNUMA_29]; +}; + +struct cpupernuma_29 { + int numanr; + count_t nrcpu; // number of cpu's + count_t stime; // accumulate system time in clock ticks for per numa + count_t utime; // accumulate user time in clock ticks for per numa + count_t ntime; // accumulate nice time in clock ticks for per numa + count_t itime; // accumulate idle time in clock ticks for per numa + count_t wtime; // accumulate iowait time in clock ticks for per numa + count_t Itime; // accumulate irq time in clock ticks for per numa + count_t Stime; // accumulate softirq time in clock ticks for per numa + count_t steal; // accumulate steal time in clock ticks for per numa + count_t guest; // accumulate guest time in clock ticks for per numa +}; + +struct cpunuma_29 { + count_t nrnuma; /* the counts of numa */ + struct cpupernuma_29 numa[MAXNUMA_29]; +}; + +/************************************************************************/ + +struct netstat_29 { + struct ipv4_stats ipv4; + struct icmpv4_stats icmpv4; + struct udpv4_stats udpv4; + + struct ipv6_stats ipv6; + struct icmpv6_stats icmpv6; + struct udpv6_stats udpv6; + + struct tcp_stats tcp; +}; + +/************************************************************************/ + +struct freqcnt_29 { + count_t maxfreq;/* frequency in MHz */ + count_t cnt; /* number of clock ticks times state */ + count_t ticks; /* number of total clock ticks */ + /* if zero, cnt is actual freq */ +}; + +struct percpu_29 { + int cpunr; + count_t stime; /* system time in clock ticks */ + count_t utime; /* user time in clock ticks */ + count_t ntime; /* nice time in clock ticks */ + count_t itime; /* idle time in clock ticks */ + count_t wtime; /* iowait time in clock ticks */ + count_t Itime; /* irq time in clock ticks */ + count_t Stime; /* softirq time in clock ticks */ + count_t steal; /* steal time in clock ticks */ + count_t guest; /* guest time in clock ticks */ + struct freqcnt_29 freqcnt;/* frequency scaling info */ + count_t instr; /* CPU instructions */ + count_t cycle; /* CPU cycles */ + count_t cfuture[6]; /* reserved for future use */ +}; + +struct cpustat_29 { + count_t nrcpu; /* number of cpu's */ + count_t devint; /* number of device interrupts */ + count_t csw; /* number of context switches */ + count_t nprocs; /* number of processes started */ + float lavg1; /* load average last minute */ + float lavg5; /* load average last 5 minutes */ + float lavg15; /* load average last 15 minutes */ + count_t cfuture[4]; /* reserved for future use */ + + struct percpu_29 all; + struct percpu_29 cpu[MAXCPU_29]; +}; + +/************************************************************************/ + +struct perdsk_29 { + char name[MAXDKNAM_29]; /* empty string for last */ + count_t nread; /* number of read transfers */ + count_t nrsect; /* number of sectors read */ + count_t nwrite; /* number of write transfers */ + count_t nwsect; /* number of sectors written */ + count_t io_ms; /* number of millisecs spent for I/O */ + count_t avque; /* average queue length */ + count_t ndisc; /* number of discards (-1 = unavailable)*/ + count_t ndsect; /* number of sectors discarded */ + count_t inflight; /* number of inflight I/O */ + count_t cfuture[3]; /* reserved for future use */ +}; + +struct dskstat_29 { + int ndsk; /* number of physical disks */ + int nmdd; /* number of md volumes */ + int nlvm; /* number of logical volumes */ + struct perdsk_29 dsk[MAXDSK_29]; + struct perdsk_29 mdd[MAXMDD_29]; + struct perdsk_29 lvm[MAXLVM_29]; +}; + +/************************************************************************/ + +struct perintf_29 { + char name[16]; /* empty string for last */ + + count_t rbyte; /* number of read bytes */ + count_t rpack; /* number of read packets */ + count_t rerrs; /* receive errors */ + count_t rdrop; /* receive drops */ + count_t rfifo; /* receive fifo */ + count_t rframe; /* receive framing errors */ + count_t rcompr; /* receive compressed */ + count_t rmultic;/* receive multicast */ + count_t rfuture[4]; /* reserved for future use */ + + count_t sbyte; /* number of written bytes */ + count_t spack; /* number of written packets */ + count_t serrs; /* transmit errors */ + count_t sdrop; /* transmit drops */ + count_t sfifo; /* transmit fifo */ + count_t scollis;/* collisions */ + count_t scarrier;/* transmit carrier */ + count_t scompr; /* transmit compressed */ + count_t sfuture[4]; /* reserved for future use */ + + char type; /* interface type ('e'/'w'/'v'/'?') */ + long speed; /* interface speed in megabits/second */ + long speedp; /* previous interface speed */ + char duplex; /* full duplex (boolean) */ + count_t cfuture[4]; /* reserved for future use */ +}; + +struct intfstat_29 { + int nrintf; + struct perintf_29 intf[MAXINTF_29]; +}; + +/************************************************************************/ + +struct pernfsmount_29 { + char mountdev[128]; /* mountdevice */ + count_t age; /* number of seconds mounted */ + + count_t bytesread; /* via normal reads */ + count_t byteswrite; /* via normal writes */ + count_t bytesdread; /* via direct reads */ + count_t bytesdwrite; /* via direct writes */ + count_t bytestotread; /* via reads */ + count_t bytestotwrite; /* via writes */ + count_t pagesmread; /* via mmap reads */ + count_t pagesmwrite; /* via mmap writes */ + + count_t future[8]; +}; + +struct nfsstat_29 { + struct { + count_t netcnt; + count_t netudpcnt; + count_t nettcpcnt; + count_t nettcpcon; + + count_t rpccnt; + count_t rpcbadfmt; + count_t rpcbadaut; + count_t rpcbadcln; + + count_t rpcread; + count_t rpcwrite; + + count_t rchits; /* repcache hits */ + count_t rcmiss; /* repcache misses */ + count_t rcnoca; /* uncached requests */ + + count_t nrbytes; /* read bytes */ + count_t nwbytes; /* written bytes */ + + count_t future[8]; + } server; + + struct { + count_t rpccnt; + count_t rpcretrans; + count_t rpcautrefresh; + + count_t rpcread; + count_t rpcwrite; + + count_t future[8]; + } client; + + struct { + int nrmounts; + struct pernfsmount nfsmnt[MAXNFSMOUNT_29]; + } nfsmounts; +}; + +/************************************************************************/ +struct psi_29 { + float avg10; // average pressure last 10 seconds + float avg60; // average pressure last 60 seconds + float avg300; // average pressure last 300 seconds + count_t total; // total number of milliseconds +}; + +struct pressure_29 { + char present; /* pressure stats supported? */ + char future[3]; + struct psi_29 cpusome; /* pressure stall info 'some' */ + struct psi_29 memsome; /* pressure stall info 'some' */ + struct psi_29 memfull; /* pressure stall info 'full' */ + struct psi_29 iosome; /* pressure stall info 'some' */ + struct psi_29 iofull; /* pressure stall info 'full' */ +}; + +/************************************************************************/ + +struct percontainer_29 { + unsigned long ctid; /* container id */ + unsigned long numproc; /* number of processes */ + + count_t system; /* */ + count_t user; /* */ + count_t nice; /* */ + count_t uptime; /* */ + + count_t physpages; /* */ +}; + +struct contstat_29 { + int nrcontainer; + struct percontainer_29 cont[MAXCONTAINER_29]; +}; + +/************************************************************************/ +/* +** experimental stuff for access to local HTTP daemons +*/ +#define HTTPREQ "GET /server-status?auto HTTP/1.1\nHost: localhost\n\n" + +struct wwwstat_29 { + count_t accesses; /* total number of HTTP-requests */ + count_t totkbytes; /* total kbytes transfer for HTTP-req */ + count_t uptime; /* number of seconds since startup */ + int bworkers; /* number of busy httpd-daemons */ + int iworkers; /* number of idle httpd-daemons */ +}; + +/************************************************************************/ +struct pergpu_29 { + char taskstats; // GPU task statistics supported? + unsigned char nrprocs; // number of processes using GPU + char type[MAXGPUTYPE_29+1]; // GPU type + char busid[MAXGPUBUS_29+1]; // GPU bus identification + int gpunr; // GPU number + int gpupercnow; // processor percentage last second + // -1 if not supported + int mempercnow; // memory percentage last second + // -1 if not supported + count_t memtotnow; // total memory in KiB + count_t memusenow; // used memory in KiB + count_t samples; // number of samples + count_t gpuperccum; // cumulative processor busy percentage + // -1 if not supported + count_t memperccum; // cumulative memory percentage + // -1 if not supported + count_t memusecum; // cumulative used memory in KiB +}; + +struct gpustat_29 { + int nrgpus; // total number of GPUs + struct pergpu_29 gpu[MAXGPU_29]; +}; + +/************************************************************************/ +struct perifb_29 { + char ibname[MAXIBNAME_29]; // InfiniBand controller + short portnr; // InfiniBand controller port + + short lanes; // number of lanes (traffic factor) + count_t rate; // transfer rate in megabits/sec + count_t rcvb; // bytes received + count_t sndb; // bytes transmitted + count_t rcvp; // packets received + count_t sndp; // packets transmitted +}; + +struct ifbstat_29 { + int nrports; // total number of IB ports + struct perifb_29 ifb[MAXIBPORT_29]; +}; + +/************************************************************************/ +struct perllc_29 { + unsigned char id; + float occupancy; + count_t mbm_local; + count_t mbm_total; +}; + +struct llcstat_29 { + unsigned char nrllcs; // total number of LLC + struct perllc_29 perllc[MAXLLC_29]; +}; + +/************************************************************************/ + +struct sstat_29 { + struct cpustat_29 cpu; + struct memstat_29 mem; + struct netstat_29 net; + struct intfstat_29 intf; + struct memnuma_29 memnuma; + struct cpunuma_29 cpunuma; + struct dskstat_29 dsk; + struct nfsstat_29 nfs; + struct contstat_29 cfs; + struct pressure_29 psi; + struct gpustat_29 gpu; + struct ifbstat_29 ifb; + struct llcstat_29 llc; + + struct wwwstat_29 www; +}; diff -Nru atop-2.8.1/procdbase.c atop-2.9.0/procdbase.c --- atop-2.8.1/procdbase.c 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/procdbase.c 2023-05-13 08:20:27.000000000 +0000 @@ -30,32 +30,6 @@ ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ** -------------------------------------------------------------------------- -** -** $Log: procdbase.c,v $ -** Revision 1.8 2010/04/23 12:19:35 gerlof -** Modified mail-address in header. -** -** Revision 1.7 2007/11/05 12:12:31 gerlof -** Match processes not only on pid, but also on start time. -** -** Revision 1.6 2005/10/21 09:50:19 gerlof -** Per-user accumulation of resource consumption. -** -** Revision 1.5 2003/07/07 09:26:40 gerlof -** Cleanup code (-Wall proof). -** -** Revision 1.4 2002/10/03 11:19:58 gerlof -** Modify (effective) uid/gid to real uid/gid. -** -** Revision 1.3 2002/07/24 11:13:50 gerlof -** Changed to ease porting to other UNIX-platforms. -** -** Revision 1.2 2002/07/08 09:29:07 root -** Call to calloc i.s.o. malloc + memset. -** -** Revision 1.1 2001/10/02 10:43:33 gerlof -** Initial revision -** */ #include diff -Nru atop-2.8.1/rawlog.h atop-2.9.0/rawlog.h --- atop-2.8.1/rawlog.h 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/rawlog.h 2023-05-13 08:20:27.000000000 +0000 @@ -26,6 +26,9 @@ ** -------------------------------------------------------------------------- */ +#ifndef __RAWLOG__ +#define __RAWLOG__ + /* ** structure describing the raw file contents ** @@ -90,3 +93,5 @@ unsigned int noverflow; /* number of overflow processes */ unsigned int ifuture[6]; /* future use */ }; + +#endif diff -Nru atop-2.8.1/showgeneric.c atop-2.9.0/showgeneric.c --- atop-2.8.1/showgeneric.c 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/showgeneric.c 2023-05-13 08:20:27.000000000 +0000 @@ -63,7 +63,6 @@ static struct sselection syssel; static void showhelp(int); -static int paused; /* boolean: currently in pause-mode */ static int fixedhead; /* boolean: fixate header-lines */ static int sysnosort; /* boolean: suppress sort of resources */ static int threadsort; /* boolean: sort threads per process */ @@ -90,6 +89,8 @@ static short colorcrit = COLOR_RED; static short colorthread = COLOR_YELLOW; +int paused; /* boolean: currently in pause-mode */ + static int cumusers(struct tstat **, struct tstat *, int); static int cumprogs(struct tstat **, struct tstat *, int); static int cumconts(struct tstat **, struct tstat *, int); @@ -99,7 +100,8 @@ static void limitedlines(void); static long getnumval(char *, long, int); static void generic_init(void); - +static char text_samp(time_t, int, struct devtstat *, + struct sstat *, int, unsigned int, char); static int (*procsort[])(const void *, const void *) = { [MSORTCPU&0x1f]=compcpu, @@ -117,16 +119,157 @@ int startoffset; /* -** print the deviation-counters on process- and system-level +** main function to handle sample generically +** to show flat text, full screen text or bar graphs */ char generic_samp(time_t curtime, int nsecs, struct devtstat *devtstat, struct sstat *sstat, int nexit, unsigned int noverflow, char flag) { - static int callnr = 0; - char *p; + static char firstcall = 1; + char retval, sorted = 0; + + if (firstcall) + { + generic_init(); + firstcall = 0; + } + + while (1) + { + if (displaymode == 'T') // text mode? + { + // show sample and wait for input or timer expiration + // + switch (retval = text_samp(curtime, nsecs, + devtstat, sstat, nexit, noverflow, flag)) + { + case MBARGRAPH: + displaymode = 'D'; + break; + + default: + return retval; + } + + sorted = 1; // resources have been sorted by text mode + } + + if (displaymode == 'D') // draw mode? + { + // show sample and wait for input or timer expiration + // + switch (retval = draw_samp(curtime, nsecs, sstat, flag, sorted)) + { + case MBARGRAPH: // just switch to text mode + displaymode = 'T'; + break; + + case MPROCGEN: // switch to text mode: generic + showtype = MPROCGEN; + + if (showorder != MSORTAUTO) + showorder = MSORTCPU; + + displaymode = 'T'; + break; + + case MPROCMEM: // switch to text mode: memory + showtype = MPROCMEM; + + if (showorder != MSORTAUTO) + showorder = MSORTMEM; + displaymode = 'T'; + break; + + case MPROCDSK: // switch to text mode: disk + if (supportflags & IOSTAT) + { + showtype = MPROCDSK; + + if (showorder != MSORTAUTO) + showorder = MSORTDSK; + } + else + { + showtype = MPROCGEN; + showorder = MSORTCPU; + } + + displaymode = 'T'; + break; + + case MPROCNET: // switch to text mode: network + if (supportflags & NETATOP) + { + showtype = MPROCNET; + + if (showorder != MSORTAUTO) + showorder = MSORTNET; + } + else + { + showtype = MPROCGEN; + showorder = MSORTCPU; + } + + displaymode = 'T'; + break; + + case MPROCGPU: // switch to text mode: GPU + if (supportflags & GPUSTAT) + { + showtype = MPROCGPU; + + if (showorder != MSORTAUTO) + showorder = MSORTGPU; + } + else + { + showtype = MPROCGEN; + showorder = MSORTCPU; + } + + displaymode = 'T'; + break; + + case MPROCSCH: // switch to text mode: scheduling + showtype = MPROCSCH; + + if (showorder != MSORTAUTO) + showorder = MSORTCPU; + + displaymode = 'T'; + break; + + case MPROCVAR: // switch to text mode: various + showtype = MPROCVAR; + + displaymode = 'T'; + break; + + case MPROCARG: // switch to text mode: arguments + showtype = MPROCARG; + + default: + return retval; + } + } + } +} + +/* +** print the deviation-counters on process- and system-level +** in text mode +*/ +static char +text_samp(time_t curtime, int nsecs, + struct devtstat *devtstat, struct sstat *sstat, + int nexit, unsigned int noverflow, char flag) +{ + char *p; register int i, curline, statline, nproc; int firstproc = 0, plistsz, alistsz, killpid, killsig; @@ -194,15 +337,8 @@ struct tstat **sellist = 0; int nsel = 0; char slastorder = 0; - char threadallowed = 0; - - if (callnr == 0) /* first call? */ - generic_init(); - - callnr++; - startoffset = 0; /* @@ -422,7 +558,7 @@ { clrtoeol(); if (usecolors) - attron(COLOR_PAIR(COLORINFO)); + attron(COLOR_PAIR(FGCOLORINFO)); } printg(statmsg); @@ -430,7 +566,7 @@ if (screen) { if (usecolors) - attroff(COLOR_PAIR(COLORINFO)); + attroff(COLOR_PAIR(FGCOLORINFO)); } statmsg = NULL; @@ -465,7 +601,7 @@ if (screen) { if (usecolors) - attron(COLOR_PAIR(COLORINFO)); + attron(COLOR_PAIR(FGCOLORINFO)); attron(A_BLINK); } @@ -475,7 +611,7 @@ if (screen) { if (usecolors) - attroff(COLOR_PAIR(COLORINFO)); + attroff(COLOR_PAIR(FGCOLORINFO)); attroff(A_BLINK); printg("%*s", COLS - strlen(initmsg) @@ -492,7 +628,7 @@ if (screen) { if (usecolors) - attron(COLOR_PAIR(COLORALMOST)); + attron(COLOR_PAIR(FGCOLORALMOST)); attron(A_BLINK); } @@ -502,7 +638,7 @@ if (screen) { if (usecolors) - attroff(COLOR_PAIR(COLORALMOST)); + attroff(COLOR_PAIR(FGCOLORALMOST)); attroff(A_BLINK); } @@ -915,6 +1051,14 @@ cleanstop(0); /* + ** switch to bar graph mode + */ + case MBARGRAPH: + erase(); + refresh(); + return lastchar; + + /* ** manual trigger for next sample */ case MSAMPNEXT: @@ -2369,6 +2513,8 @@ curstat->gen.nthr += curproc->gen.nthr; curstat->cpu.utime += curproc->cpu.utime; curstat->cpu.stime += curproc->cpu.stime; + curstat->cpu.nvcsw += curproc->cpu.nvcsw; + curstat->cpu.nivcsw += curproc->cpu.nivcsw; if (curproc->dsk.wsz > curproc->dsk.cwsz) nett_wsz = curproc->dsk.wsz -curproc->dsk.cwsz; @@ -2856,7 +3002,7 @@ /* ** install catch-routine to finish in a controlled way - ** and activate cbreak-mode + ** and activate cbreak mode */ if (screen) { @@ -2881,13 +3027,17 @@ noecho(); keypad(stdscr, TRUE); - if (COLS < 30) + /* + ** verify minimal dimensions + */ + if (COLS < MINCOLUMNS || LINES < MINLINES) { - endwin(); // finish curses interface + endwin(); // finish ncurses interface - fprintf(stderr, "Not enough columns available\n" - "(need at least %d columns)\n", 30); - fprintf(stderr, "Please resize window....\n"); + fprintf(stderr, + "Terminal size should be at least " + "%d columns by %d lines\n", + MINCOLUMNS, MINLINES); cleanstop(1); } @@ -2897,10 +3047,54 @@ use_default_colors(); start_color(); - init_pair(COLORINFO, colorinfo, -1); - init_pair(COLORALMOST, coloralmost, -1); - init_pair(COLORCRIT, colorcrit, -1); - init_pair(COLORTHR, colorthread, -1); + // color definitions + // + init_color(COLOR_MYORANGE, 675, 500, 50); + init_color(COLOR_MYGREEN, 0, 600, 100); + init_color(COLOR_MYGREY, 240, 240, 240); + + init_color(COLOR_MYBROWN1, 420, 160, 160); + init_color(COLOR_MYBROWN2, 735, 280, 280); + + init_color(COLOR_MYBLUE0, 50, 50, 300); + init_color(COLOR_MYBLUE1, 50, 300, 500); + init_color(COLOR_MYBLUE2, 50, 500, 800); + init_color(COLOR_MYBLUE3, 100, 350, 600); + init_color(COLOR_MYBLUE4, 150, 500, 700); + init_color(COLOR_MYBLUE5, 200, 650, 800); + + init_color(COLOR_MYGREEN0, 90, 300, 0); + init_color(COLOR_MYGREEN1, 90, 400, 100); + init_color(COLOR_MYGREEN2, 90, 600, 100); + + // color pair definitions (foreground/background) + // + init_pair(FGCOLORINFO, colorinfo, -1); + init_pair(FGCOLORALMOST, coloralmost, -1); + init_pair(FGCOLORCRIT, colorcrit, -1); + init_pair(FGCOLORTHR, colorthread, -1); + init_pair(FGCOLORBORDER, COLOR_CYAN, -1); + + init_pair(WHITE_GREEN, COLOR_WHITE, COLOR_MYGREEN); + init_pair(WHITE_ORANGE, COLOR_WHITE, COLOR_MYORANGE); + init_pair(WHITE_RED, COLOR_WHITE, COLOR_RED); + init_pair(WHITE_GREY, COLOR_WHITE, COLOR_MYGREY); + init_pair(WHITE_BLUE, COLOR_WHITE, COLOR_BLUE); + init_pair(WHITE_MAGENTA, COLOR_WHITE, COLOR_MAGENTA); + + init_pair(WHITE_BROWN1, COLOR_WHITE, COLOR_MYBROWN1); + init_pair(WHITE_BROWN2, COLOR_WHITE, COLOR_MYBROWN2); + + init_pair(WHITE_BLUE0, COLOR_WHITE, COLOR_MYBLUE0); + init_pair(WHITE_BLUE1, COLOR_WHITE, COLOR_MYBLUE1); + init_pair(WHITE_BLUE2, COLOR_WHITE, COLOR_MYBLUE2); + init_pair(WHITE_BLUE3, COLOR_WHITE, COLOR_MYBLUE3); + init_pair(WHITE_BLUE4, COLOR_WHITE, COLOR_MYBLUE4); + init_pair(WHITE_BLUE5, COLOR_WHITE, COLOR_MYBLUE5); + + init_pair(WHITE_GREEN0, COLOR_WHITE, COLOR_MYGREEN0); + init_pair(WHITE_GREEN1, COLOR_WHITE, COLOR_MYGREEN1); + init_pair(WHITE_GREEN2, COLOR_WHITE, COLOR_MYGREEN2); } else { @@ -2912,6 +3106,9 @@ signal(SIGTERM, cleanstop); } + + + /* ** show help information in interactive mode */ @@ -2919,7 +3116,11 @@ char *helpline; char helparg; } helptext[] = { - {"Figures shown for active processes:\n", ' '}, + {"Display mode:\n", ' '}, + {"\t'%c' - show bar graphs for system utilization (toggle)\n", + MBARGRAPH}, + {"\n", ' '}, + {"Information in text mode for active processes:\n", ' '}, {"\t'%c' - generic info (default)\n", MPROCGEN}, {"\t'%c' - memory details\n", MPROCMEM}, {"\t'%c' - disk details\n", MPROCDSK}, @@ -2930,7 +3131,6 @@ {"\t'%c' - various info (ppid, user/group, date/time, status, " "exitcode)\n", MPROCVAR}, {"\t'%c' - full command line per process\n", MPROCARG}, - {"\t'%c' - cgroup v2 info per process\n", MPROCCGR}, {"\t'%c' - use own output line definition\n", MPROCOWN}, {"\n", ' '}, {"Sort list of processes in order of:\n", ' '}, @@ -2965,12 +3165,11 @@ {"Screen-handling:\n", ' '}, {"\t^L - redraw the screen \n", ' '}, {"\tPgDn - show next page in the process list (or ^F)\n", ' '}, - {"\tArDn - arrow-down for next line in process list\n", ' '}, {"\tPgUp - show previous page in the process list (or ^B)\n", ' '}, + {"\tArDn - arrow-down for next line in process list\n", ' '}, {"\tArUp arrow-up for previous line in process list\n", ' '}, - {"\n", ' '}, {"\tArRt - arrow-right for next character in full command line\n", ' '}, - {"\tArLt - arrow-left for previous character in full command line\n", + {"\tArLt - arrow-left for previous character in full command line\n", ' '}, {"\n", ' '}, {"Presentation (keys shown in header line):\n", ' '}, @@ -3046,35 +3245,55 @@ */ if (i >= winlines-2 && shown >= tobeshown) { - wmove (helpwin, winlines-1, 0); + int inputkey; + + wmove(helpwin, winlines-1, 0); wclrtoeol(helpwin); - wprintw (helpwin, "Press 'q' to leave help, " - "space for next page or " - "other key for next line... "); + wprintw(helpwin, "Press q (leave help), " + "space (next page), " + "Enter (next line) or select key..."); + + keypad(helpwin, 1); // recognize keypad keys - switch (wgetch(helpwin)) + switch (inputkey = wgetch(helpwin)) { + case KEY_NPAGE: + case KEY_PPAGE: + case KEY_UP: + case KEY_DOWN: + case KEY_LEFT: + case KEY_RIGHT: + break; // ignore keypad keys + case 'q': delwin(helpwin); return; + case ' ': shown = 0; tobeshown = winlines-1; break; - default: + + case '\n': shown = 0; tobeshown = 1; + break; + + default: + ungetch(inputkey); + delwin(helpwin); + return; } - wmove (helpwin, winlines-1, 0); + wmove(helpwin, winlines-1, 0); } } - wmove (helpwin, winlines-1, 0); + wmove(helpwin, winlines-1, 0); wclrtoeol(helpwin); - wprintw (helpwin, "End of help - press 'q' to leave help... "); - while ( wgetch(helpwin) != 'q' ); - delwin (helpwin); + wprintw(helpwin, "End of help - press 'q' to leave help..."); + while (wgetch(helpwin) != 'q'); + delwin(helpwin); } /* @@ -3242,9 +3461,6 @@ } } -extern int get_posval(char *name, char *val); - - void do_maxcpu(char *name, char *val) { @@ -3382,6 +3598,14 @@ case '-': break; + case MBARGRAPH: + displaymode = 'D'; + break; + + case MBARMONO: + barmono = 1; + break; + case MSORTCPU: showorder = MSORTCPU; break; diff -Nru atop-2.8.1/showgeneric.h atop-2.9.0/showgeneric.h --- atop-2.8.1/showgeneric.h 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/showgeneric.h 2023-05-13 08:20:27.000000000 +0000 @@ -21,10 +21,19 @@ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ** See the GNU General Public License for more details. */ +#ifndef __SHOWGENERIC__ +#define __SHOWGENERIC__ + #define USERSTUB 9999999 #define MAXUSERSEL 64 #define MAXPID 32 +// minimum screen dimensions +// +#define MINLINES 24 +#define MINCOLUMNS 60 + + struct syscap { int nrcpu; count_t availcpu; @@ -71,12 +80,82 @@ }; /* -** color names +** color definitions +*/ +#define COLOR_MYORANGE 20 +#define COLOR_MYGREEN 21 +#define COLOR_MYGREY 22 + +#define COLOR_MYBROWN1 24 +#define COLOR_MYBROWN2 25 + +#define COLOR_MYBLUE0 26 +#define COLOR_MYBLUE1 27 +#define COLOR_MYBLUE2 28 +#define COLOR_MYBLUE3 29 +#define COLOR_MYBLUE4 30 +#define COLOR_MYBLUE5 31 + +#define COLOR_MYGREEN0 35 +#define COLOR_MYGREEN1 36 +#define COLOR_MYGREEN2 37 + +/* +** color pair definitions +*/ +#define FGCOLORBORDER 1 +#define FGCOLORINFO 2 +#define FGCOLORALMOST 3 +#define FGCOLORCRIT 4 +#define FGCOLORTHR 5 + +#define WHITE_GREEN 10 +#define WHITE_ORANGE 11 +#define WHITE_RED 12 +#define WHITE_GREY 13 +#define WHITE_BLUE 14 +#define WHITE_MAGENTA 15 + +#define WHITE_BROWN1 18 +#define WHITE_BROWN2 19 + +#define WHITE_BLUE0 20 +#define WHITE_BLUE1 21 +#define WHITE_BLUE2 22 +#define WHITE_BLUE3 23 +#define WHITE_BLUE4 24 +#define WHITE_BLUE5 25 + +#define WHITE_GREEN0 30 +#define WHITE_GREEN1 31 +#define WHITE_GREEN2 32 + +/* +** text and bar color selections */ -#define COLORINFO 2 -#define COLORALMOST 3 -#define COLORCRIT 4 -#define COLORTHR 5 +#define COLOROKAY WHITE_GREEN +#define COLORWARN WHITE_ORANGE +#define COLORBAD WHITE_RED + +#define COLORCPUSYS WHITE_BLUE1 +#define COLORCPUUSR WHITE_BLUE2 +#define COLORCPUIDLE WHITE_BLUE3 +#define COLORCPUSTEAL WHITE_BLUE4 +#define COLORCPUGUEST WHITE_BLUE5 + +#define COLORMEMFREE WHITE_GREEN +#define COLORMEMCACH WHITE_ORANGE +#define COLORMEMUSED WHITE_GREY +#define COLORMEMSHM WHITE_BROWN1 +#define COLORMEMTMP WHITE_BLUE +#define COLORMEMSLAB WHITE_MAGENTA +#define COLORMEMBAR WHITE_BLUE3 + +#define COLORDSKREAD WHITE_GREEN1 +#define COLORDSKWRITE WHITE_GREEN2 + +#define COLORNETRECV WHITE_BROWN1 +#define COLORNETSEND WHITE_BROWN2 /* ** list with keystrokes/flags @@ -139,6 +218,15 @@ #define MHELP1 '?' #define MHELP2 'h' +#define MBARGRAPH 'B' +#define MBARLOWER 'L' +#define MBARMONO 'H' + +/* +** extern pause indication +*/ +extern int paused; + /* ** general function prototypes */ @@ -161,3 +249,26 @@ int priproc(struct tstat **, int, int, int, int, int, char, char, struct syscap *, int, int); void priphead(int, int, char *, char *, char, count_t); + +char draw_samp(time_t, int, struct sstat *, char, char); + +void do_username(char *, char *); +void do_procname(char *, char *); +void do_maxcpu(char *, char *); +void do_maxgpu(char *, char *); +void do_maxdisk(char *, char *); +void do_maxmdd(char *, char *); +void do_maxlvm(char *, char *); +void do_maxintf(char *, char *); +void do_maxifb(char *, char *); +void do_maxnfsm(char *, char *); +void do_maxcont(char *, char *); +void do_maxnuma(char *, char *); +void do_maxllc(char *, char *); +void do_colinfo(char *, char *); +void do_colalmost(char *, char *); +void do_colcrit(char *, char *); +void do_colthread(char *, char *); +void do_flags(char *, char *); + +#endif diff -Nru atop-2.8.1/showlinux.c atop-2.9.0/showlinux.c --- atop-2.8.1/showlinux.c 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/showlinux.c 2023-05-13 08:20:27.000000000 +0000 @@ -32,233 +32,6 @@ ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ** -------------------------------------------------------------------------- -** -** $Log: showlinux.c,v $ -** Revision 1.70 2010/10/23 14:04:12 gerlof -** Counters for total number of running and sleep threads (JC van Winkel). -** -** Revision 1.69 2010/05/18 19:20:08 gerlof -** Introduce CPU frequency and scaling (JC van Winkel). -** -** Revision 1.68 2010/04/23 12:19:35 gerlof -** Modified mail-address in header. -** -** Revision 1.67 2010/04/17 17:20:33 gerlof -** Allow modifying the layout of the columns in the system lines. -** -** Revision 1.66 2010/03/16 21:14:46 gerlof -** Program and user selection can be combined with program and user -** accumulation. -** -** Revision 1.65 2010/03/04 10:53:26 gerlof -** Support I/O-statistics on logical volumes and MD devices. -** -** Revision 1.64 2010/01/18 18:06:28 gerlof -** Modified priorities for system-level columns. -** -** Revision 1.63 2010/01/16 12:54:33 gerlof -** Corrected order of columns. -** -** Revision 1.62 2010/01/16 11:38:02 gerlof -** Corrected counters for patched kernels (JC van Winkel). -** -** Revision 1.61 2010/01/08 11:25:56 gerlof -** Corrected column-width and priorities of network-stats. -** -** Revision 1.60 2010/01/03 18:27:19 gerlof -** *** empty log message *** -** -** Revision 1.59 2009/12/19 21:01:28 gerlof -** Improved syntax checking for ownprocline keyword (JC van Winkel). -** -** Revision 1.58 2009/12/17 11:59:28 gerlof -** Gather and display new counters: dirty cache and guest cpu usage. -** -** Revision 1.57 2009/12/17 10:51:19 gerlof -** Allow own defined process line with key 'o' and a definition -** in the atoprc file. -** -** Revision 1.56 2009/12/17 09:13:19 gerlof -** Reformatted some fields for better grouping of info. -** -** Revision 1.55 2009/12/12 10:11:18 gerlof -** Register and display end date and end time for process. -** -** Revision 1.54 2009/12/12 09:06:48 gerlof -** \Corrected cumulated disk I/O per user/program (JC van Winkel). -** -** Revision 1.53 2009/12/10 14:02:39 gerlof -** Add EUID, SUID and FSUID (and similar for GID's). -** -** Revision 1.52 2009/12/10 11:56:34 gerlof -** Various bug-solutions. -** -** Revision 1.51 2009/12/10 10:08:01 gerlof -** Major redesign for improved user interface (variable number of columns). -** Made by JC van Winkel. -** -** Revision 1.49 2008/03/06 08:38:28 gerlof -** Register/show ppid of a process. -** -** Revision 1.48 2008/01/18 07:37:05 gerlof -** Show information about the state of the individual threads -** in the scheduling report shown with keystroke 's'. -** -** Revision 1.47 2008/01/07 11:34:18 gerlof -** Correct the sort-order of network-interfaces (on busy-percentage). -** -** Revision 1.46 2007/11/07 09:23:29 gerlof -** Modified format for avg1, avg5 and avg15 (CPL) when counters too large. -** -** Revision 1.45 2007/11/05 11:43:25 gerlof -** Bug-solution for new-process indicator on 64-bits machines. -** -** Revision 1.44 2007/11/05 10:57:56 gerlof -** Bug-solution for huge exit code on 64-bits machines. -** -** Revision 1.43 2007/08/17 09:45:57 gerlof -** Experimental: gather info about HTTP statistics. -** -** Revision 1.42 2007/08/16 12:02:04 gerlof -** Add support for atopsar reporting. -** Concerns modification of networking-counters. -** -** Revision 1.41 2007/07/04 10:18:16 gerlof -** Bug-solution for division by zero. -** -** Revision 1.40 2007/07/03 09:02:29 gerlof -** Support Apache-statistics. -** -** Revision 1.39 2007/03/22 10:12:54 gerlof -** Support for io counters (>= kernel 2.6.20). -** -** Revision 1.38 2007/03/21 14:22:24 gerlof -** Handle io counters maintained from 2.6.20 -** -** Revision 1.37 2007/02/13 10:36:09 gerlof -** Removal of external declarations. -** Use of hertz variable instead of HZ. -** -** Revision 1.36 2007/01/26 12:11:07 gerlof -** Add configuration-value 'swoutcritsec'. -** -** Revision 1.35 2007/01/26 10:25:42 gerlof -** Introduce steal percentage for virtual machines. -** Correct bug: when one interface is colored all subsequent interfaces -** are colored. -** -** Revision 1.34 2007/01/18 10:58:45 gerlof -** Only check for committed limit if it is not zero. -** -** Revision 1.33 2007/01/18 10:37:09 gerlof -** Add support for colors. -** Add support for automatic determination of most critical resource. -** Add support for parsing of new arguments in ~/.atoprc -** -** Revision 1.32 2006/11/13 13:48:46 gerlof -** Implement load-average counters, context-switches and interrupts. -** -** Revision 1.31 2006/02/07 08:38:49 gerlof -** Swapped the zombie counter and exit counter in the PRC-line. -** -** Revision 1.30 2006/02/07 08:30:07 gerlof -** Add possibility to show counters per second. -** Ease parsing of output-lines by fixed number of columns per line. -** -** Revision 1.29 2006/01/30 09:24:12 gerlof -** PRC-line: 'exits' modified to 'exit' to save space. -** -** Revision 1.28 2006/01/30 09:14:26 gerlof -** Extend memory counters (a.o. page scans). -** -** Revision 1.27 2005/11/04 14:16:45 gerlof -** Minor bug-solutions. -** -** Revision 1.26 2005/10/28 09:51:29 gerlof -** All flags/subcommands are defined as macro's. -** Subcommand 'p' has been changed to 'z' (pause). -** -** Revision 1.25 2005/10/21 09:51:11 gerlof -** Per-user accumulation of resource consumption. -** -** Revision 1.24 2004/12/14 15:06:48 gerlof -** Implementation of patch-recognition for disk and network-statistics. -** -** Revision 1.23 2004/10/28 08:31:41 gerlof -** New counter: vm committed space -** -** Revision 1.22 2004/09/24 10:02:46 gerlof -** Wrong cpu-numbers for system level statistics. -** -** Revision 1.21 2004/09/23 08:21:10 gerlof -** Added wait-percentage per cpu. -** -** Revision 1.20 2004/09/23 07:37:34 gerlof -** Consistent handling of CPU percentages on system-level and process-level. -** -** Revision 1.19 2004/09/13 09:20:21 gerlof -** Modify subcommands (former 's' -> 'v', 'v' -> 'V', new 's'). -** -** Revision 1.18 2004/09/02 10:55:21 root -** Added sleep-average to process-info. -** -** Revision 1.17 2004/08/31 09:53:31 gerlof -** Show information about underlying threads. -** -** Revision 1.16 2004/06/01 11:58:34 gerlof -** Regular expressions for selections on process-name and user-name. -** -** Revision 1.15 2004/05/06 09:47:59 gerlof -** Ported to kernel-version 2.6. -** -** Revision 1.14 2003/07/07 09:27:34 gerlof -** Cleanup code (-Wall proof). -** -** Revision 1.13 2003/07/03 12:04:25 gerlof -** Minor bug fixes. -** -** Revision 1.12 2003/06/30 11:29:57 gerlof -** Enlarge counters to 'long long'. -** -** Revision 1.11 2003/06/24 06:22:10 gerlof -** Limit number of system resource lines. -** -** Revision 1.10 2003/02/07 10:43:22 gerlof -** Solved a division-by-zero bug for process-percentage. -** -** Revision 1.9 2003/01/24 14:20:57 gerlof -** If possible, also show commandline when process has exited. -** -** Revision 1.8 2003/01/17 07:32:49 gerlof -** Show the full command-line per process (option 'c'). -** -** Revision 1.7 2002/10/04 10:05:54 gerlof -** Bug-solution: New process indicator in static output set when needed. -** -** Revision 1.6 2002/10/03 11:14:42 gerlof -** Modify (effective) uid/gid to real uid/gid. -** -** Revision 1.5 2002/09/26 13:52:51 gerlof -** Limit header lines by not showing disks. -** Limit header lines by not showing disks. -** -** Revision 1.4 2002/09/16 08:59:13 gerlof -** Change field EXCODE to STATUS for support of indicator of newly created -** processes. -** -** Revision 1.3 2002/09/02 08:42:44 gerlof -** Bug-solution: blank line after header when more than 999 screens of -** process-list information. -** -** Revision 1.2 2002/08/30 07:11:20 gerlof -** Minor changes in the header-line of the process list. -** -** Revision 1.1 2002/07/24 11:14:16 gerlof -** Initial revision -** -** -** Initial -** */ #include @@ -285,6 +58,9 @@ #include "showlinux.h" static void make_proc_dynamicgen(void); +static int get_perc(char *, char *); +static void make_proc_prints(proc_printpair *, int, const char *, + const char *); /* ** critical percentages for occupation-percentage; @@ -294,7 +70,7 @@ int gpubadness = 100; /* percentage */ int membadness = 90; /* percentage */ int swpbadness = 80; /* percentage */ -int dskbadness = 70; /* percentage */ +int dskbadness = 90; /* percentage */ int netbadness = 90; /* percentage */ int pagbadness = 10; /* number per second */ @@ -616,6 +392,8 @@ &procprt_RUNDELAY, &procprt_BLKDELAY, &procprt_WCHAN, + &procprt_NVCSW, + &procprt_NIVCSW, &procprt_VGROW, &procprt_RGROW, &procprt_MINFLT, @@ -922,12 +700,12 @@ } /* - * make_proc_prints: make array of proc_printpairs - * input: string, proc_printpair array, maxentries - */ -void +** make_proc_prints: make array of proc_printpairs +** input: string, proc_printpair array, maxentries +*/ +static void make_proc_prints(proc_printpair *ar, int maxn, const char *pairs, -const char *linename) + const char *linename) { name_prio items[MAXITEMS]; int n=strlen(pairs); @@ -1494,7 +1272,8 @@ make_proc_prints(schedprocs, MAXITEMS, "PID:10 TID:6 CID:4 VPID:3 CTID:3 TRUN:7 TSLPI:7 " "TSLPU:7 POLI:8 NICE:9 PRI:5 RTPR:9 CPUNR:8 ST:8 " - "EXC:8 S:8 RDELAY:8 BDELAY:7 WCHAN:5 SORTITEM:10 CMD:10", + "EXC:8 S:8 RDELAY:8 BDELAY:7 WCHAN:5 " + "NVCSW:7 NIVCSW:7 SORTITEM:10 CMD:10", "built-in schedprocs"); make_proc_prints(dskprocs, MAXITEMS, @@ -3059,7 +2838,7 @@ return value; } -int +static int get_perc(char *name, char *val) { int value = get_posval(name, val); diff -Nru atop-2.8.1/showlinux.h atop-2.9.0/showlinux.h --- atop-2.8.1/showlinux.h 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/showlinux.h 2023-05-13 08:20:27.000000000 +0000 @@ -27,13 +27,10 @@ ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ** -------------------------------------------------------------------------- -** -** $Log: showlinux.h,v $ -** Initial revision -** -** Initial -** */ +#ifndef __SHOWLINUX__ +#define __SHOWLINUX__ + #define MAXITEMS 80 /* The maximum number of items per line */ /* @@ -128,6 +125,34 @@ void showprocline(proc_printpair* elemptr, struct tstat *curstat, double perc, int nsecs, int avgval); +void do_cpucritperc(char *, char *); +void do_gpucritperc(char *, char *); +void do_memcritperc(char *, char *); +void do_swpcritperc(char *, char *); +void do_dskcritperc(char *, char *); +void do_netcritperc(char *, char *); +void do_swoutcritsec(char *, char *); +void do_almostcrit(char *, char *); +void do_ownsysprcline(char *, char *); +void do_ownallcpuline(char *, char *); +void do_ownindivcpuline(char *, char *); +void do_owncplline(char *, char *); +void do_owngpuline(char *, char *); +void do_ownmemline(char *, char *); +void do_ownswpline(char *, char *); +void do_ownpagline(char *, char *); +void do_ownmemnumaline(char *, char *); +void do_owncpunumaline(char *, char *); +void do_ownllcline(char *, char *); +void do_owndskline(char *, char *); +void do_ownnettransportline(char *, char *); +void do_ownnetnetline(char *, char *); +void do_ownnetinterfaceline(char *, char *); +void do_owninfinibandline(char *, char *); +void do_ownprocline(char *, char *); + +int get_posval(char *, char *); + extern sys_printdef *prcsyspdefs[]; extern sys_printdef *cpusyspdefs[]; extern sys_printdef *cpisyspdefs[]; @@ -432,6 +457,8 @@ extern proc_printdef procprt_RUNDELAY; extern proc_printdef procprt_BLKDELAY; extern proc_printdef procprt_WCHAN; +extern proc_printdef procprt_NVCSW; +extern proc_printdef procprt_NIVCSW; extern proc_printdef procprt_CGROUP_PATH; extern proc_printdef procprt_CGRCPUWGT; extern proc_printdef procprt_CGRCPUMAX; @@ -467,3 +494,5 @@ extern char *procprt_TCPRASZ_e(struct tstat *, int, int); extern char *procprt_UDPSASZ_e(struct tstat *, int, int); extern char *procprt_UDPRASZ_e(struct tstat *, int, int); + +#endif diff -Nru atop-2.8.1/showprocs.c atop-2.9.0/showprocs.c --- atop-2.8.1/showprocs.c 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/showprocs.c 2023-05-13 08:20:27.000000000 +0000 @@ -53,6 +53,138 @@ #include "showlinux.h" static void format_bandw(char *, count_t); +static void gettotwidth(proc_printpair *, int *, int *, int *); +static int *getspacings(proc_printpair *); + +char *procprt_TID_ae(struct tstat *, int, int); +char *procprt_PID_a(struct tstat *, int, int); +char *procprt_PID_e(struct tstat *, int, int); +char *procprt_PPID_a(struct tstat *, int, int); +char *procprt_PPID_e(struct tstat *, int, int); +char *procprt_VPID_a(struct tstat *, int, int); +char *procprt_VPID_e(struct tstat *, int, int); +char *procprt_CTID_a(struct tstat *, int, int); +char *procprt_CTID_e(struct tstat *, int, int); +char *procprt_CID_a(struct tstat *, int, int); +char *procprt_CID_e(struct tstat *, int, int); +char *procprt_SYSCPU_ae(struct tstat *, int, int); +char *procprt_USRCPU_ae(struct tstat *, int, int); +char *procprt_VGROW_a(struct tstat *, int, int); +char *procprt_VGROW_e(struct tstat *, int, int); +char *procprt_RGROW_a(struct tstat *, int, int); +char *procprt_RGROW_e(struct tstat *, int, int); +char *procprt_MINFLT_ae(struct tstat *, int, int); +char *procprt_MAJFLT_ae(struct tstat *, int, int); +char *procprt_VSTEXT_a(struct tstat *, int, int); +char *procprt_VSTEXT_e(struct tstat *, int, int); +char *procprt_VSIZE_a(struct tstat *, int, int); +char *procprt_VSIZE_e(struct tstat *, int, int); +char *procprt_RSIZE_a(struct tstat *, int, int); +char *procprt_RSIZE_e(struct tstat *, int, int); +char *procprt_PSIZE_a(struct tstat *, int, int); +char *procprt_PSIZE_e(struct tstat *, int, int); +char *procprt_VSLIBS_a(struct tstat *, int, int); +char *procprt_VSLIBS_e(struct tstat *, int, int); +char *procprt_VDATA_a(struct tstat *, int, int); +char *procprt_VDATA_e(struct tstat *, int, int); +char *procprt_VSTACK_a(struct tstat *, int, int); +char *procprt_VSTACK_e(struct tstat *, int, int); +char *procprt_SWAPSZ_a(struct tstat *, int, int); +char *procprt_SWAPSZ_e(struct tstat *, int, int); +char *procprt_LOCKSZ_a(struct tstat *, int, int); +char *procprt_LOCKSZ_e(struct tstat *, int, int); +char *procprt_CMD_a(struct tstat *, int, int); +char *procprt_CMD_e(struct tstat *, int, int); +char *procprt_RUID_ae(struct tstat *, int, int); +char *procprt_EUID_a(struct tstat *, int, int); +char *procprt_EUID_e(struct tstat *, int, int); +char *procprt_SUID_a(struct tstat *, int, int); +char *procprt_SUID_e(struct tstat *, int, int); +char *procprt_FSUID_a(struct tstat *, int, int); +char *procprt_FSUID_e(struct tstat *, int, int); +char *procprt_RGID_ae(struct tstat *, int, int); +char *procprt_EGID_a(struct tstat *, int, int); +char *procprt_EGID_e(struct tstat *, int, int); +char *procprt_SGID_a(struct tstat *, int, int); +char *procprt_SGID_e(struct tstat *, int, int); +char *procprt_FSGID_a(struct tstat *, int, int); +char *procprt_FSGID_e(struct tstat *, int, int); +char *procprt_STDATE_ae(struct tstat *, int, int); +char *procprt_STTIME_ae(struct tstat *, int, int); +char *procprt_ENDATE_a(struct tstat *, int, int); +char *procprt_ENDATE_e(struct tstat *, int, int); +char *procprt_ENTIME_a(struct tstat *, int, int); +char *procprt_ENTIME_e(struct tstat *, int, int); +char *procprt_THR_a(struct tstat *, int, int); +char *procprt_THR_e(struct tstat *, int, int); +char *procprt_TRUN_a(struct tstat *, int, int); +char *procprt_TRUN_e(struct tstat *, int, int); +char *procprt_TSLPI_a(struct tstat *, int, int); +char *procprt_TSLPI_e(struct tstat *, int, int); +char *procprt_TSLPU_a(struct tstat *, int, int); +char *procprt_TSLPU_e(struct tstat *, int, int); +char *procprt_POLI_a(struct tstat *, int, int); +char *procprt_POLI_e(struct tstat *, int, int); +char *procprt_NICE_a(struct tstat *, int, int); +char *procprt_NICE_e(struct tstat *, int, int); +char *procprt_PRI_a(struct tstat *, int, int); +char *procprt_PRI_e(struct tstat *, int, int); +char *procprt_RTPR_a(struct tstat *, int, int); +char *procprt_RTPR_e(struct tstat *, int, int); +char *procprt_CURCPU_a(struct tstat *, int, int); +char *procprt_CURCPU_e(struct tstat *, int, int); +char *procprt_ST_a(struct tstat *, int, int); +char *procprt_ST_e(struct tstat *, int, int); +char *procprt_EXC_a(struct tstat *, int, int); +char *procprt_EXC_e(struct tstat *, int, int); +char *procprt_S_a(struct tstat *, int, int); +char *procprt_S_e(struct tstat *, int, int); +char *procprt_COMMAND_LINE_ae(struct tstat *, int, int); +char *procprt_NPROCS_ae(struct tstat *, int, int); +char *procprt_RDDSK_a(struct tstat *, int, int); +char *procprt_RDDSK_e(struct tstat *, int, int); +char *procprt_WRDSK_a(struct tstat *, int, int); +char *procprt_WRDSK_e(struct tstat *, int, int); +char *procprt_CWRDSK_a(struct tstat *, int, int); +char *procprt_WCANCEL_a(struct tstat *, int, int); +char *procprt_WCANCEL_e(struct tstat *, int, int); +char *procprt_BANDWI_a(struct tstat *, int, int); +char *procprt_BANDWI_e(struct tstat *, int, int); +char *procprt_BANDWO_a(struct tstat *, int, int); +char *procprt_BANDWO_e(struct tstat *, int, int); +char *procprt_GPULIST_ae(struct tstat *, int, int); +char *procprt_GPUMEMNOW_ae(struct tstat *, int, int); +char *procprt_GPUMEMAVG_ae(struct tstat *, int, int); +char *procprt_GPUGPUBUSY_ae(struct tstat *, int, int); +char *procprt_GPUMEMBUSY_ae(struct tstat *, int, int); +char *procprt_WCHAN_a(struct tstat *, int, int); +char *procprt_WCHAN_e(struct tstat *, int, int); +char *procprt_RUNDELAY_a(struct tstat *, int, int); +char *procprt_RUNDELAY_e(struct tstat *, int, int); +char *procprt_BLKDELAY_a(struct tstat *, int, int); +char *procprt_BLKDELAY_e(struct tstat *, int, int); +char *procprt_NVCSW_a(struct tstat *, int, int); +char *procprt_NVCSW_e(struct tstat *, int, int); +char *procprt_NIVCSW_a(struct tstat *, int, int); +char *procprt_NIVCSW_e(struct tstat *, int, int); +char *procprt_CGROUP_PATH_a(struct tstat *, int, int); +char *procprt_CGROUP_PATH_e(struct tstat *, int, int); +char *procprt_CGRCPUWGT_a(struct tstat *, int, int); +char *procprt_CGRCPUWGT_e(struct tstat *, int, int); +char *procprt_CGRCPUMAX_a(struct tstat *, int, int); +char *procprt_CGRCPUMAX_e(struct tstat *, int, int); +char *procprt_CGRCPUMAXR_a(struct tstat *, int, int); +char *procprt_CGRCPUMAXR_e(struct tstat *, int, int); +char *procprt_CGRMEMMAX_a(struct tstat *, int, int); +char *procprt_CGRMEMMAX_e(struct tstat *, int, int); +char *procprt_CGRMEMMAXR_a(struct tstat *, int, int); +char *procprt_CGRMEMMAXR_e(struct tstat *, int, int); +char *procprt_CGRSWPMAX_a(struct tstat *, int, int); +char *procprt_CGRSWPMAX_e(struct tstat *, int, int); +char *procprt_CGRSWPMAXR_a(struct tstat *, int, int); +char *procprt_CGRSWPMAXR_e(struct tstat *, int, int); +char *procprt_SORTITEM_ae(struct tstat *, int, int); + static char *columnhead[] = { [MSORTCPU]= "CPU", [MSORTMEM]= "MEM", @@ -84,7 +216,7 @@ * sumwidth: (ref) returns the total width of the printitems in the array * varwidth: (ref) returns the number of variable width items in the array */ -void +static void gettotwidth(proc_printpair* elemptr, int *nitems, int *sumwidth, int* varwidth) { int i; @@ -116,7 +248,7 @@ * * Note: this function is only to be called when screen is true. */ -int * +static int * getspacings(proc_printpair* elemptr) { static int spacings[MAXITEMS]; @@ -324,7 +456,7 @@ { if (usecolors && !curstat->gen.isproc) { - attron(COLOR_PAIR(COLORTHR)); + attron(COLOR_PAIR(FGCOLORTHR)); } else { @@ -370,7 +502,7 @@ { if (usecolors && !curstat->gen.isproc) { - attroff(COLOR_PAIR(COLORTHR)); + attroff(COLOR_PAIR(FGCOLORTHR)); } else { @@ -2060,6 +2192,42 @@ { "BDELAY", "BDELAY", procprt_BLKDELAY_a, procprt_BLKDELAY_e, 6}; /***************************************************************/ char * +procprt_NVCSW_a(struct tstat *curstat, int avgval, int nsecs) +{ + static char buf[64]; + + val2valstr(curstat->cpu.nvcsw, buf, 6, avgval, nsecs); + return buf; +} + +char * +procprt_NVCSW_e(struct tstat *curstat, int avgval, int nsecs) +{ + return " -"; +} + +proc_printdef procprt_NVCSW = + { " NVCSW", "NVCSW", procprt_NVCSW_a, procprt_NVCSW_e, 6 }; +/***************************************************************/ +char * +procprt_NIVCSW_a(struct tstat *curstat, int avgval, int nsecs) +{ + static char buf[64]; + + val2valstr(curstat->cpu.nivcsw, buf, 6, avgval, nsecs); + return buf; +} + +char * +procprt_NIVCSW_e(struct tstat *curstat, int avgval, int nsecs) +{ + return " -"; +} + +proc_printdef procprt_NIVCSW = + { "NIVCSW", "NIVCSW", procprt_NIVCSW_a, procprt_NIVCSW_e, 6 }; +/***************************************************************/ +char * procprt_CGROUP_PATH_a(struct tstat *curstat, int avgval, int nsecs) { extern proc_printdef procprt_CGROUP_PATH; diff -Nru atop-2.8.1/showsys.c atop-2.9.0/showsys.c --- atop-2.8.1/showsys.c 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/showsys.c 2023-05-13 08:20:27.000000000 +0000 @@ -52,6 +52,11 @@ #include "showgeneric.h" #include "showlinux.h" +static void addblanks(double *, double *); +static void sumscaling(struct sstat *, count_t *, count_t *, count_t *); +static void psiformatavg(struct psi *, char *, char *, int); +static void psiformattot(struct psi *, char *, extraparam *, int *, char *, int); + /*******************************************************************/ /* ** print the label of a system-statistics line and switch on @@ -68,9 +73,9 @@ if (usecolors) { - attron(COLOR_PAIR(COLORCRIT)); + attron(COLOR_PAIR(FGCOLORCRIT)); printg(labeltext); - attroff(COLOR_PAIR(COLORCRIT)); + attroff(COLOR_PAIR(FGCOLORCRIT)); } else { @@ -81,16 +86,16 @@ attroff(A_BLINK); - return COLORCRIT; + return FGCOLORCRIT; } if (almostcrit && badness >= almostcrit) { if (usecolors) { - attron(COLOR_PAIR(COLORALMOST)); + attron(COLOR_PAIR(FGCOLORALMOST)); printg(labeltext); - attroff(COLOR_PAIR(COLORALMOST)); + attroff(COLOR_PAIR(FGCOLORALMOST)); } else { @@ -99,7 +104,7 @@ attroff(A_BOLD); } - return COLORALMOST; + return FGCOLORALMOST; } } @@ -112,7 +117,7 @@ static char *sysprt_BLANKBOX(struct sstat *sstat, extraparam *notused, int, int *); -void +static void addblanks(double *charslackused, double *charslackover) { *charslackused+=*charslackover; @@ -240,9 +245,9 @@ color = 0; if (badness >= 100) - color = COLORCRIT; + color = FGCOLORCRIT; else if (almostcrit && badness >= almostcrit) - color = COLORALMOST; + color = FGCOLORALMOST; } if (color) // after all: has a color been set? @@ -357,10 +362,10 @@ static char buf[15]="#zombie "; if (as->nzomb > 30) - *color = COLORALMOST; + *color = FGCOLORALMOST; if (as->nzomb > 50) - *color = COLORCRIT; + *color = FGCOLORCRIT; val2valstr(as->nzomb, buf+8, 4, 0, 0); return buf; @@ -378,7 +383,7 @@ { if (as->noverflow) { - *color = COLORCRIT; + *color = FGCOLORCRIT; buf[6] = '>'; val2valstr(as->nexit, buf+7, 5, as->avgval, as->nsecs); } @@ -393,12 +398,12 @@ { if (firstcall) { - *color = COLORCRIT; + *color = FGCOLORCRIT; firstcall = 0; } else { - *color = COLORINFO; + *color = FGCOLORINFO; } switch (acctreason) @@ -588,10 +593,10 @@ /* - * sumscaling: sum scaling info for all processors - * - */ -void sumscaling(struct sstat *sstat, count_t *maxfreq, +** sumscaling: sum scaling info for all processors +*/ +static void +sumscaling(struct sstat *sstat, count_t *maxfreq, count_t *cnt, count_t *ticks) { count_t mymaxfreq = 0; @@ -814,7 +819,7 @@ break; case 1: - *color = COLORINFO; + *color = FGCOLORINFO; sprintf(buf, "ipc initial"); break; @@ -847,7 +852,7 @@ break; case 1: - *color = COLORINFO; + *color = FGCOLORINFO; sprintf(buf, "ipc initial"); break; @@ -876,7 +881,7 @@ break; case 1: - *color = COLORINFO; + *color = FGCOLORINFO; sprintf(buf+5, "initial"); break; @@ -902,7 +907,7 @@ break; case 1: - *color = COLORINFO; + *color = FGCOLORINFO; sprintf(buf+5, "initial"); break; @@ -966,7 +971,7 @@ static char buf[15]="avg15 "; if (sstat->cpu.lavg15 > (2 * sstat->cpu.nrcpu) ) - *color = COLORALMOST; + *color = FGCOLORALMOST; if (sstat->cpu.lavg15 > 99999.0) { @@ -1094,7 +1099,7 @@ sstat->gpu.gpu[as->index].samples; if (perc >= 40) - *color = COLORALMOST; + *color = FGCOLORALMOST; snprintf(buf+8, sizeof buf-8, "%3d%%", perc); } @@ -1122,7 +1127,7 @@ sstat->gpu.gpu[as->index].samples; if (perc >= 90) - *color = COLORALMOST; + *color = FGCOLORALMOST; snprintf(buf+8, sizeof buf-8, "%3d%%", perc); } @@ -1272,7 +1277,7 @@ { static char buf[16]="pgtab "; *color = -1; - val2memstr(sstat->mem.pagetables * pagesize, buf+6, MBFORMAT, 0, 0); + val2memstr(sstat->mem.pagetables * pagesize, buf+6, MBFORMAT, 0, 0); return buf; } @@ -1578,7 +1583,7 @@ val2memstr(sstat->mem.committed * pagesize, buf+6, MBFORMAT, 0, 0); if (sstat->mem.commitlim && sstat->mem.committed > sstat->mem.commitlim) - *color = COLORALMOST; + *color = FGCOLORALMOST; return buf; } @@ -1592,7 +1597,7 @@ val2memstr(sstat->mem.commitlim * pagesize, buf+6, MBFORMAT, 0, 0); if (sstat->mem.commitlim && sstat->mem.committed > sstat->mem.commitlim) - *color = COLORINFO; + *color = FGCOLORINFO; return buf; } @@ -1710,7 +1715,7 @@ static char buf[16]="oomkill "; if (sstat->mem.oomkills) - *color = COLORCRIT; + *color = FGCOLORCRIT; val2valstr(sstat->mem.oomkills, buf+8, 4, as->avgval, as->nsecs); return buf; @@ -2044,7 +2049,7 @@ sys_printdef syspdef_NUMLLC = {"NUMLLC", sysprt_NUMLLC, NULL}; /*******************************************************************/ // general formatting of PSI field in avg10/avg60/avg300 -void +static void psiformatavg(struct psi *p, char *head, char *buf, int bufsize) { static char formats[] = "%.0f/%.0f/%.0f"; @@ -2068,7 +2073,7 @@ snprintf(tmpbuf, sizeof tmpbuf, formats, avg10, avg60, avg300); } - snprintf(buf, bufsize, "%s %9s", head, tmpbuf); + snprintf(buf, bufsize, "%s %9.9s", head, tmpbuf); } static char * @@ -2118,7 +2123,7 @@ /*******************************************************************/ // general formatting of PSI field in total percentage -void +static void psiformattot(struct psi *p, char *head, extraparam *as, int *color, char *buf, int bufsize) { @@ -2129,7 +2134,7 @@ perc = 100; if (perc >= 1) - *color = COLORALMOST; + *color = FGCOLORALMOST; snprintf(buf, bufsize, formats, head, perc); } diff -Nru atop-2.8.1/various.c atop-2.9.0/various.c --- atop-2.8.1/various.c 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/various.c 2023-05-13 08:20:27.000000000 +0000 @@ -28,74 +28,6 @@ ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ** -------------------------------------------------------------------------- -** -** $Log: various.c,v $ -** Revision 1.21 2010/11/12 06:16:16 gerlof -** Show all parts of timestamp in header line, even when zero. -** -** Revision 1.20 2010/05/18 19:21:08 gerlof -** Introduce CPU frequency and scaling (JC van Winkel). -** -** Revision 1.19 2010/04/28 18:21:11 gerlof -** Cast value larger than 4GB to long long. -** -** Revision 1.18 2010/04/23 12:19:35 gerlof -** Modified mail-address in header. -** -** Revision 1.17 2010/03/26 11:52:45 gerlof -** Introduced unit of Tbytes for memory-usage. -** -** Revision 1.16 2009/12/17 08:28:38 gerlof -** Express CPU-time usage in days and hours for large values. -** -** Revision 1.15 2009/12/10 08:50:39 gerlof -** Introduction of a new function to convert number of seconds -** to a string indicating days, hours, minutes and seconds. -** -** Revision 1.14 2007/02/13 10:32:47 gerlof -** Removal of external declarations. -** Removal of function getpagesz(). -** -** Revision 1.13 2006/02/07 08:27:21 gerlof -** Add possibility to show counters per second. -** Modify presentation of CPU-values. -** -** Revision 1.12 2005/10/31 12:26:09 gerlof -** Modified date-format to yyyy/mm/dd. -** -** Revision 1.11 2005/10/21 09:51:29 gerlof -** Per-user accumulation of resource consumption. -** -** Revision 1.10 2004/05/06 09:46:24 gerlof -** Ported to kernel-version 2.6. -** -** Revision 1.9 2003/07/07 09:27:46 gerlof -** Cleanup code (-Wall proof). -** -** Revision 1.8 2003/07/03 11:16:59 gerlof -** Minor bug solutions. -** -** Revision 1.7 2003/06/30 11:31:17 gerlof -** Enlarge counters to 'long long'. -** -** Revision 1.6 2003/06/24 06:22:24 gerlof -** Limit number of system resource lines. -** -** Revision 1.5 2002/08/30 07:49:09 gerlof -** Convert a hh:mm string into a number of seconds since 00:00. -** -** Revision 1.4 2002/08/27 12:08:37 gerlof -** Modified date format (from yyyy/mm/dd to mm/dd/yyyy). -** -** Revision 1.3 2002/07/24 11:14:05 gerlof -** Changed to ease porting to other UNIX-platforms. -** -** Revision 1.2 2002/07/11 09:43:36 root -** Modified HZ into sysconf(_SC_CLK_TCK). -** -** Revision 1.1 2001/10/02 10:43:36 gerlof -** Initial revision -** */ #include @@ -113,10 +45,14 @@ #include #include #include +#include #include "atop.h" #include "acctproc.h" + +static unsigned long long getbootlinux(long); + /* ** Function convtime() converts a value (number of seconds since ** 1-1-1970) to an ascii-string in the format hh:mm:ss, stored in @@ -711,7 +647,6 @@ getboot(void) { static unsigned long long boottime; - unsigned long long getbootlinux(long); if (!boottime) /* do this only once */ boottime = getbootlinux(hertz); @@ -719,6 +654,70 @@ return boottime; } + +/* +** LINUX SPECIFIC: +** Determine boot-time of this system (as number of jiffies since 1-1-1970). +*/ +static unsigned long long +getbootlinux(long hertz) +{ + int cpid; + char tmpbuf[1280]; + FILE *fp; + unsigned long startticks; + unsigned long long bootjiffies = 0; + struct timespec ts; + + /* + ** dirty hack to get the boottime, since the + ** Linux 2.6 kernel (2.6.5) does not return a proper + ** boottime-value with the times() system call :-( + */ + if ( (cpid = fork()) == 0 ) + { + /* + ** child just waiting to be killed by parent + */ + pause(); + } + else + { + /* + ** parent determines start-time (in jiffies since boot) + ** of the child and calculates the boottime in jiffies + ** since 1-1-1970 + */ + (void) clock_gettime(CLOCK_REALTIME, &ts); // get current + bootjiffies = 1LL * ts.tv_sec * hertz + + 1LL * ts.tv_nsec * hertz / 1000000000LL; + + snprintf(tmpbuf, sizeof tmpbuf, "/proc/%d/stat", cpid); + + if ( (fp = fopen(tmpbuf, "r")) != NULL) + { + if ( fscanf(fp, "%*d (%*[^)]) %*c %*d %*d %*d %*d " + "%*d %*d %*d %*d %*d %*d %*d %*d " + "%*d %*d %*d %*d %*d %*d %lu", + &startticks) == 1) + { + bootjiffies -= startticks; + } + + fclose(fp); + } + + /* + ** kill the child and get rid of the zombie + */ + kill(cpid, SIGKILL); + (void) wait((int *)0); + } + + return bootjiffies; +} + + /* ** generic pointer verification after malloc */ diff -Nru atop-2.8.1/versdate.h atop-2.9.0/versdate.h --- atop-2.8.1/versdate.h 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/versdate.h 2023-05-13 08:20:27.000000000 +0000 @@ -1 +1,4 @@ -#define ATOPDATE "2023/01/07 14:27:57" +#ifndef __ATOP_VERSDATA__ +#define __ATOP_VERSDATA__ +#define ATOPDATE "2023/05/13 09:34:24" +#endif diff -Nru atop-2.8.1/version.h atop-2.9.0/version.h --- atop-2.8.1/version.h 2023-01-07 13:28:51.000000000 +0000 +++ atop-2.9.0/version.h 2023-05-13 08:20:27.000000000 +0000 @@ -1 +1,9 @@ -#define ATOPVERS "2.8.1" +#ifndef __ATOP_VERSION__ +#define __ATOP_VERSION__ + +#define ATOPVERS "2.9.0" + +char *getstrvers(void); +unsigned short getnumvers(void); + +#endif