atop-2.4.0/0000775000203100020310000000000013416466037011774 5ustar gerlofgerlofatop-2.4.0/acctproc.c0000664000203100020310000006154113416466037013745 0ustar gerlofgerlof/* ** 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 functions to manipulate with process-accounting ** features (switch it on/off and read the process-accounting records). ** ================================================================ ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Date: November 1996 ** LINUX-port: June 2000 ** ** 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. ** ** $Log: acctproc.c,v $ ** Revision 1.28 2010/04/23 12:20:19 gerlof ** Modified mail-address in header. ** ** Revision 1.27 2009/12/12 10:12:01 gerlof ** Register and display end date and end time for process. ** ** Revision 1.26 2008/03/06 08:37:25 gerlof ** Register/show ppid of a process. ** ** Revision 1.25 2008/01/14 09:22:23 gerlof ** Support for environment variable ATOPACCT to specify the name of a ** particular process accouting file. ** ** Revision 1.24 2007/08/17 08:50:26 gerlof ** Verify if private accounting used before switching off accounting. ** ** Revision 1.23 2007/03/20 13:01:51 gerlof ** Introduction of variable supportflags. ** ** Revision 1.22 2007/02/13 09:14:49 gerlof ** New boolean introduced to indicate if accounting is active. ** ** Revision 1.21 2006/02/07 06:46:15 gerlof ** Removed swap-counter. ** ** Revision 1.20 2005/11/04 14:17:10 gerlof ** Improved recognition of certain version process accounting file. ** ** Revision 1.19 2005/10/31 12:44:58 gerlof ** Support account-record version 3 (used by Mandriva). ** ** Revision 1.18 2005/10/31 08:55:05 root ** *** empty log message *** ** ** Revision 1.17 2004/12/14 15:05:00 gerlof ** Implementation of patch-recognition for disk and network-statistics. ** ** Revision 1.16 2004/06/01 11:57:22 gerlof ** Consider other standard accounting-files, i.e. /var/account/pacct. ** ** Revision 1.15 2004/05/06 09:48:21 gerlof ** Ported to kernel-version 2.6. ** ** Revision 1.14 2003/07/07 09:26:15 gerlof ** Cleanup code (-Wall proof). ** ** Revision 1.13 2003/07/02 06:43:11 gerlof ** Modified include-file sys/acct.h to linux/acct.h to make it ** work on Alpha-based systems as well. ** ** Revision 1.12 2003/06/27 12:31:24 gerlof ** Adapt long to long long. ** ** Revision 1.11 2003/04/03 08:32:58 gerlof ** Cosmetic changes. ** ** Revision 1.10 2003/01/14 09:01:45 gerlof ** Small cosmetic changes. ** ** Revision 1.9 2002/10/03 11:12:03 gerlof ** Modify (effective) uid/gid to real uid/gid. ** ** Revision 1.8 2002/07/24 11:11:12 gerlof ** Redesigned to ease porting to other UNIX-platforms. ** ** Revision 1.7 2002/07/11 07:28:29 root ** Some additions related to secure accounting file handling ** ** Revision 1.6 2002/07/08 09:14:54 root ** Modified secure handling of accounting file ** (inspired by Tobias Rittweiler). ** ** Revision 1.5 2001/11/07 09:16:55 gerlof ** Allow users to run atop without process-accounting switched on. ** ** Revision 1.4 2001/10/16 06:15:52 gerlof ** Partly redesigned. ** ** Revision 1.3 2001/10/04 13:02:24 gerlof ** Redesign of the way to determine how many atop's are using process-accounting ** on basis of semaphores. ** ** Revision 1.2 2001/10/04 08:46:46 gerlof ** Improved verification of kernel-symbol addresses ** ** Revision 1.1 2001/10/02 10:38:35 gerlof ** Initial revision ** */ #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include #include #include #include #include "atop.h" #include "photoproc.h" #include "acctproc.h" #include "atopacctd.h" #define ACCTDIR "/var/cache/atop.d" #define ACCTFILE "atop.acct" #define ACCTENV "ATOPACCT" static char acctatop; /* boolean: atop's own accounting busy ? */ static off_t acctsize; /* previous size of account file */ static int acctrecsz; /* size of account record */ static int acctversion; /* version of account record layout */ static int acctfd = -1; /* fd of account file (-1 = not open) */ static long curshadowseq; /* current shadow file sequence number */ static long maxshadowrec; /* number of records per shadow file */ static char *pacctdir = PACCTDIR; static count_t acctexp (comp_t ct); static int acctvers(int); static void acctrestarttrial(); static void switchshadow(void); struct pacctadm { char *name; struct stat stat; } pacctadm[] = { { "/var/log/pacct", {0, }, }, { "/var/account/pacct", {0, }, } }; /* ** Semaphore-handling ** ** A semaphore-group with two semaphores is created ** ** 0 - Binary semaphore (mutex) to get access to active atop-counter ** ** 1 - Active atop-counter (inverted). ** This semaphore is initialized at some high value and is ** decremented by every atop-incarnation which uses the private ** accounting-file and incremented as soon as such atop stops again. ** If an atop-incarnation stops and it appears to be the last one ** using the private accounting-file, accounting is stopped ** and the file removed ** (Yes, I know: it's not proper usage of the semaphore-principle). */ #define ATOPACCTKEY 3121959 #define ATOPACCTTOT 100 struct sembuf semclaim = {0, -1, SEM_UNDO}, semrelse = {0, +1, SEM_UNDO}, semdecre = {1, -1, SEM_UNDO}, semincre = {1, +1, SEM_UNDO}; /* ** switch on the process-accounting mechanism ** ** return value: ** 0 - activated (success) ** 1 - not activated: unreadable accounting file ** 2 - not activated: empty environment variable ATOPACCT ** 3 - not activated: no access to semaphore group ** 4 - not activated: impossible to create own accounting file ** 5 - not activated: no root privileges */ int acctswon(void) { int i, j, sematopid, sempacctpubid; static ushort vals[] = {1, ATOPACCTTOT}; union {ushort *array;} arg = {vals}; struct stat statbuf; char *ep; /* ** when a particular environment variable is present, atop should ** use a specific accounting-file (as defined by the environment ** variable) or should use no process accounting at all (when ** contents of environment variable is empty) */ if ( (ep = getenv(ACCTENV)) ) { /* ** environment variable exists */ if (*ep) { /* ** open active account file with the specified name */ if (! droprootprivs() ) cleanstop(42); if ( (acctfd = open(ep, O_RDONLY) ) == -1) return 1; if ( !acctvers(acctfd) ) { (void) close(acctfd); acctfd = -1; return 1; } supportflags |= ACCTACTIVE; return 0; } else { /* ** no contents */ return 2; } } /* ** when the atopacctd daemon is active on this system, ** it should be the preferred way to read the accounting records */ if ( (sempacctpubid = semget(PACCTPUBKEY, 0, 0)) != -1) { FILE *cfp; char shadowpath[128]; struct flock flock; if (! droprootprivs() ) cleanstop(42); (void) semop(sempacctpubid, &semclaim, 1); snprintf(shadowpath, sizeof shadowpath, "%s/%s/%s", pacctdir, PACCTSHADOWD, PACCTSHADOWC); if ( (cfp = fopen(shadowpath, "r")) ) { if (fscanf(cfp, "%ld/%lu", &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); 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(); return 0; } (void) close(acctfd); } } else { fclose(cfp); maxshadowrec = 0; } } (void) semop(sempacctpubid, &semrelse, 1); } /* ** check if process accounting is already switched on ** for one of the standard accounting-files; in that case we ** open this file and get our info from here .... */ for (i=0, j=0; i < sizeof pacctadm/sizeof pacctadm[0]; i++) { if ( stat(pacctadm[i].name, &pacctadm[i].stat) == 0) j++; } if (j) { /* ** at least one file is present; check if it is really in use ** at this moment for accounting by forking a child-process ** which immediately finishes to force a new accounting-record */ if ( fork() == 0 ) exit(0); /* let the child finish */ (void) wait((int *) 0); /* let the parent wait */ for (i=0; i < sizeof pacctadm/sizeof pacctadm[0]; i++) { if ( stat(pacctadm[i].name, &statbuf) == 0) { /* ** accounting-file has grown? */ if (statbuf.st_size > pacctadm[i].stat.st_size) { /* ** open active account file */ if ( (acctfd = open(pacctadm[i].name, O_RDONLY) ) == -1) return 1; if ( !acctvers(acctfd) ) { (void) close(acctfd); acctfd = -1; return 1; } supportflags |= ACCTACTIVE; return 0; } } } } /* ** process-accounting is not yet switched on in a standard way; ** check if another atop has switched on accounting already ** ** first try to create a semaphore group exclusively; if this succeeds, ** this is the first atop-incarnation since boot and the semaphore group ** should be initialized` */ if ( (sematopid = semget(ATOPACCTKEY, 2, 0600|IPC_CREAT|IPC_EXCL)) >= 0) (void) semctl(sematopid, 0, SETALL, arg); else sematopid = semget(ATOPACCTKEY, 0, 0); /* ** check if we got access to the semaphore group */ if (sematopid == -1) return 3; /* ** the semaphore group is opened now; claim exclusive rights */ (void) semop(sematopid, &semclaim, 1); /* ** are we the first to use the accounting-mechanism ? */ if (semctl(sematopid, 1, GETVAL, 0) == ATOPACCTTOT) { /* ** create a new separate directory below /tmp ** for the accounting file; ** if this directory exists (e.g. previous atop-run killed) ** it will be cleaned and newly created */ if ( mkdir(ACCTDIR, 0700) == -1) { if (errno == EEXIST) { (void) acct(0); (void) unlink(ACCTDIR "/" ACCTFILE); (void) rmdir(ACCTDIR); } if ( mkdir(ACCTDIR, 0700) == -1) { /* ** persistent failure */ (void) semop(sematopid, &semrelse, 1); return 4; } } /* ** create accounting file in new directory */ (void) close( creat(ACCTDIR "/" ACCTFILE, 0600) ); /* ** switch on accounting */ if ( acct(ACCTDIR "/" ACCTFILE) < 0) { (void) unlink(ACCTDIR "/" ACCTFILE); (void) rmdir(ACCTDIR); (void) semop(sematopid, &semrelse, 1); return 5; } } /* ** accounting is switched on now; ** open accounting-file */ if ( (acctfd = open(ACCTDIR "/" ACCTFILE, O_RDONLY) ) < 0) { (void) acct(0); (void) unlink(ACCTDIR "/" ACCTFILE); (void) rmdir(ACCTDIR); (void) semop(sematopid, &semrelse, 1); return 1; } /* ** accounting successfully switched on */ (void) semop(sematopid, &semdecre, 1); (void) semop(sematopid, &semrelse, 1); acctatop = 1; /* ** determine version of accounting-record */ if (fstat(acctfd, &statbuf) == -1) { (void) acct(0); (void) close(acctfd); (void) unlink(ACCTDIR "/" ACCTFILE); (void) rmdir(ACCTDIR); acctfd = -1; return 1; } if (statbuf.st_size == 0) /* no acct record written yet */ { /* ** let's write one record */ if ( fork() == 0 ) exit(0); /* let the child finish */ (void) wait((int *) 0); /* let the parent wait */ } if ( !acctvers(acctfd) ) { (void) acct(0); (void) close(acctfd); (void) unlink(ACCTDIR "/" ACCTFILE); (void) rmdir(ACCTDIR); acctfd = -1; return 1; } supportflags |= ACCTACTIVE; return 0; } /* ** determine the version of the accounting-record layout/length ** and reposition the seek-pointer to the end of the accounting file */ static int acctvers(int fd) { struct acct tmprec; /* ** read first record from accounting file to verify ** the second byte (always contains version number) */ if ( read(fd, &tmprec, sizeof tmprec) < sizeof tmprec) return 0; switch (tmprec.ac_version & 0x0f) { case 2: acctrecsz = sizeof(struct acct); acctversion = 2; break; case 3: acctrecsz = sizeof(struct acct_v3); acctversion = 3; break; default: fprintf(stderr, "Unknown format of process accounting file\n"); cleanstop(8); } /* ** accounting successfully switched on */ acctsize = acctprocnt() * acctrecsz; /* ** reposition to actual file-size */ (void) lseek(fd, acctsize, SEEK_SET); return 1; } /* ** switch off the process-accounting mechanism */ void acctswoff(void) { int sematopid; struct stat before, after; /* ** if accounting not supported, skip call */ if (acctfd == -1) return; /* ** our private accounting-file in use? */ if (acctatop) { acctatop = 0; /* ** claim the semaphore to get exclusive rights for ** the accounting-manipulation */ sematopid = semget(ATOPACCTKEY, 0, 0); (void) semop(sematopid, &semclaim, 1); (void) semop(sematopid, &semincre, 1); /* ** check if we were the last user of accounting */ if (semctl(sematopid, 1, GETVAL, 0) == ATOPACCTTOT) { /* ** switch off private accounting ** ** verify if private accounting is still in use to ** avoid that we switch off process accounting that ** has been activated manually in the meantime */ (void) fstat(acctfd, &before); if ( fork() == 0 ) /* create a child and */ exit(0); /* let the child finish */ (void) wait((int *) 0); /* let the parent wait */ (void) fstat(acctfd, &after); if (after.st_size > before.st_size) { /* ** remove the directory and file */ regainrootprivs(); /* get root privs again */ (void) acct(0); (void) unlink(ACCTDIR "/" ACCTFILE); (void) rmdir(ACCTDIR); if (! droprootprivs() ) cleanstop(42); } } (void) semop(sematopid, &semrelse, 1); } /* ** anyhow close the accounting-file again */ (void) close(acctfd); /* close account file again */ acctfd = -1; supportflags &= ~ACCTACTIVE; } /* ** get the number of exited processes written ** in the process-account file since the previous sample */ unsigned long acctprocnt(void) { 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) { unsigned long numrecs = 0; long newseq; char shadowpath[128]; FILE *cfp; /* ** verify how many new processes are added to the current ** shadow file */ numrecs = (statacc.st_size - acctsize) / acctrecsz; /* ** verify if subsequent shadow files are involved ** (i.e. if the current file is full) */ if (statacc.st_size / acctrecsz < maxshadowrec) return numrecs; /* ** more shadow files available ** get current shadow file */ snprintf(shadowpath, sizeof shadowpath, "%s/%s/%s", pacctdir, PACCTSHADOWD, PACCTSHADOWC); if ( (cfp = fopen(shadowpath, "r")) ) { if (fscanf(cfp, "%ld", &newseq) == 1) { fclose(cfp); } else { fclose(cfp); return numrecs; } } else { return numrecs; } if (newseq == curshadowseq) return numrecs; snprintf(shadowpath, sizeof shadowpath, PACCTSHADOWF, pacctdir, PACCTSHADOWD, newseq); /* ** determine the size of newest shadow file */ if (stat(shadowpath, &statacc) == -1) return numrecs; numrecs += ((newseq - curshadowseq - 1) * maxshadowrec) + (statacc.st_size / acctrecsz); return numrecs; } else /* ** classic process accounting on bases of directly opened ** process accounting file */ { if (acctsize > statacc.st_size) /* accounting reset? */ { /* ** reposition to start of file */ (void) lseek(acctfd, 0, SEEK_SET); acctsize = 0; } return (statacc.st_size - acctsize) / acctrecsz; } } /* ** reposition the seek offset in the process accounting file to skip ** processes that have not been read */ void acctrepos(unsigned int noverflow) { /* ** if accounting not supported, skip call */ if (acctfd == -1) return; if (maxshadowrec) { int i; off_t virtoffset = acctsize + noverflow * acctrecsz; off_t maxshadowsz = maxshadowrec * acctrecsz; long switches = virtoffset / maxshadowsz; acctsize = virtoffset % maxshadowsz; for (i=0; i < switches; i++) switchshadow(); (void) lseek(acctfd, acctsize, SEEK_SET); } else { /* ** just reposition to skip superfluous records */ (void) lseek(acctfd, noverflow * acctrecsz, SEEK_CUR); acctsize += noverflow * acctrecsz; } } /* ** read the process records from the process accounting file, ** that are written since the previous cycle */ unsigned long acctphotoproc(struct tstat *accproc, int nrprocs) { register int nrexit; register struct tstat *api; struct acct acctrec; struct acct_v3 acctrec_v3; struct stat statacc; /* ** if accounting not supported, skip call */ if (acctfd == -1) return 0; /* ** determine the size of the (current) account file ** and the current offset within that file */ if (fstat(acctfd, &statacc) == -1) return 0; /* ** check all exited processes in accounting file */ for (nrexit=0, api=accproc; nrexit < nrprocs; nrexit++, api++, acctsize += acctrecsz) { /* ** in case of shadow accounting files, we might have to ** switch from the current accounting file to the next */ if (maxshadowrec && acctsize >= statacc.st_size) { switchshadow(); /* ** determine the size of the new (current) account file ** and initialize the current offset within that file */ if (fstat(acctfd, &statacc) == -1) return 0; acctsize = 0; } /* ** read the next record */ switch (acctversion) { case 2: if ( read(acctfd, &acctrec, acctrecsz) < acctrecsz ) break; /* unexpected end of account file */ /* ** fill process info from accounting-record */ api->gen.state = 'E'; api->gen.nthr = 1; api->gen.isproc = 1; api->gen.pid = 0; api->gen.tgid = 0; api->gen.ppid = 0; api->gen.excode = acctrec.ac_exitcode; api->gen.ruid = acctrec.ac_uid16; api->gen.rgid = acctrec.ac_gid16; api->gen.btime = acctrec.ac_btime; api->gen.elaps = acctrec.ac_etime; api->cpu.stime = acctexp(acctrec.ac_stime); api->cpu.utime = acctexp(acctrec.ac_utime); api->mem.minflt = acctexp(acctrec.ac_minflt); api->mem.majflt = acctexp(acctrec.ac_majflt); api->dsk.rio = acctexp(acctrec.ac_rw); strcpy(api->gen.name, acctrec.ac_comm); break; case 3: if ( read(acctfd, &acctrec_v3, acctrecsz) < acctrecsz ) break; /* unexpected end of account file */ /* ** fill process info from accounting-record */ api->gen.state = 'E'; api->gen.pid = acctrec_v3.ac_pid; api->gen.tgid = acctrec_v3.ac_pid; api->gen.ppid = acctrec_v3.ac_ppid; api->gen.nthr = 1; api->gen.isproc = 1; api->gen.excode = acctrec_v3.ac_exitcode; api->gen.ruid = acctrec_v3.ac_uid; api->gen.rgid = acctrec_v3.ac_gid; api->gen.btime = acctrec_v3.ac_btime; api->gen.elaps = acctrec_v3.ac_etime; api->cpu.stime = acctexp(acctrec_v3.ac_stime); api->cpu.utime = acctexp(acctrec_v3.ac_utime); api->mem.minflt = acctexp(acctrec_v3.ac_minflt); api->mem.majflt = acctexp(acctrec_v3.ac_majflt); api->dsk.rio = acctexp(acctrec_v3.ac_rw); strcpy(api->gen.name, acctrec_v3.ac_comm); break; } } if (acctsize > ACCTMAXFILESZ && !maxshadowrec) acctrestarttrial(); return nrexit; } /* ** when the size of the private accounting file exceeds a certain limit, ** it might be useful to stop process accounting, truncate the ** process accounting file to zero and start process accounting again ** ** this will only be done if this atop process is the only one ** that is currently using the accounting file */ static void acctrestarttrial() { struct stat statacc; int sematopid; /* ** not private accounting-file in use? */ if (!acctatop) return; // do not restart /* ** still remaining records in accounting file that are ** written between the moment that the number of exited ** processes was counted and the moment that all processes ** were read */ (void) fstat(acctfd, &statacc); if (acctsize != statacc.st_size) return; // do not restart /* ** claim the semaphore to get exclusive rights for ** the accounting-manipulation */ sematopid = semget(ATOPACCTKEY, 0, 0); (void) semop(sematopid, &semclaim, 1); /* ** check if there are more users of accounting file */ if (semctl(sematopid, 1, GETVAL, 0) < ATOPACCTTOT-1) { (void) semop(sematopid, &semrelse, 1); return; // do not restart } /* ** restart is possible ** ** - switch off accounting ** - truncate the file ** - switch on accounting */ regainrootprivs(); // get root privs again (void) acct(0); // switch off accounting if ( truncate(ACCTDIR "/" ACCTFILE, 0) == 0) (void) lseek(acctfd, 0, SEEK_SET); (void) acct(ACCTDIR "/" ACCTFILE); if (! droprootprivs() ) cleanstop(42); acctsize = 0; (void) semop(sematopid, &semrelse, 1); } /* ** expand the special compression-methods */ static count_t acctexp(comp_t ct) { count_t exp; count_t val; exp = (ct >> 13) & 0x7; /* obtain 3 bits base-8 exponent */ val = ct & 0x1fff; /* obtain 13 bits mantissa */ while (exp-- > 0) val <<= 3; return val; } /* ** switch to the next accounting shadow file */ static void switchshadow(void) { int tmpfd; char shadowpath[128]; struct flock flock; /* ** determine path name of new shadow file */ curshadowseq++; snprintf(shadowpath, sizeof shadowpath, PACCTSHADOWF, pacctdir, PACCTSHADOWD, curshadowseq); /* ** open new shadow file, while the previous is also kept open ** (to keep the read lock until a read lock is set for the new ** shadow file) */ if ( (tmpfd = open(shadowpath, O_RDONLY)) != -1) { /* ** set read lock on new shadow file */ flock.l_type = F_RDLCK; flock.l_whence = SEEK_SET; flock.l_start = 0; flock.l_len = 1; if ( fcntl(tmpfd, F_SETLK, &flock) != -1) { (void) close(acctfd); // implicit release read lock acctfd = tmpfd; return; } else { (void) close(tmpfd); } } } /* ** handle the option 'pacctdir' in the /etc/atoprc file */ void do_pacctdir(char *tagname, char *tagvalue) { char shadowpath[128]; struct stat dirstat; /* ** copy the directory pathname to an own buffer */ if ( (pacctdir = malloc(strlen(tagvalue)+1)) == NULL ) { perror("malloc pacctdir"); exit(11); } strcpy(pacctdir, tagvalue); /* ** verify if the atopacctd daemon is active */ if ( semget(PACCTPUBKEY, 0, 0) == -1) { fprintf(stderr, "Warning: option '%s' specified " "while atopacctd not running!\n", tagname); sleep(2); return; } /* ** verify that the topdirectory exists */ if ( stat(pacctdir, &dirstat) == -1 ) { fprintf(stderr, "Warning: option '%s' specified - ", tagname); perror(pacctdir); sleep(2); return; } if (! S_ISDIR(dirstat.st_mode) ) { fprintf(stderr, "Warning: option '%s' specified - ", tagname); fprintf(stderr, "%s not a directory\n", pacctdir); sleep(2); return; } /* ** verify that the topdirectory contains the required subdirectory */ snprintf(shadowpath, sizeof shadowpath, "%s/%s", pacctdir, PACCTSHADOWD); if ( stat(shadowpath, &dirstat) == -1 ) { fprintf(stderr, "Warning: option '%s' specified - ", tagname); perror(shadowpath); sleep(2); return; } if (! S_ISDIR(dirstat.st_mode) ) { fprintf(stderr, "Warning: option '%s' specified - ", tagname); fprintf(stderr, "%s not a directory\n", shadowpath); sleep(2); return; } } atop-2.4.0/acctproc.h0000664000203100020310000001253713416466037013753 0ustar gerlofgerlof/* ** 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. ** ** Include-file for process-accounting functions. ** ================================================================ ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Date: November 1996 ** LINUX-port: June 2000 ** ** 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. */ int acctswon(void); void acctswoff(void); unsigned long acctprocnt(void); unsigned long acctphotoproc(struct tstat *, int); void acctrepos(unsigned int); /* ** maximum number of records to be read from process accounting file ** for one sample, to avoid that atop explodes and introduces OOM killing .... ** ** the maximum is based on a limit of 50 MiB extra memory (approx. 70000 procs) */ #define MAXACCTPROCS (50*1024*1024/sizeof(struct tstat)) /* ** preferred maximum size of process accounting file (200 MiB) */ #define ACCTMAXFILESZ (200*1024*1024) /* ** alternative layout of accounting record if kernel-patch ** has been installed */ #include typedef __u16 comp_t; typedef __u32 comp2_t; #define ACCT_COMM 16 struct acct_atop { char ac_flag; /* Flags */ char ac_version; /* Always set to ACCT_VERSION */ __u32 ac_pid; /* Process ID */ __u32 ac_ppid; /* Parent Process ID */ __u16 ac_uid16; /* LSB of Real User ID */ __u16 ac_gid16; /* LSB of Real Group ID */ __u16 ac_tty; /* Control Terminal */ __u32 ac_btime; /* Process Creation Time */ comp_t ac_utime; /* User Time */ comp_t ac_stime; /* System Time */ comp_t ac_etime; /* Elapsed Time */ comp_t ac_mem; /* Virtual Memory */ comp_t ac_rss; /* Resident Memory */ comp_t ac_io; /* Chars Transferred */ comp_t ac_rw; /* Blocks Read or Written */ comp_t ac_bread; /* Blocks Read */ comp_t ac_bwrite; /* Blocks Written */ comp2_t ac_dskrsz; /* Cum. blocks read */ comp2_t ac_dskwsz; /* Cum. blocks written */ comp_t ac_tcpsnd; /* TCP send requests */ comp_t ac_tcprcv; /* TCP recv requests */ comp2_t ac_tcpssz; /* TCP cum. length */ comp2_t ac_tcprsz; /* TCP cum. length */ comp_t ac_udpsnd; /* UDP send requests */ comp_t ac_udprcv; /* UDP recv requests */ comp2_t ac_udpssz; /* UDP cum. length */ comp2_t ac_udprsz; /* UDP cum. length */ comp_t ac_rawsnd; /* RAW send requests */ comp_t ac_rawrcv; /* RAW recv requests */ comp_t ac_minflt; /* Minor Pagefaults */ comp_t ac_majflt; /* Major Pagefaults */ comp_t ac_swaps; /* Number of Swaps */ /* m68k had no padding here. */ #if !defined(CONFIG_M68K) || !defined(__KERNEL__) __u16 ac_ahz; /* AHZ */ #endif __u32 ac_exitcode; /* Exitcode */ char ac_comm[ACCT_COMM + 1]; /* Command Name */ __u8 ac_etime_hi; /* Elapsed Time MSB */ __u16 ac_etime_lo; /* Elapsed Time LSB */ __u32 ac_uid; /* Real User ID */ __u32 ac_gid; /* Real Group ID */ }; /* ** default layout of accounting record ** (copied from /usr/src/linux/include/linux/acct.h) */ struct acct { char ac_flag; /* Flags */ char ac_version; /* Always set to ACCT_VERSION */ /* for binary compatibility back until 2.0 */ __u16 ac_uid16; /* LSB of Real User ID */ __u16 ac_gid16; /* LSB of Real Group ID */ __u16 ac_tty; /* Control Terminal */ __u32 ac_btime; /* Process Creation Time */ comp_t ac_utime; /* User Time */ comp_t ac_stime; /* System Time */ comp_t ac_etime; /* Elapsed Time */ comp_t ac_mem; /* Average Memory Usage */ comp_t ac_io; /* Chars Transferred */ comp_t ac_rw; /* Blocks Read or Written */ comp_t ac_minflt; /* Minor Pagefaults */ comp_t ac_majflt; /* Major Pagefaults */ comp_t ac_swaps; /* Number of Swaps */ /* m68k had no padding here. */ #if !defined(CONFIG_M68K) || !defined(__KERNEL__) __u16 ac_ahz; /* AHZ */ #endif __u32 ac_exitcode; /* Exitcode */ char ac_comm[ACCT_COMM + 1]; /* Command Name */ __u8 ac_etime_hi; /* Elapsed Time MSB */ __u16 ac_etime_lo; /* Elapsed Time LSB */ __u32 ac_uid; /* Real User ID */ __u32 ac_gid; /* Real Group ID */ }; struct acct_v3 { char ac_flag; /* Flags */ char ac_version; /* Always set to ACCT_VERSION */ __u16 ac_tty; /* Control Terminal */ __u32 ac_exitcode; /* Exitcode */ __u32 ac_uid; /* Real User ID */ __u32 ac_gid; /* Real Group ID */ __u32 ac_pid; /* Process ID */ __u32 ac_ppid; /* Parent Process ID */ __u32 ac_btime; /* Process Creation Time */ #ifdef __KERNEL__ __u32 ac_etime; /* Elapsed Time */ #else float ac_etime; /* Elapsed Time */ #endif comp_t ac_utime; /* User Time */ comp_t ac_stime; /* System Time */ comp_t ac_mem; /* Average Memory Usage */ comp_t ac_io; /* Chars Transferred */ comp_t ac_rw; /* Blocks Read or Written */ comp_t ac_minflt; /* Minor Pagefaults */ comp_t ac_majflt; /* Major Pagefaults */ comp_t ac_swaps; /* Number of Swaps */ char ac_comm[ACCT_COMM]; /* Command Name */ }; atop-2.4.0/atopacctd.c0000664000203100020310000005570013416466037014111 0ustar gerlofgerlof/* ** The atopacctd daemon switches on the process accounting feature ** in the kernel and let the process accounting records be written to ** a file, called the source file. After process accounting is active, ** the atopacctd daemon transfers every process accounting record that ** is available in the source file to a shadow file. ** Client processes (like atop) can read the shadow file instead of ** the original process accounting source file. ** ** This approach has the following advantages: ** ** - The atopacctd daemon keeps the source file to a limited size ** by truncating it regularly. ** ** - The atopacct daemon takes care that a shadow file has a limited size. ** As soon as the current shadow file reaches its maximum size, the ** atopacctd daemon creates a subsequent shadow file. For this reason, ** the name of a shadow file contains a sequence number. ** Shadow files that are not used by client processes any more, are ** automatically removed by the atopacctd daemon. ** ** - When no client processes are active (any more), all shadow files ** will be deleted and no records will be transferred to shadow files ** any more. As soon as at least one client is activated again, the ** atopacctd daemon start writing shadow files again. ** ** The directory /var/run is used as the default top-directory. An ** alternative top-directory can be specified as command line argument ** (in that case, also modify /etc/atoprc to inform atop as a client). ** Below this top-directory the source file pacct_source is created and ** the subdirectory pacct_shadow.d as a 'container' for the shadow files. ** ---------------------------------------------------------------------- ** Copyright (C) 2014 Gerlof Langeveld (gerlof.langeveld@atoptool.nl) ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License version 2 as ** published by the Free Software Foundation. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "atop.h" #include "photoproc.h" #include "acctproc.h" #include "version.h" #include "versdate.h" #include "atopacctd.h" #define RETRYCNT 10 // # retries to read account record #define RETRYMS 25 // timeout (millisec) to read account record #define NORECINTERVAL 3600 // no-record-available interval (seconds) #define PACCTSEC 3 // timeout (sec) to retry switch on pacct #define POLLSEC 1 // timeout (sec) when NETLINK fails #define GCINTERVAL 60 // garbage collection interval (seconds) /* ** Semaphore-handling ** ** Two semaphore groups are created with one semaphore each. ** ** The private semaphore (group) specifies the number of atopacctd processes ** running (to be sure that only one daemon is active at the time). ** ** The public semaphore (group) reflects the number of processes using ** the process accounting shadow files, i.e. the number of clients. This ** semaphore starts at a high value and should be decremented whenever a ** client starts using the shadow files and incremented again whenever that ** client terminates. */ static int semprv; static int sempub; #define SEMTOTAL 100 #define NUMCLIENTS (SEMTOTAL - semctl(sempub, 0, GETVAL, 0)) static char atopacctdversion[] = ATOPVERS; static char atopacctddate[] = ATOPDATE; static unsigned long maxshadowrec = MAXSHADOWREC; static char *pacctdir = PACCTDIR; static char cleanup_and_go = 0; /* ** function prototypes */ static int awaitprocterm(int, int, int, char *, int *, unsigned long *, unsigned long *); static int swonpacct(int, char *); static int createshadow(long); static int pass2shadow(int, char *, int); 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 int main(int argc, char *argv[]) { int i, nfd, afd, sfd; int parentpid; struct stat dirstat; struct rlimit rlim; FILE *pidf; struct sembuf semincr = {0, +1, SEM_UNDO}; char shadowdir[128], shadowpath[128]; char accountpath[128]; unsigned long oldshadow = 0, curshadow = 0; int shadowbusy = 0; time_t gclast = time(0); struct sigaction sigcleanup; /* ** argument passed? */ if (argc == 2) { /* ** version number required (flag -v or -V)? */ if (*argv[1] == '-') // flag? { if ( *(argv[1]+1) == 'v' || *(argv[1]+1) == 'V') { printf("%s \n", getstrvers()); return 0; } else { fprintf(stderr, "Usage: atopacctd [-v|topdirectory]\n" "Default topdirectory: %s\n", PACCTDIR); exit(1); } } /* ** if first argument is not a flag, it should be the name ** of an alternative top directory (to be validated later on) */ pacctdir = argv[1]; } else { if (argc != 1) { fprintf(stderr, "Usage: atopacctd [-v|topdirectory]\n" "Default topdirectory: %s\n", PACCTDIR); exit(1); } } /* ** verify if we are running with the right privileges */ if (geteuid() != 0) { fprintf(stderr, "Root privileges are needed!\n"); exit(1); } /* ** verify that the top directory is not world-writable ** and owned by root */ if ( stat(pacctdir, &dirstat) == -1 ) { perror(pacctdir); fprintf(stderr, "Usage: atopacctd [-v|topdirectory]\n" "Default topdirectory: %s\n", PACCTDIR); exit(2); } if (! S_ISDIR(dirstat.st_mode) ) { fprintf(stderr, "atopacctd: %s is not a directory\n", pacctdir); exit(2); } if (dirstat.st_uid != 0) { fprintf(stderr, "atopacctd: directory %s must be owned by root\n", pacctdir); exit(2); } if (dirstat.st_mode & (S_IWGRP|S_IWOTH)) { fprintf(stderr, "atopacctd: directory %s may not be writable " "for group/others\n", pacctdir); exit(2); } /* ** create the semaphore groups and initialize the semaphores; ** if the private semaphore already exists, verify if another ** atopacctd daemon is already running */ if ( (semprv = semget(PACCTPRVKEY, 0, 0)) >= 0) // exists? { if ( semctl(semprv, 0, GETVAL, 0) > 0) { fprintf(stderr, "atopacctd is already running!\n"); exit(3); } } else { if ( (semprv = semget(PACCTPRVKEY, 1, 0600|IPC_CREAT|IPC_EXCL)) >= 0) { (void) semctl(semprv, 0, SETVAL, 0); } else { perror("cannot create private semaphore"); exit(3); } } if ( (sempub = semget(PACCTPUBKEY, 0, 0)) == -1) // not existing? { if ( (sempub = semget(PACCTPUBKEY, 1, 0666|IPC_CREAT|IPC_EXCL)) >= 0) { (void) semctl(sempub, 0, SETVAL, SEMTOTAL); } else { perror("cannot create public semaphore"); exit(3); } } /* ** 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 (void) sigaction(SIGTERM, &sigcleanup, (struct sigaction *)0); if ( fork() ) // implicitly switch to background { /* ** parent after forking first child: ** wait for signal 15 from child before terminating ** because systemd expects parent to terminate whenever ** service is up and running */ pause(); // wait for signal from child exit(0); // finish parent } setsid(); // become session leader to lose ctty if ( fork() ) // finish parent; continue in child exit(0); // --> no session leader, no ctty getrlimit(RLIMIT_NOFILE, &rlim); for (i=0; i < rlim.rlim_cur; i++) // close all files, but { if (i != 2) // do not close stderr close(i); } umask(022); (void) chdir("/tmp"); // go to a safe place /* ** increase semaphore to define that atopacctd is running */ if ( semop(semprv, &semincr, 1) == -1) { perror("cannot increment private semaphore"); kill(parentpid, SIGTERM); exit(4); } /* ** create source accounting file to which the kernel can write ** its records */ snprintf(accountpath, sizeof accountpath, "%s/%s", pacctdir, PACCTORIG); (void) unlink(accountpath); if ( (afd = creat(accountpath, 0600)) == -1) { perror(accountpath); kill(parentpid, SIGTERM); exit(5); } (void) close(afd); /* ** open the accounting file for read */ if ( (afd = open(accountpath, O_RDONLY)) == -1) { perror(accountpath); kill(parentpid, SIGTERM); exit(5); } /* ** create directory to store the shadow files */ snprintf(shadowdir, sizeof shadowdir, "%s/%s", pacctdir, PACCTSHADOWD); if ( mkdir(shadowdir, 0755) == -1) { perror(shadowdir); kill(parentpid, SIGTERM); exit(5); } sfd = createshadow(curshadow); setcurrent(curshadow); /* ** open syslog interface */ openlog("atopacctd", LOG_PID, LOG_DAEMON); syslog(LOG_INFO, "%s ", getstrvers()); /* ** raise priority (be sure the nice value becomes -20, ** independent of the current nice value) */ (void) nice(-39); /* ** connect to NETLINK socket of kernel to be triggered ** when processes have finished */ if ( (nfd = netlink_open()) == -1) { (void) unlink(accountpath); kill(parentpid, SIGTERM); exit(5); } /* ** switch on accounting - inital */ if ( swonpacct(afd, accountpath) == -1) { (void) unlink(accountpath); kill(parentpid, SIGTERM); exit(6); } syslog(LOG_INFO, "accounting to %s", accountpath); /* ** signal handling */ (void) signal(SIGHUP, SIG_IGN); (void) sigaction(SIGINT, &sigcleanup, (struct sigaction *)0); (void) sigaction(SIGQUIT, &sigcleanup, (struct sigaction *)0); (void) sigaction(SIGTERM, &sigcleanup, (struct sigaction *)0); /* ** create PID file */ if ( (pidf = fopen(PIDFILE, "w")) ) { fprintf(pidf, "%d\n", getpid()); fclose(pidf); } /* ** terminate parent: service initialized */ kill(parentpid, SIGTERM); /* ** main loop */ while (! cleanup_and_go) { int state; /* ** await termination of (at least) one process and ** copy the process accounting record(s) */ state = awaitprocterm(nfd, afd, sfd, accountpath, &shadowbusy, &oldshadow, &curshadow); if (state == -1) // irrecoverable error? break; /* ** verify if garbage collection is needed ** i.e. removal of shadow files that are not in use any more */ if ( shadowbusy && time(0) > gclast + GCINTERVAL ) { gcshadows(&oldshadow, curshadow); gclast = time(0); } } /* ** cleanup and terminate */ (void) acct((char *) 0); // disable process accounting (void) unlink(accountpath); // remove source file for (; oldshadow <= curshadow; oldshadow++) // remove shadow files { /* ** assemble path name of shadow file (starting by oldest) */ snprintf(shadowpath, sizeof shadowpath, PACCTSHADOWF, pacctdir, PACCTSHADOWD, oldshadow); (void) unlink(shadowpath); } snprintf(shadowpath, sizeof shadowpath, "%s/%s/%s", pacctdir, PACCTSHADOWD, PACCTSHADOWC); (void) unlink(shadowpath); // remove file 'current' (void) rmdir(shadowdir); // remove shadow.d directory if (cleanup_and_go) { syslog(LOG_NOTICE, "Terminated by signal %d\n", cleanup_and_go); if (cleanup_and_go == SIGTERM) return 0; else return cleanup_and_go + 128; } else { syslog(LOG_NOTICE, "Terminated!\n"); return 13; } } /* ** wait for at least one process termination and copy process accounting ** record(s) from the source process accounting file to the current ** shadow accounting file ** ** return code: 0 - no process accounting record read ** 1 - at least one process accounting record read ** -1 - irrecoverable failure */ static int awaitprocterm(int nfd, int afd, int sfd, char *accountpath, int *shadowbusyp, unsigned long *oldshadowp, unsigned long *curshadowp) { static int arecsize, netlinkactive = 1; static unsigned long long atotsize, stotsize, maxshadowsz; static time_t reclast; struct timespec retrytimer = {0, RETRYMS/2*1000000}; int retrycount = RETRYCNT; int asz, rv, ssz; char abuf[16000]; int partsz, remsz; /* ** neutral state: ** ** wait for info from NETLINK indicating that at least ** one process has finished; the real contents of the ** NETLINK message is ignored, it is only used as trigger ** that something can be read from the process accounting file ** ** unfortunately it is not possible to use inotify() on the ** source file as a trigger that a new accounting record ** has been written (does not work if the kernel itself ** writes to the file) ** ** when the NETLINK interface fails due to kernel bug 190711, ** we switch to polling mode: ** wait for timer and verify if process accounting ** records are available (repeatedly); ugly but the only ** thing we can do if we can't use NETLINK */ if (netlinkactive) { rv = netlink_recv(nfd, 0); if (rv == 0) // EOF? { syslog(LOG_ERR, "unexpected EOF on NETLINK\n"); perror("unexpected EOF on NETLINK\n"); return -1; } if (rv < 0) // failure? { switch (-rv) { // acceptable errors that might indicate that // processes have terminated case EINTR: case ENOMEM: case ENOBUFS: break; default: syslog(LOG_ERR, "unexpected error on NETLINK: %s\n", strerror(-rv)); fprintf(stderr, "unexpected error on NETLINK: %s\n", strerror(-rv)); if (-rv == EINVAL) { syslog(LOG_ERR, "(see ATOP README about kernel bug 190711)\n"); fprintf(stderr, "(see ATOP README about kernel bug 190711)\n"); } syslog(LOG_ERR, "switching to polling mode\n"); fprintf(stderr, "switching to polling mode\n"); netlinkactive = 0; // polling mode wanted return 0; } } /* ** get rid of all other waiting finished processes via netlink ** before handling the process accounting record(s) */ while ( netlink_recv(nfd, MSG_DONTWAIT) > 0 ); } else // POLLING MODE { sleep(POLLSEC); retrycount = 1; } /* ** read new process accounting record(s) ** such record(s) may not immediately be available (timing matter), ** so some retries might be necessary */ while ((asz = read(afd, abuf, sizeof abuf)) == 0 && --retrycount) { nanosleep(&retrytimer, (struct timespec *)0); retrytimer.tv_nsec = RETRYMS*1000000; } switch (asz) { case 0: // EOF (no records available)? if (time(0) > reclast + NORECINTERVAL && reclast) { syslog(LOG_WARNING, "reactivate process accounting\n"); if (truncate(accountpath, 0) != -1) { lseek(afd, 0, SEEK_SET); atotsize = swonpacct(afd, accountpath); } reclast = time(0); } return 0; // wait for NETLINK again case -1: // failure? syslog(LOG_ERR, "%s - unexpected read error: %s\n", accountpath, strerror(errno)); return -1; } reclast = time(0); /* ** only once: determine the size of an accounting ** record and calculate the maximum size for each ** shadow file */ if (!arecsize) { arecsize = acctsize((struct acct *)abuf); if (arecsize) { maxshadowsz = maxshadowrec * arecsize; } else { syslog(LOG_ERR, "cannot determine size of account record\n"); return -1; } } /* ** truncate process accounting file regularly */ atotsize += asz; // maintain current size if (atotsize >= MAXORIGSZ) { if (truncate(accountpath, 0) != -1) { lseek(afd, 0, SEEK_SET); atotsize = 0; } } /* ** determine if any client is using the shadow ** accounting files; if not, verify if clients ** have been using the shadow files till now and ** cleanup has to be performed */ if (NUMCLIENTS == 0) { /* ** did last client just disappeared? */ if (*shadowbusyp) { /* ** remove all shadow files */ gcshadows(oldshadowp, (*curshadowp)+1); *oldshadowp = 0; *curshadowp = 0; stotsize = 0; /* ** create new file with sequence 0 */ (void) close(sfd); sfd = createshadow(*curshadowp); setcurrent(*curshadowp); *shadowbusyp = 0; } return 1; } *shadowbusyp = 1; /* ** transfer process accounting data to shadow file ** but take care to fill a shadow file exactly ** to its maximum and not more... */ if (stotsize + asz <= maxshadowsz) // would fit? { /* ** pass all data */ if ( (ssz = pass2shadow(sfd, abuf, asz)) > 0) stotsize += ssz; remsz = 0; partsz = 0; } else { /* ** calculate the remainder that has to ** be written to the next shadow file */ partsz = maxshadowsz - stotsize; remsz = asz - partsz; /* ** transfer first part of the data to current ** shadow file */ if ( (ssz = pass2shadow(sfd, abuf, partsz)) > 0) stotsize += ssz; } /* ** verify if current shadow file has reached its ** maximum size; if so, switch to next sequence number ** and write remaining data (if any) */ if (stotsize >= maxshadowsz) { close(sfd); sfd = createshadow(++(*curshadowp)); setcurrent(*curshadowp); stotsize = 0; /* ** transfer remaining part of the data */ if (remsz) { if ( (ssz = pass2shadow(sfd, abuf+partsz, remsz)) > 0) stotsize += ssz; } } return 1; } /* ** create first shadow file with requested sequence number */ static int createshadow(long seq) { int sfd; char shadowpath[128]; snprintf(shadowpath, sizeof shadowpath, PACCTSHADOWF, pacctdir, PACCTSHADOWD, seq); /* ** open the shadow file for write */ if ( (sfd = creat(shadowpath, 0644)) == -1) { perror(shadowpath); exit(5); } return sfd; } /* ** transfer process accounting data to shadow file */ static int pass2shadow(int sfd, char *sbuf, int ssz) { static unsigned long long nrskipped; struct statvfs statvfs; /* ** check if the filesystem is not filled for more than 95% */ if ( fstatvfs(sfd, &statvfs) != -1) { if (statvfs.f_blocks == 0 || statvfs.f_bfree * 100 / statvfs.f_blocks < 5 ) { if (nrskipped == 0) // first skip? { syslog(LOG_WARNING, "Filesystem > 95%% full; " "pacct writing skipped\n"); } nrskipped++; return 0; } } /* ** there is enough space in the filesystem (again) ** verify if writing has been suspended due to lack of space (if so, ** write a log message) */ if (nrskipped) { syslog(LOG_WARNING, "Pacct writing continued (%llu skipped)\n", nrskipped); nrskipped = 0; } /* ** transfer process accounting record(s) to shadow file */ if ( write(sfd, sbuf, ssz) == -1 ) { syslog(LOG_ERR, "Unexpected write error to shadow file: %s\n", strerror(errno)); exit(7); } return ssz; } /* ** switch on the process accounting mechanism ** first parameter: file descriptor of open accounting file ** second parameter: name of accounting file ** return value: -1 in case of permanent failure, ** otherwise number of bytes read from accounting file */ static int swonpacct(int afd, char *accountpath) { int n, acctokay = 0; char abuf[4096]; /* ** due to kernel bug 190271 (process accounting sometimes ** does not work), we verify if process accounting really ** works after switching it on. If not, we keep retrying ** for a while. */ while (! acctokay) { int maxcnt = 40; /* ** switch on process accounting */ if ( acct(accountpath) == -1) { perror("cannot switch on process accounting"); return -1; } /* ** try if process accounting works by spawning a ** child process that immediately finishes (should ** result in a process accounting record) */ if ( fork() == 0 ) exit(0); (void) wait((int *)0); // wait for child to finish while ( (n = read(afd, abuf, sizeof abuf)) <= 0 && --maxcnt) usleep(50000); if (n > 0) // process accounting works { acctokay = 1; } else { syslog(LOG_ERR, "Retrying to switch on process accounting\n"); syslog(LOG_ERR, "(see ATOP README about kernel bug 190271)\n"); acct((char *)0); // switch off process accounting sleep(PACCTSEC); // wait a while before retrying } } return n; } /* ** remove old shadow files not being in use any more ** ** When a reading process (atop) opens a shadow file, ** it places a read lock on the first byte of that file. ** More then one read lock is allowed on that first byte ** (in case of more atop incarnations). ** If at least one read lock exists, a write lock (to be ** tried here) will fail which means that the file is still ** in use by at least one reader. */ static void gcshadows(unsigned long *oldshadowp, unsigned long curshadow) { struct flock flock; int tmpsfd; char shadowpath[128]; /* ** fill flock structure: write lock on first byte */ flock.l_type = F_WRLCK; flock.l_whence = SEEK_SET; flock.l_start = 0; flock.l_len = 1; for (; *oldshadowp < curshadow; (*oldshadowp)++) { /* ** assemble path name of shadow file (starting by oldest) */ snprintf(shadowpath, sizeof shadowpath, PACCTSHADOWF, pacctdir, PACCTSHADOWD, *oldshadowp); /* ** try to open oldest existing file for write ** and verify if it is in use */ if ( (tmpsfd = open(shadowpath, O_WRONLY)) == -1) break; if ( fcntl(tmpsfd, F_SETLK, &flock) == -1) // no-wait trial { close(tmpsfd); break; // setting lock failed, so still in use } /* ** lock successfully set, so file is unused: remove file; ** closing the file implicitly removes the succeeded lock */ (void) close(tmpsfd); (void) unlink(shadowpath); } } /* ** write sequence number of current (newest) file */ static void setcurrent(long curshadow) { static int cfd = -1; char currentpath[128], currentdata[128]; int len; /* ** assemble file name of currency file and open (only once) */ if (cfd == -1) { snprintf(currentpath, sizeof currentpath, "%s/%s/%s", pacctdir, PACCTSHADOWD, PACCTSHADOWC); if ( (cfd = creat(currentpath, 0644)) == -1) { syslog(LOG_ERR, "Could not create currency file: %s\n", strerror(errno)); return; } } /* ** assemble ASCII string to be written: seqnumber/maxrecords */ len = snprintf(currentdata, sizeof currentdata, "%ld/%lu", curshadow, maxshadowrec); /* ** wipe currency file and write new assembled string */ (void) ftruncate(cfd, 0); (void) lseek(cfd, 0, SEEK_SET); (void) write(cfd, currentdata, len); } /* ** determine the size of an accounting record */ static int acctsize(struct acct *parec) { switch (parec->ac_version & 0x0f) { case 2: return sizeof(struct acct); case 3: return sizeof(struct acct_v3); default: return 0; } } /* ** generate version number and date */ char * getstrvers(void) { static char vers[256]; snprintf(vers, sizeof vers, "Version: %s - %s", atopacctdversion, atopacctddate); return vers; } /* ** signal catcher: ** set flag to be verified in main loop to cleanup and terminate */ void cleanup(int sig) { cleanup_and_go = sig; } atop-2.4.0/atopacctd.h0000664000203100020310000000207013416466037014106 0ustar gerlofgerlof/* ** keys to access the semaphores */ #define PACCTPUBKEY 1071980 // # clients using shadow files #define PACCTPRVKEY (PACCTPUBKEY-1) // # atopacctd daemons busy (max. 1) /* ** name of the PID file */ #define PIDFILE "/var/run/atopacctd.pid" /* ** directory containing the source accounting file and ** the subdirectory (PACCTSHADOWD) containing the shadow file(s) ** this directory can be overruled by a command line parameter (atopacctd) ** or by a keyword in the /etc/atoprc file (atop) */ #define PACCTDIR "/var/run" /* ** accounting file (source file to which kernel writes records) */ #define PACCTORIG "pacct_source" // file name in PACCTDIR #define MAXORIGSZ (1024*1024) // maximum size of source file /* ** file and directory names for shadow files */ #define PACCTSHADOWD "pacct_shadow.d" // directory name in PACCTDIR #define PACCTSHADOWF "%s/%s/%010ld.paf" // file name of shadow file #define PACCTSHADOWC "current" // file containining current // sequence and MAXSHADOWREC #define MAXSHADOWREC 10000 // number of accounting records per shadow file atop-2.4.0/atop.c0000664000203100020310000010163613416466037013112 0ustar gerlofgerlof/* ** 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 the main-function, which verifies the ** calling-parameters and takes care of initialization. ** The engine-function drives the main sample-loop in which after the ** indicated interval-time a snapshot is taken of the system-level and ** process-level counters and the deviations are calculated and ** visualized for the user. ** ========================================================================== ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Date: November 1996 ** Linux-port: June 2000 ** Modified: May 2001 - Ported to kernel 2.4 ** -------------------------------------------------------------------------- ** Copyright (C) 2000-2018 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 ** -------------------------------------------------------------------------- ** ** After initialization, the main-function calls the ENGINE. ** For every cycle (so after another interval) the ENGINE calls various ** functions as shown below: ** ** +---------------------------------------------------------------------+ ** | E N G I N E | ** | | ** | | ** | _____________________await interval-timer_____________________ | ** | | ^ | ** | | ________ ________ ________ ________ | | ** | | ^ | ^ | ^ | ^ | | | ** +---|-----|--------|-----|--------|----|--------|----|--------|----|--+ ** | | | | | | | | | | ** +--V-----|--+ +--V-----|--+ +--V----|--+ +--V----|--+ +--V----|-+ ** | | | | | | | | | | ** | photosyst | | photoproc | | acct | | deviate | | print | ** | | | | |photoproc | | ...syst | | | ** | | | | | | | ...proc | | | ** +-----------+ +-----------+ +----------+ +----------+ +---------+ ** ^ ^ ^ ^ | ** | | | | | ** | | | V V ** ______ _________ __________ ________ _________ ** / \ / \ / \ / \ / \ ** /proc /proc accounting task screen or ** file database file ** \______/ \_________/ \__________/ \________/ \_________/ ** ** - photosyst() ** Takes a snapshot of the counters related to resource-usage on ** system-level (cpu, disk, memory, network). ** This code is UNIX-flavor dependent; in case of Linux the counters ** are retrieved from /proc. ** ** - photoproc() ** Takes a snapshot of the counters related to resource-usage of ** tasks which are currently active. For this purpose the whole ** task-list is read. ** This code is UNIX-flavor dependent; in case of Linux the counters ** are retrieved from /proc. ** ** - acctphotoproc() ** Takes a snapshot of the counters related to resource-usage of ** tasks which have been finished during the last interval. ** For this purpose all new records in the accounting-file are read. ** ** When all counters have been gathered, functions are called to calculate ** the difference between the current counter-values and the counter-values ** of the previous cycle. These functions operate on the system-level ** as well as on the task-level counters. ** These differences are stored in a new structure(-table). ** ** - deviatsyst() ** Calculates the differences between the current system-level ** counters and the corresponding counters of the previous cycle. ** ** - deviattask() ** Calculates the differences between the current task-level ** counters and the corresponding counters of the previous cycle. ** The per-task counters of the previous cycle are stored in the ** task-database; this "database" is implemented as a linked list ** of taskinfo structures in memory (so no disk-accesses needed). ** Within this linked list hash-buckets are maintained for fast searches. ** The entire task-database is handled via a set of well-defined ** functions from which the name starts with "pdb_..." (see the ** source-file procdbase.c). ** The processes which have been finished during the last cycle ** are also treated by deviattask() in order to calculate what their ** resource-usage was before they finished. ** ** All information is ready to be visualized now. ** There is a structure which holds the start-address of the ** visualization-function to be called. Initially this structure contains ** the address of the generic visualization-function ("generic_samp"), but ** these addresses can be modified in the main-function depending on particular ** 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-priviliges 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 ** */ static const char rcsid[] = "$Id: atop.c,v 1.49 2010/10/23 14:01:00 gerlof Exp $"; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "atop.h" #include "acctproc.h" #include "ifprop.h" #include "photoproc.h" #include "photosyst.h" #include "showgeneric.h" #include "parseable.h" #include "gpucom.h" #define allflags "ab:cde:fghijklmnopqrstuvwxyz1ABCDEFGHIJKL:MNOP:QRSTUVWXYZ" #define MAXFL 64 /* maximum number of command-line flags */ /* ** declaration of global variables */ struct utsname utsname; int utsnodenamelen; time_t pretime; /* timing info */ time_t curtime; /* timing info */ unsigned long interval = 10; unsigned long sampcnt; char screen; int linelen = 80; char acctreason; /* accounting not active (return val) */ char rawname[RAWNAMESZ]; char rawreadflag; unsigned int begintime, endtime; char flaglist[MAXFL]; char deviatonly = 1; char usecolors = 1; /* boolean: colors for high occupation */ char threadview = 0; /* boolean: show individual threads */ char calcpss = 0; /* boolean: read/calculate process PSS */ unsigned short hertz; unsigned int pagesize; unsigned int nrgpus; int osrel; int osvers; int ossub; int supportflags; /* supported features */ char **argvp; struct visualize vis = {generic_samp, generic_error, generic_end, generic_usage}; /* ** argument values */ static char awaittrigger; /* boolean: awaiting trigger */ static unsigned int nsamples = 0xffffffff; static char midnightflag; static char rawwriteflag; /* ** interpretation of defaults-file /etc/atoprc and $HOME/.atop */ 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_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_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 *); static struct { char *tag; void (*func)(char *, char *); int sysonly; } manrc[] = { { "flags", do_flags, 0, }, { "interval", do_interval, 0, }, { "linelen", do_linelength, 0, }, { "username", do_username, 0, }, { "procname", do_procname, 0, }, { "maxlinecpu", do_maxcpu, 0, }, { "maxlinegpu", do_maxgpu, 0, }, { "maxlinedisk", do_maxdisk, 0, }, { "maxlinemdd", do_maxmdd, 0, }, { "maxlinelvm", do_maxlvm, 0, }, { "maxlineintf", do_maxintf, 0, }, { "maxlineifb", do_maxifb, 0, }, { "maxlinenfsm", do_maxnfsm, 0, }, { "maxlinecont", do_maxcont, 0, }, { "colorinfo", do_colinfo, 0, }, { "coloralmost", do_colalmost, 0, }, { "colorcritical", do_colcrit, 0, }, { "colorthread", do_colthread, 0, }, { "ownallcpuline", do_ownallcpuline, 0, }, { "ownonecpuline", do_ownindivcpuline, 0, }, { "owncplline", do_owncplline, 0, }, { "ownmemline", do_ownmemline, 0, }, { "ownswpline", do_ownswpline, 0, }, { "ownpagline", do_ownpagline, 0, }, { "owndskline", do_owndskline, 0, }, { "ownnettrline", do_ownnettransportline, 0, }, { "ownnetnetline", do_ownnetnetline, 0, }, { "ownnetifline", do_ownnetinterfaceline, 0, }, { "ownifbline", do_owninfinibandline, 0, }, { "ownprocline", do_ownprocline, 0, }, { "ownsysprcline", do_ownsysprcline, 0, }, { "owndskline", do_owndskline, 0, }, { "cpucritperc", do_cpucritperc, 0, }, { "gpucritperc", do_gpucritperc, 0, }, { "memcritperc", do_memcritperc, 0, }, { "swpcritperc", do_swpcritperc, 0, }, { "dskcritperc", do_dskcritperc, 0, }, { "netcritperc", do_netcritperc, 0, }, { "swoutcritsec", do_swoutcritsec, 0, }, { "almostcrit", do_almostcrit, 0, }, { "atopsarflags", do_atopsarflags, 0, }, { "pacctdir", do_pacctdir, 1, }, }; /* ** internal prototypes */ static void engine(void); int main(int argc, char *argv[]) { register int i; int c; char *p; struct rlimit rlim; /* ** since priviliged actions will be done later on, at this stage ** the root-priviliges are dropped by switching effective user-id ** to real user-id (security reasons) */ if (! droprootprivs() ) { fprintf(stderr, "not possible to drop root privs\n"); exit(42); } /* ** preserve command arguments to allow restart of other version */ argvp = argv; /* ** read defaults-files /etc/atoprc en $HOME/.atoprc (if any) */ readrc("/etc/atoprc", 1); if ( (p = getenv("HOME")) ) { char path[1024]; snprintf(path, sizeof path, "%s/.atoprc", p); readrc(path, 0); } /* ** check if we are supposed to behave as 'atopsar' ** i.e. system statistics only */ if ( (p = strrchr(argv[0], '/'))) p++; else p = argv[0]; if ( memcmp(p, "atopsar", 7) == 0) return atopsar(argc, argv); /* ** interpret command-line arguments & flags */ if (argc > 1) { /* ** gather all flags for visualization-functions ** ** generic flags will be handled here; ** unrecognized flags are passed to the print-routines */ i = 0; while (i < MAXFL-1 && (c=getopt(argc, argv, allflags)) != EOF) { switch (c) { case '?': /* usage wanted ? */ prusage(argv[0]); break; case 'V': /* version wanted ? */ printf("%s\n", getstrvers()); exit(0); case 'w': /* writing of raw data ? */ rawwriteflag++; if (optind >= argc) prusage(argv[0]); strncpy(rawname, argv[optind++], RAWNAMESZ-1); vis.show_samp = rawwrite; break; case 'r': /* reading of raw data ? */ if (optind < argc && *(argv[optind]) != '-') strncpy(rawname, argv[optind++], RAWNAMESZ-1); rawreadflag++; break; case 'S': /* midnight limit ? */ midnightflag++; break; case 'a': /* all processes per sample ? */ deviatonly = 0; break; case 'R': /* all processes per sample ? */ calcpss = 1; break; case 'b': /* begin time ? */ if ( !hhmm2secs(optarg, &begintime) ) prusage(argv[0]); break; case 'e': /* end time ? */ if ( !hhmm2secs(optarg, &endtime) ) prusage(argv[0]); break; case 'P': /* parseable output? */ if ( !parsedef(optarg) ) prusage(argv[0]); vis.show_samp = parseout; break; case 'L': /* line length */ if ( !numeric(optarg) ) prusage(argv[0]); linelen = atoi(optarg); break; default: /* gather other flags */ flaglist[i++] = c; } } /* ** get optional interval-value and optional number of samples */ if (optind < argc && optind < MAXFL) { if (!numeric(argv[optind])) prusage(argv[0]); interval = atoi(argv[optind]); optind++; if (optind < argc) { if (!numeric(argv[optind]) ) prusage(argv[0]); if ( (nsamples = atoi(argv[optind])) < 1) prusage(argv[0]); } } } /* ** determine the name of this node (without domain-name) ** and the kernel-version */ (void) uname(&utsname); if ( (p = strchr(utsname.nodename, '.')) ) *p = '\0'; utsnodenamelen = strlen(utsname.nodename); sscanf(utsname.release, "%d.%d.%d", &osrel, &osvers, &ossub); /* ** determine the clock rate and memory page size for this machine */ hertz = sysconf(_SC_CLK_TCK); pagesize = sysconf(_SC_PAGESIZE); /* ** check if raw data from a file must be viewed */ if (rawreadflag) { rawread(); cleanstop(0); } /* ** determine start-time for gathering current statistics */ curtime = getboot() / hertz; /* ** be sure to be leader of an own process group when ** running as a daemon (or at least: when not interactive); ** needed for systemd */ if (rawwriteflag) (void) setpgid(0, 0); /* ** catch signals for proper close-down */ signal(SIGHUP, cleanstop); signal(SIGTERM, cleanstop); /* ** regain the root-priviliges that we dropped at the beginning ** to do some priviliged work */ regainrootprivs(); /* ** lock ATOP in memory to get reliable samples (also when ** memory is low and swapping is going on); ** ignored if not running under superuser priviliges! */ rlim.rlim_cur = RLIM_INFINITY; rlim.rlim_max = RLIM_INFINITY; if (setrlimit(RLIMIT_MEMLOCK, &rlim) == 0) (void) mlockall(MCL_CURRENT|MCL_FUTURE); /* ** increment CPU scheduling-priority to get reliable samples (also ** during heavy CPU load); ** ignored if not running under superuser priviliges! */ if ( nice(-20) == -1) ; /* ** switch-on the process-accounting mechanism to register the ** (remaining) resource-usage by processes which have finished */ acctreason = acctswon(); /* ** determine properties (like speed) of all interfaces */ initifprop(); /* ** open socket to the IP layer to issue getsockopt() calls later on */ netatop_ipopen(); /* ** since privileged activities are finished now, there is no ** need to keep running under root-priviliges, so switch ** effective user-id to real user-id */ if (! droprootprivs() ) cleanstop(42); /* ** start the engine now ..... */ engine(); cleanstop(0); return 0; /* never reached */ } /* ** The engine() drives the main-loop of the program */ static void engine(void) { struct sigaction sigact; static time_t timelimit; void getusr1(int), getusr2(int); /* ** reserve space for system-level statistics */ static struct sstat *cursstat; /* current */ static struct sstat *presstat; /* previous */ static struct sstat *devsstat; /* deviation */ static struct sstat *hlpsstat; /* ** reserve space for task-level statistics */ static struct tstat *curtpres; /* current present list */ static unsigned long curtlen; /* size of present list */ struct tstat *curpexit; /* exited process list */ static struct devtstat devtstat; /* deviation info */ unsigned long ntaskpres; /* number of tasks present */ unsigned long nprocexit; /* number of exited procs */ unsigned long nprocexitnet; /* number of exited procs */ /* via netatopd daemon */ unsigned long noverflow; int nrgpuproc=0, /* number of GPU processes */ gpupending=0; /* boolean: request sent */ struct gpupidstat *gp = NULL; /* ** initialization: allocate required memory dynamically */ cursstat = calloc(1, sizeof(struct sstat)); presstat = calloc(1, sizeof(struct sstat)); devsstat = calloc(1, sizeof(struct sstat)); ptrverify(cursstat, "Malloc failed for current sysstats\n"); ptrverify(presstat, "Malloc failed for prev sysstats\n"); ptrverify(devsstat, "Malloc failed for deviate sysstats\n"); /* ** install the signal-handler for ALARM, USR1 and USR2 (triggers * for the next sample) */ memset(&sigact, 0, sizeof sigact); sigact.sa_handler = getusr1; sigaction(SIGUSR1, &sigact, (struct sigaction *)0); memset(&sigact, 0, sizeof sigact); sigact.sa_handler = getusr2; sigaction(SIGUSR2, &sigact, (struct sigaction *)0); memset(&sigact, 0, sizeof sigact); sigact.sa_handler = getalarm; sigaction(SIGALRM, &sigact, (struct sigaction *)0); if (interval > 0) alarm(interval); if (midnightflag) { time_t timenow = time(0); struct tm *tp = localtime(&timenow); tp->tm_hour = 23; tp->tm_min = 59; tp->tm_sec = 59; timelimit = mktime(tp); } /* ** open socket to the atopgpud daemon for GPU statistics */ nrgpus = gpud_init(); if (nrgpus) supportflags |= GPUSTAT; /* ** MAIN-LOOP: ** - Wait for the requested number of seconds or for other trigger ** ** - System-level counters ** get current counters ** calculate the differences with the previous sample ** ** - Process-level counters ** get current counters from running & exited processes ** calculate the differences with the previous sample ** ** - Call the print-function to visualize the differences */ for (sampcnt=0; sampcnt < nsamples; sampcnt++) { char lastcmd; /* ** if the limit-flag is specified: ** check if the next sample is expected before midnight; ** if not, stop atop now */ if (midnightflag && (curtime+interval) > timelimit) break; /* ** wait for alarm-signal to arrive (except first sample) ** or wait for SIGUSR1/SIGUSR2 */ if (sampcnt > 0 && awaittrigger) pause(); awaittrigger = 1; /* ** gather time info for this sample */ pretime = curtime; curtime = time(0); /* seconds since 1-1-1970 */ /* ** send request for statistics to atopgpud */ if (nrgpus) gpupending = gpud_statrequest(); /* ** take a snapshot of the current system-level statistics ** and calculate the deviations (i.e. calculate the activity ** during the last sample) */ hlpsstat = cursstat; /* swap current/prev. stats */ cursstat = presstat; presstat = hlpsstat; photosyst(cursstat); /* obtain new counters */ /* ** receive and parse response from atopgpud */ if (nrgpus && gpupending) { nrgpuproc = gpud_statresponse(nrgpus, cursstat->gpu.gpu, &gp); gpupending = 0; // connection lost or timeout on receive? if (nrgpuproc == -1) { int ng; // try to reconnect ng = gpud_init(); if (ng != nrgpus) // no success nrgpus = 0; if (nrgpus) { // request for stats again if (gpud_statrequest()) { // receive stats response nrgpuproc = gpud_statresponse(nrgpus, cursstat->gpu.gpu, &gp); // persistent failure? if (nrgpuproc == -1) nrgpus = 0; } } } cursstat->gpu.nrgpus = nrgpus; } deviatsyst(cursstat, presstat, devsstat, curtime-pretime > 0 ? curtime-pretime : 1); /* ** take a snapshot of the current task-level statistics ** and calculate the deviations (i.e. calculate the activity ** during the last sample) ** ** first register active tasks */ curtpres = NULL; do { curtlen = counttasks(); curtpres = realloc(curtpres, curtlen * sizeof(struct tstat)); ptrverify(curtpres, "Malloc failed for %d tstats\n", curtlen); memset(curtpres, 0, curtlen * sizeof(struct tstat)); } while ( (ntaskpres = photoproc(curtpres, curtlen)) == curtlen); /* ** register processes that exited during last sample; ** first determine how many processes exited ** ** the number of exited processes is limited to avoid ** that atop explodes in memory and introduces OOM killing */ nprocexit = acctprocnt(); /* number of exited processes */ if (nprocexit > MAXACCTPROCS) { noverflow = nprocexit - MAXACCTPROCS; nprocexit = MAXACCTPROCS; } else noverflow = 0; /* ** determine how many processes have been exited ** for the netatop module (only processes that have ** used the network) */ if (nprocexit > 0 && (supportflags & NETATOPD)) nprocexitnet = netatop_exitstore(); else nprocexitnet = 0; /* ** reserve space for the exited processes and read them */ if (nprocexit > 0) { curpexit = malloc(nprocexit * sizeof(struct tstat)); ptrverify(curpexit, "Malloc failed for %lu exited processes\n", nprocexit); memset(curpexit, 0, nprocexit * sizeof(struct tstat)); nprocexit = acctphotoproc(curpexit, nprocexit); /* ** reposition offset in accounting file when not ** all exited processes have been read (i.e. skip ** those processes) */ if (noverflow) acctrepos(noverflow); } else { curpexit = NULL; } /* ** merge GPU per-process stats with other per-process stats */ if (nrgpus && nrgpuproc) gpumergeproc(curtpres, ntaskpres, curpexit, nprocexit, gp, nrgpuproc); /* ** calculate deviations */ deviattask(curtpres, ntaskpres, curpexit, nprocexit, &devtstat, devsstat); /* ** activate the installed print-function to visualize ** the deviations */ lastcmd = (vis.show_samp)( curtime, curtime-pretime > 0 ? curtime-pretime : 1, &devtstat, devsstat, nprocexit, noverflow, sampcnt==0); /* ** release dynamically allocated memory */ if (nprocexit > 0) free(curpexit); free(curtpres); if (nprocexitnet > 0) netatop_exiterase(); if (gp) free(gp); if (lastcmd == 'r') /* reset requested ? */ { sampcnt = -1; curtime = getboot() / hertz; // reset current time /* set current (will be 'previous') counters to 0 */ memset(cursstat, 0, sizeof(struct sstat)); /* remove all tasks in database */ pdb_makeresidue(); pdb_cleanresidue(); } } /* end of main-loop */ } /* ** print usage of this command */ void prusage(char *myname) { printf("Usage: %s [-flags] [interval [samples]]\n", myname); printf("\t\tor\n"); printf("Usage: %s -w file [-S] [-%c] [interval [samples]]\n", myname, MALLPROC); printf(" %s -r [file] [-b hh:mm] [-e hh:mm] [-flags]\n", myname); printf("\n"); printf("\tgeneric flags:\n"); 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 -P generate parseable output for specified label(s)\n"); printf("\t -L alternate line length (default 80) in case of " "non-screen output\n"); (*vis.show_usage)(); printf("\n"); printf("\tspecific flags for raw logfiles:\n"); printf("\t -w write raw data to file (compressed)\n"); printf("\t -r read raw data from file (compressed)\n"); printf("\t special file: y[y...] for yesterday (repeated)\n"); printf("\t -S finish atop automatically before midnight " "(i.s.o. #samples)\n"); printf("\t -b begin showing data from specified time\n"); printf("\t -e finish showing data after specified time\n"); printf("\n"); printf("\tinterval: number of seconds (minimum 0)\n"); printf("\tsamples: number of intervals (minimum 1)\n"); printf("\n"); printf("If the interval-value is zero, a new sample can be\n"); printf("forced manually by sending signal USR1" " (kill -USR1 pid_atop)\n"); printf("or with the keystroke '%c' in interactive mode.\n", MSAMPNEXT); printf("\n"); printf("Please refer to the man-page of 'atop' for more details.\n"); cleanstop(1); } /* ** handler for ALRM-signal */ void getalarm(int sig) { awaittrigger=0; if (interval > 0) alarm(interval); /* restart the timer */ } /* ** handler for USR1-signal */ void getusr1(int sig) { awaittrigger=0; } /* ** handler for USR2-signal */ void getusr2(int sig) { awaittrigger=0; nsamples = sampcnt; // force stop after next sample } /* ** functions to handle a particular tag in the .atoprc file */ extern int get_posval(char *name, char *val); void do_interval(char *name, char *val) { interval = get_posval(name, val); } void do_linelength(char *name, char *val) { linelen = get_posval(name, val); } /* ** read RC-file and modify defaults accordingly */ static void readrc(char *path, int syslevel) { int i, nr, line=0, errorcnt = 0; /* ** check if this file is readable with the user's ** *real uid/gid* with syscall access() */ if ( access(path, R_OK) == 0) { FILE *fp; char linebuf[256], tagname[20], tagvalue[256]; fp = fopen(path, "r"); while ( fgets(linebuf, sizeof linebuf, fp) ) { line++; i = strlen(linebuf); if (i > 0 && linebuf[i-1] == '\n') linebuf[i-1] = 0; nr = sscanf(linebuf, "%19s %255[^#]", tagname, tagvalue); switch (nr) { case 0: continue; case 1: if (tagname[0] == '#') continue; fprintf(stderr, "%s: syntax error line " "%d (no value specified)\n", path, line); cleanstop(1); break; /* not reached */ default: if (tagname[0] == '#') continue; if (tagvalue[0] != '#') break; fprintf(stderr, "%s: syntax error line " "%d (no value specified)\n", path, line); cleanstop(1); } /* ** tag name and tag value found ** try to recognize tag name */ for (i=0; i < sizeof manrc/sizeof manrc[0]; i++) { if ( strcmp(tagname, manrc[i].tag) == 0) { if (manrc[i].sysonly && !syslevel) { fprintf(stderr, "%s: warning at line %2d " "- tag name %s not allowed " "in private atoprc\n", path, line, tagname); errorcnt++; break; } manrc[i].func(tagname, tagvalue); break; } } /* ** tag name not recognized */ if (i == sizeof manrc/sizeof manrc[0]) { fprintf(stderr, "%s: warning at line %2d " "- tag name %s not valid\n", path, line, tagname); errorcnt++; } } if (errorcnt) sleep(2); fclose(fp); } } atop-2.4.0/atopconvert.c0000664000203100020310000007047713416466037014523 0ustar gerlofgerlof/* ** 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 program converts a raw logfile created by a particular version ** of atop to (by default) the current version of atop. ** ========================================================================== ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Initial: July/August 2018 ** -------------------------------------------------------------------------- ** Copyright (C) 2018-2019 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 ** -------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "atop.h" #include "photosyst.h" #include "photoproc.h" #include "prev/photosyst_20.h" #include "prev/photoproc_20.h" #include "prev/photosyst_21.h" #include "prev/photoproc_21.h" #include "prev/photosyst_22.h" #include "prev/photoproc_22.h" #include "prev/photosyst_23.h" #include "prev/photoproc_23.h" #include "prev/photosyst_24.h" #include "prev/photoproc_24.h" /////////////////////////////////////////////////////////////// // Conversion functions // -------------------- // The structures with system level and process level info // consists of sub-structures, generally for cpu, memory, // disk and network values. These sub-structures might have // changed from a specific version of atop to the next version. // For modified sub-structures, conversion functions have to be // written. These conversion functions will be called in a chained // way for one version increment at the time. Suppose that a // raw log is offered that has been created by atop 2.0 to be // converted to atop 2.3, every sub-structure will be converted // from 2.0 to 2.1, from 2.1 to 2.2 and finally from 2.2 to 2.3. // When a sub-structure has NOT been changed from one version to // another, it will just be copied by the generic conversion // function 'justcopy' to the proper location in the structure // of the next version. // All conversion steps are controlled by the convs[] table. /////////////////////////////////////////////////////////////// // Generic function that just copies an old structure byte-wise to // a new structure (new structure implicitly padded with binary zeroes) // void justcopy(void *old, void *new, count_t oldsize, count_t newsize) { if (oldsize) memcpy(new, old, newsize > oldsize ? oldsize : newsize); } // Specific functions that convert an old sstat sub-structure to // a new sub-structure (system level) // void scpu_to_21(void *old, void *new, count_t oldsize, count_t newsize) { // cfuture[1] --> cfuture[4] in struct percpu // struct cpustat_20 *c20 = old; struct cpustat_21 *c21 = new; int i; memcpy(c21, c20, (char *)&c20->all - (char *)c20); // base values memcpy(&c21->all, &c20->all, sizeof(struct percpu_20)); for (i=0; i < MAXCPU_20; i++) memcpy( &(c21->cpu[i]), &(c20->cpu[i]), sizeof(struct percpu_20)); } void sdsk_to_21(void *old, void *new, count_t oldsize, count_t newsize) { // MAXDSK and MAXLVM have been enlarged // struct dskstat_20 *d20 = old; struct dskstat_21 *d21 = new; d21->ndsk = d20->ndsk; d21->nmdd = d20->nmdd; d21->nlvm = d20->nlvm; memcpy(d21->dsk, d20->dsk, sizeof d20->dsk); memcpy(d21->mdd, d20->mdd, sizeof d20->mdd); memcpy(d21->lvm, d20->lvm, sizeof d20->lvm); } void sint_to_22(void *old, void *new, count_t oldsize, count_t newsize) { // members 'type' and 'speedp' added to struct perintf // struct intfstat_21 *i21 = old; struct intfstat_22 *i22 = new; int i; i22->nrintf = i21->nrintf; for (i=0; i < MAXINTF_21; i++) { memcpy(&(i22->intf[i]), &(i21->intf[i]), sizeof(struct perintf_21)); // correct last members by refilling // i22->intf[i].type = '?'; i22->intf[i].speed = i21->intf[i].speed; i22->intf[i].speedp = i21->intf[i].speed; i22->intf[i].duplex = i21->intf[i].duplex; memset(i22->intf[i].cfuture, 0, sizeof i22->intf[i].cfuture); } } // Specific functions that convert an old tstat sub-structure to // a new sub-structure (process level) // void tgen_to_21(void *old, void *new, count_t oldsize, count_t newsize) { // member 'envid' inserted in struct gen // struct gen_20 *g20 = old; struct gen_21 *g21 = new; memcpy(g21, g20, (char *)g20->ifuture - (char *)g20); // base values g21->envid = 0; } void tmem_to_21(void *old, void *new, count_t oldsize, count_t newsize) { // members 'pmem' and 'cfuture[4]' inserted in struct mem // struct mem_20 *m20 = old; struct mem_21 *m21 = new; m21->minflt = m20->minflt; m21->majflt = m20->majflt; m21->vexec = m20->vexec; m21->vmem = m20->vmem; m21->rmem = m20->rmem; m21->pmem = 0; m21->vgrow = m20->vgrow; m21->rgrow = m20->rgrow; m21->vdata = m20->vdata; m21->vstack = m20->vstack; m21->vlibs = m20->vlibs; m21->vswap = m20->vswap; } void tgen_to_22(void *old, void *new, count_t oldsize, count_t newsize) { // member 'envid' removed, members 'ctid' and 'vpid' inserted in struct gen // struct gen_21 *g21 = old; struct gen_22 *g22 = new; memcpy(g22, g21, (char *)&g21->envid - (char *)g21); // copy base values g22->ctid = g21->envid; g22->vpid = 0; } /////////////////////////////////////////////////////////////// // conversion definition for various structs in sstat and tstat // #define SETVERSION(major, minor) ((major << 8) | minor) #define STROFFSET(str, begin) ((long)((char *)str - (char *)begin)) struct sconvstruct { count_t structsize; void *structptr; void (*structconv)(void *, void *, count_t, count_t); }; struct tconvstruct { count_t structsize; long structoffset; void (*structconv)(void *, void *, count_t, count_t); }; struct sstat_20 sstat_20; struct sstat_21 sstat_21; struct sstat_22 sstat_22; struct sstat_23 sstat_23; struct sstat_24 sstat_24; struct sstat sstat; struct tstat_20 tstat_20; struct tstat_21 tstat_21; struct tstat_22 tstat_22; struct tstat_23 tstat_23; struct tstat_24 tstat_24; struct tstat tstat; struct convertall { int version; // version of raw log unsigned int sstatlen; // length of struct sstat void *sstat; // pointer to sstat struct unsigned int tstatlen; // length of struct tstat void *tstat; // pointer to tstat structs // conversion definition for subparts within sstat struct sconvstruct scpu; struct sconvstruct smem; struct sconvstruct snet; struct sconvstruct sintf; struct sconvstruct sdsk; struct sconvstruct snfs; struct sconvstruct scfs; struct sconvstruct swww; struct sconvstruct spsi; struct sconvstruct sgpu; struct sconvstruct sifb; // conversion definition for subparts within tstat struct tconvstruct tgen; struct tconvstruct tcpu; struct tconvstruct tdsk; struct tconvstruct tmem; struct tconvstruct tnet; struct tconvstruct tgpu; } convs[] = { {SETVERSION(2,0), sizeof(struct sstat_20), &sstat_20, sizeof(struct tstat_20), NULL, {sizeof(struct cpustat_20), &sstat_20.cpu, NULL}, {sizeof(struct memstat_20), &sstat_20.mem, NULL}, {sizeof(struct netstat_20), &sstat_20.net, NULL}, {sizeof(struct intfstat_20), &sstat_20.intf, NULL}, {sizeof(struct dskstat_20), &sstat_20.dsk, NULL}, {0, NULL, NULL}, {0, NULL, NULL}, {sizeof(struct wwwstat_20), &sstat_20.www, NULL}, {0, NULL, NULL}, {0, NULL, NULL}, {0, NULL, NULL}, {sizeof(struct gen_20), STROFFSET(&tstat_20.gen, &tstat_20), NULL}, {sizeof(struct cpu_20), STROFFSET(&tstat_20.cpu, &tstat_20), NULL}, {sizeof(struct dsk_20), STROFFSET(&tstat_20.dsk, &tstat_20), NULL}, {sizeof(struct mem_20), STROFFSET(&tstat_20.mem, &tstat_20), NULL}, {sizeof(struct net_20), STROFFSET(&tstat_20.net, &tstat_20), NULL}, {0, 0, NULL}, }, {SETVERSION(2,1), // 2.0 --> 2.1 sizeof(struct sstat_21), &sstat_21, sizeof(struct tstat_21), NULL, {sizeof(struct cpustat_21), &sstat_21.cpu, scpu_to_21}, {sizeof(struct memstat_21), &sstat_21.mem, justcopy}, {sizeof(struct netstat_21), &sstat_21.net, justcopy}, {sizeof(struct intfstat_21), &sstat_21.intf, justcopy}, {sizeof(struct dskstat_21), &sstat_21.dsk, sdsk_to_21}, {0, NULL, NULL}, {0, NULL, NULL}, {sizeof(struct wwwstat_21), &sstat_21.www, justcopy}, {0, NULL, NULL}, {0, NULL, NULL}, {0, NULL, NULL}, {sizeof(struct gen_21), STROFFSET(&tstat_21.gen, &tstat_21), tgen_to_21}, {sizeof(struct cpu_21), STROFFSET(&tstat_21.cpu, &tstat_21), justcopy}, {sizeof(struct dsk_21), STROFFSET(&tstat_21.dsk, &tstat_21), justcopy}, {sizeof(struct mem_21), STROFFSET(&tstat_21.mem, &tstat_21), tmem_to_21}, {sizeof(struct net_21), STROFFSET(&tstat_21.net, &tstat_21), justcopy}, {0, 0, NULL}, }, {SETVERSION(2,2), // 2.1 --> 2.2 sizeof(struct sstat_22), &sstat_22, sizeof(struct tstat_22), NULL, {sizeof(struct cpustat_22), &sstat_22.cpu, justcopy}, {sizeof(struct memstat_22), &sstat_22.mem, justcopy}, {sizeof(struct netstat_22), &sstat_22.net, justcopy}, {sizeof(struct intfstat_22), &sstat_22.intf, sint_to_22}, {sizeof(struct dskstat_22), &sstat_22.dsk, justcopy}, {sizeof(struct nfsstat_22), &sstat_22.nfs, NULL}, {sizeof(struct contstat_22), &sstat_22.cfs, NULL}, {sizeof(struct wwwstat_22), &sstat_22.www, justcopy}, {0, NULL, NULL}, {0, NULL, NULL}, {0, NULL, NULL}, {sizeof(struct gen_22), STROFFSET(&tstat_22.gen, &tstat_22), tgen_to_22}, {sizeof(struct cpu_22), STROFFSET(&tstat_22.cpu, &tstat_22), justcopy}, {sizeof(struct dsk_22), STROFFSET(&tstat_22.dsk, &tstat_22), justcopy}, {sizeof(struct mem_22), STROFFSET(&tstat_22.mem, &tstat_22), justcopy}, {sizeof(struct net_22), STROFFSET(&tstat_22.net, &tstat_22), justcopy}, {0, 0, NULL}, }, {SETVERSION(2,3), // 2.2 --> 2.3 sizeof(struct sstat_23), &sstat_23, sizeof(struct tstat_23), NULL, {sizeof(struct cpustat_23), &sstat_23.cpu, justcopy}, {sizeof(struct memstat_23), &sstat_23.mem, justcopy}, {sizeof(struct netstat_23), &sstat_23.net, justcopy}, {sizeof(struct intfstat_23), &sstat_23.intf, justcopy}, {sizeof(struct dskstat_23), &sstat_23.dsk, justcopy}, {sizeof(struct nfsstat_23), &sstat_23.nfs, justcopy}, {sizeof(struct contstat_23), &sstat_23.cfs, justcopy}, {sizeof(struct wwwstat_23), &sstat_23.www, justcopy}, {0, NULL, NULL}, {0, NULL, NULL}, {0, NULL, NULL}, {sizeof(struct gen_23), STROFFSET(&tstat_23.gen, &tstat_23), justcopy}, {sizeof(struct cpu_23), STROFFSET(&tstat_23.cpu, &tstat_23), justcopy}, {sizeof(struct dsk_23), STROFFSET(&tstat_23.dsk, &tstat_23), justcopy}, {sizeof(struct mem_23), STROFFSET(&tstat_23.mem, &tstat_23), justcopy}, {sizeof(struct net_23), STROFFSET(&tstat_23.net, &tstat_23), justcopy}, {0, 0, NULL}, }, {SETVERSION(2,4), // 2.3 --> 2.4 sizeof(struct sstat_24), &sstat_24, sizeof(struct tstat_24), NULL, {sizeof(struct cpustat_24), &sstat_24.cpu, justcopy}, {sizeof(struct memstat_24), &sstat_24.mem, justcopy}, {sizeof(struct netstat_24), &sstat_24.net, justcopy}, {sizeof(struct intfstat_24), &sstat_24.intf, justcopy}, {sizeof(struct dskstat_24), &sstat_24.dsk, justcopy}, {sizeof(struct nfsstat_24), &sstat_24.nfs, justcopy}, {sizeof(struct contstat_24), &sstat_24.cfs, justcopy}, {sizeof(struct wwwstat_24), &sstat_24.www, justcopy}, {0, &sstat_24.psi, NULL}, {0, &sstat_24.gpu, NULL}, {0, &sstat_24.ifb, NULL}, {sizeof(struct gen_24), STROFFSET(&tstat_24.gen, &tstat_24), justcopy}, {sizeof(struct cpu_24), STROFFSET(&tstat_24.cpu, &tstat_24), justcopy}, {sizeof(struct dsk_24), STROFFSET(&tstat_24.dsk, &tstat_24), justcopy}, {sizeof(struct mem_24), STROFFSET(&tstat_24.mem, &tstat_24), justcopy}, {sizeof(struct net_24), STROFFSET(&tstat_24.net, &tstat_24), justcopy}, {sizeof(struct gpu_24), STROFFSET(&tstat_24.gpu, &tstat_24), justcopy}, }, }; int numconvs = sizeof convs / sizeof(struct convertall); /////////////////////////////////////////////////////////////// // End of conversion functions /////////////////////////////////////////////////////////////// /* ** structure which describes the raw file contents ** ** layout raw file: rawheader ** ** rawrecord \ ** compressed system-level statistics | sample 1 ** compressed process-level statistics / ** ** rawrecord \ ** compressed system-level statistics | sample 2 ** compressed process-level statistics / ** ** etcetera ..... */ #define MYMAGIC (unsigned int) 0xfeedbeef struct rawheader { unsigned int magic; unsigned short aversion; /* creator atop version with MSB */ unsigned short future1; /* can be reused */ unsigned short future2; /* can be reused */ unsigned short rawheadlen; /* length of struct rawheader */ unsigned short rawreclen; /* length of struct rawrecord */ unsigned short hertz; /* clock interrupts per second */ unsigned short sfuture[6]; /* future use */ unsigned int sstatlen; /* length of struct sstat */ unsigned int tstatlen; /* length of struct tstat */ struct utsname utsname; /* info about this system */ char cfuture[8]; /* future use */ unsigned int pagesize; /* size of memory page (bytes) */ int supportflags; /* used features */ int osrel; /* OS release number */ int osvers; /* OS version number */ int ossub; /* OS version subnumber */ int ifuture[6]; /* future use */ }; struct rawrecord { time_t curtime; /* current time (epoch) */ unsigned short flags; /* various flags */ unsigned short sfuture[3]; /* future use */ unsigned int scomplen; /* length of compressed sstat */ unsigned int pcomplen; /* length of compressed tstat's */ unsigned int interval; /* interval (number of seconds) */ unsigned int ndeviat; /* number of tasks in list */ unsigned int nactproc; /* number of processes in list */ unsigned int ntask; /* total number of tasks */ unsigned int totproc; /* total number of processes */ unsigned int totrun; /* number of running threads */ unsigned int totslpi; /* number of sleeping threads(S)*/ unsigned int totslpu; /* number of sleeping threads(D)*/ unsigned int totzomb; /* number of zombie processes */ unsigned int nexit; /* number of exited processes */ unsigned int noverflow; /* number of overflow processes */ unsigned int ifuture[6]; /* future use */ }; // function prototypes // static int openin(char *); static void readin(int, void *, int); static int openout(char *); static void writeout(int, void *, int); static void writesamp(int, struct rawrecord *, void *, int, void *, int, int); static void convert_samples(int, int, struct rawheader *, int, int); static void do_sconvert(struct sconvstruct *, struct sconvstruct *); static void do_tconvert(void *, void *, struct tconvstruct *, struct tconvstruct *); static int getrawsstat(int, struct sstat *, int); static int getrawtstat(int, struct tstat *, int, int); static void testcompval(int, char *); int main(int argc, char *argv[]) { int ifd, ofd; struct rawheader irh, orh; int i, versionix, targetix = -1; int c, major, minor, targetvers; char *infile, *outfile; // verify the command line arguments: // optional flags and mandatory input and output filename // if (argc < 3) prusage(argv[0]); while ((c = getopt(argc, argv, "?t:")) != EOF) { switch (c) { case '?': // usage wanted ? prusage(argv[0]); break; case 't': // target version if ( sscanf(optarg, "%d.%d", &major, &minor) != 2) { fprintf(stderr, "target version format: major.minor\n"); prusage(argv[0]); } targetvers = SETVERSION(major, minor); // search for target version in conversion table // for (i=0, targetix=-1; i < numconvs; i++) { if (targetvers == convs[i].version) { targetix = i; break; } } if (targetix == -1) // incorrect target version? { fprintf(stderr, "target version incorrect!"); prusage(argv[0]); } break; default: prusage(argv[0]); break; } } if (optind < argc-2) prusage(argv[0]); infile = argv[optind++]; outfile = argv[optind++]; if (strcmp(infile, outfile) == 0) { fprintf(stderr, "input file and output file should not be identical!\n"); exit(12); } // determine target version (default: latest version) // if (targetix == -1) // no specific target version requested? targetix = numconvs - 1; // open the input file and verify magic number // if ( (ifd = openin(infile)) == -1) { prusage(argv[0]); exit(2); } readin(ifd, &irh, sizeof irh); if (irh.magic != MYMAGIC) { fprintf(stderr, "File %s does not contain atop/atopsar data " "(wrong magic number)\n", infile); exit(3); } printf("Version of %s: %d.%d\n", infile, (irh.aversion >> 8) & 0x7f, irh.aversion & 0xff); if (irh.rawheadlen != sizeof(struct rawheader) || irh.rawreclen != sizeof(struct rawrecord) ) { fprintf(stderr, "File %s created with atop compiled " "for other CPU architecture\n", infile); exit(3); } // search for version of input file in conversion table // for (i=0, versionix=-1; i < numconvs; i++) { if (convs[i].version == (irh.aversion & 0x7fff)) { versionix = i; break; } } if (versionix == -1) { fprintf(stderr, "This version is not supported for conversion!\n"); exit(11); } if (versionix >= targetix) { fprintf(stderr, "This version is already up-to-date!\n"); exit(0); } if (irh.sstatlen != convs[versionix].sstatlen || irh.tstatlen != convs[versionix].tstatlen ) { fprintf(stderr, "File %s contains unexpected internal structures\n", infile); fprintf(stderr, "sstat: %d/%d, tstat: %d/%d\n", irh.sstatlen, convs[versionix].sstatlen, irh.tstatlen, convs[versionix].tstatlen); exit(11); } // open the output file // if ( (ofd = openout(outfile)) == -1) { prusage(argv[0]); exit(4); } // write raw header to output file // orh = irh; orh.aversion = convs[targetix].version | 0x8000; orh.sstatlen = convs[targetix].sstatlen; orh.tstatlen = convs[targetix].tstatlen; writeout(ofd, &orh, sizeof orh); printf("Version of %s: %d.%d\n", outfile, (orh.aversion >> 8) & 0x7f, orh.aversion & 0xff); // copy and convert every sample // convert_samples(ifd, ofd, &irh, versionix, targetix); return 0; } // // Function that reads the input file sample-by-sample, // converts it to an output sample and writes that to the output file // static void convert_samples(int ifd, int ofd, struct rawheader *irh, int ivix, int ovix) { struct rawrecord irr, orr; int i, t; count_t count = 0; while ( read(ifd, &irr, irh->rawreclen) == irh->rawreclen) { count++; // read compressed system-level statistics and decompress // if ( !getrawsstat(ifd, convs[ivix].sstat, irr.scomplen) ) exit(7); // read compressed process-level statistics and decompress // convs[ivix].tstat = malloc(convs[ivix].tstatlen * irr.ndeviat); ptrverify(convs[ivix].tstat, "Malloc failed for %d stored tasks\n", irr.ndeviat); if ( !getrawtstat(ifd, convs[ivix].tstat, irr.pcomplen, irr.ndeviat) ) exit(7); // STEP-BY-STEP CONVERSION FROM OLD VERSION TO NEW VERSION // for (i=ivix; i < ovix; i++) { // convert system-level statistics to newer version // memset(convs[i+1].sstat, 0, convs[i+1].sstatlen); do_sconvert(&(convs[i].scpu), &(convs[i+1].scpu)); do_sconvert(&(convs[i].smem), &(convs[i+1].smem)); do_sconvert(&(convs[i].snet), &(convs[i+1].snet)); do_sconvert(&(convs[i].sintf), &(convs[i+1].sintf)); do_sconvert(&(convs[i].sdsk), &(convs[i+1].sdsk)); do_sconvert(&(convs[i].snfs), &(convs[i+1].snfs)); do_sconvert(&(convs[i].scfs), &(convs[i+1].scfs)); do_sconvert(&(convs[i].spsi), &(convs[i+1].spsi)); do_sconvert(&(convs[i].sgpu), &(convs[i+1].sgpu)); do_sconvert(&(convs[i].sifb), &(convs[i+1].sifb)); do_sconvert(&(convs[i].swww), &(convs[i+1].swww)); // convert process-level statistics to newer version // convs[i+1].tstat = malloc(convs[i+1].tstatlen * irr.ndeviat); ptrverify(convs[ivix].tstat, "Malloc failed for %d stored tasks\n", irr.ndeviat); memset(convs[i+1].tstat, 0, convs[i+1].tstatlen * irr.ndeviat); for (t=0; t < irr.ndeviat; t++) // for every task { do_tconvert( convs[i].tstat +(t*convs[i].tstatlen), convs[i+1].tstat+(t*convs[i+1].tstatlen), &(convs[i].tgen), &(convs[i+1].tgen)); do_tconvert( convs[i].tstat +(t*convs[i].tstatlen), convs[i+1].tstat+(t*convs[i+1].tstatlen), &(convs[i].tcpu), &(convs[i+1].tcpu)); do_tconvert( convs[i].tstat +(t*convs[i].tstatlen), convs[i+1].tstat+(t*convs[i+1].tstatlen), &(convs[i].tdsk), &(convs[i+1].tdsk)); do_tconvert( convs[i].tstat +(t*convs[i].tstatlen), convs[i+1].tstat+(t*convs[i+1].tstatlen), &(convs[i].tmem), &(convs[i+1].tmem)); do_tconvert( convs[i].tstat +(t*convs[i].tstatlen), convs[i+1].tstat+(t*convs[i+1].tstatlen), &(convs[i].tnet), &(convs[i+1].tnet)); do_tconvert( convs[i].tstat +(t*convs[i].tstatlen), convs[i+1].tstat+(t*convs[i+1].tstatlen), &(convs[i].tgpu), &(convs[i+1].tgpu)); } free(convs[i].tstat); } // write new sample to output file // orr = irr; writesamp(ofd, &orr, convs[ovix].sstat, convs[ovix].sstatlen, convs[ovix].tstat, convs[ovix].tstatlen, irr.ndeviat); // cleanup // free(convs[ovix].tstat); } printf("Samples converted: %llu\n", count); } // // Function that calls the appropriate function to convert a struct // from the sstat structure // static void do_sconvert(struct sconvstruct *cur, struct sconvstruct *next) { if (next->structconv) { (*(next->structconv))(cur->structptr, next->structptr, cur->structsize, next->structsize); } } // // Function that calls the appropriate function to convert a struct // from one of the tstat structures // static void do_tconvert(void *curtstat, void *nexttstat, struct tconvstruct *cur, struct tconvstruct *next) { if (next->structconv) { (*(next->structconv))(curtstat + cur->structoffset, nexttstat + next->structoffset, cur->structsize, next->structsize); } } // // Function that opens an existing raw file and // verifies the magic number // static int openin(char *infile) { int rawfd; /* ** open raw file for reading */ if ( (rawfd = open(infile, O_RDONLY)) == -1) { fprintf(stderr, "%s - ", infile); perror("open for reading"); return -1; } return rawfd; } // // Function that reads a chunk of bytes from // the input raw file // static void readin(int rawfd, void *buf, int size) { /* ** read the requested chunk and verify */ if ( read(rawfd, buf, size) < size) { fprintf(stderr, "can not read raw file\n"); close(rawfd); exit(9); } } // // Function that creates a raw log for output // static int openout(char *outfile) { int rawfd; /* ** create new output file */ if ( (rawfd = creat(outfile, 0666)) == -1) { fprintf(stderr, "%s - ", outfile); perror("create raw output file"); return -1; } return rawfd; } // // Function that reads a chunk of bytes from // the input raw file // static void writeout(int rawfd, void *buf, int size) { /* ** write the provided chunk and verify */ if ( write(rawfd, buf, size) < size) { fprintf(stderr, "can not write raw file\n"); close(rawfd); exit(10); } } // // Function that shows the usage message // void prusage(char *name) { fprintf(stderr, "Usage: %s [-t version] rawinput rawoutput\n", name); fprintf(stderr, "\t\t-t version target version (default: %d.%d) for output\n", (convs[numconvs-1].version >> 8) & 0x7f, convs[numconvs-1].version & 0x7f); exit(1); } // // Function to read the system-level statistics from the current offset // static int getrawsstat(int rawfd, struct sstat *sp, int complen) { Byte *compbuf; unsigned long uncomplen = sizeof(struct sstat); int rv; compbuf = malloc(complen); ptrverify(compbuf, "Malloc failed for reading compressed sysstats\n"); if ( read(rawfd, compbuf, complen) < complen) { free(compbuf); fprintf(stderr, "Failed to read %d bytes for system\n", complen); return 0; } rv = uncompress((Byte *)sp, &uncomplen, compbuf, complen); testcompval(rv, "uncompress"); free(compbuf); return 1; } // // Function to read the process-level statistics from the current offset // static int getrawtstat(int rawfd, struct tstat *pp, int complen, int ndeviat) { Byte *compbuf; unsigned long uncomplen = sizeof(struct tstat) * ndeviat; int rv; compbuf = malloc(complen); ptrverify(compbuf, "Malloc failed for reading compressed procstats\n"); if ( read(rawfd, compbuf, complen) < complen) { free(compbuf); fprintf(stderr, "Failed to read %d bytes for tasks\n", complen); return 0; } rv = uncompress((Byte *)pp, &uncomplen, compbuf, complen); testcompval(rv, "uncompress"); free(compbuf); return 1; } // // Function that writes a new sample to the output file // static void writesamp(int ofd, struct rawrecord *rr, void *sstat, int sstatlen, void *tstat, int tstatlen, int ntask) { int rv; Byte scompbuf[sstatlen], *pcompbuf; unsigned long scomplen = sizeof scompbuf; unsigned long pcomplen = tstatlen * ntask; /* ** compress system- and process-level statistics */ rv = compress(scompbuf, &scomplen, (Byte *)sstat, (unsigned long)sstatlen); testcompval(rv, "compress"); pcompbuf = malloc(pcomplen); ptrverify(pcompbuf, "Malloc failed for compression buffer\n"); rv = compress(pcompbuf, &pcomplen, (Byte *)tstat, (unsigned long)pcomplen); testcompval(rv, "compress"); rr->scomplen = scomplen; rr->pcomplen = pcomplen; if ( write(ofd, rr, sizeof *rr) == -1) { perror("write raw record"); exit(7); } /* ** write compressed system status structure to file */ if ( write(ofd, scompbuf, scomplen) == -1) { perror("write raw status record"); exit(7); } /* ** write compressed list of process status structures to file */ if ( write(ofd, pcompbuf, pcomplen) == -1) { perror("write raw process record"); exit(7); } free(pcompbuf); } // // check success of (de)compression // static void testcompval(int rv, char *func) { switch (rv) { case Z_OK: case Z_STREAM_END: case Z_NEED_DICT: break; case Z_MEM_ERROR: fprintf(stderr, "%s: failed due to lack of memory\n", func); exit(7); case Z_BUF_ERROR: fprintf(stderr, "%s: failed due to lack of room in buffer\n", func); exit(7); case Z_DATA_ERROR: fprintf(stderr, "%s: failed due to corrupted/incomplete data\n", func); exit(7); default: fprintf(stderr, "%s: unexpected error %d\n", func, rv); exit(7); } } // // generic pointer verification after malloc // void ptrverify(const void *ptr, const char *errormsg, ...) { if (!ptr) { va_list args; va_start(args, errormsg); vfprintf(stderr, errormsg, args); va_end (args); exit(13); } } atop-2.4.0/atop.h0000664000203100020310000001221413416466037013110 0ustar gerlofgerlof/* ** 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. ** ** Include-file describing miscellaneous constants and function-prototypes. ** ================================================================ ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Date: November 1996 ** LINUX-port: June 2000 ** ** 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. */ #define EQ 0 #define SECSDAY 86400 #define RAWNAMESZ 256 /* ** memory-size formatting possibilities */ #define ANYFORMAT 0 #define KBFORMAT 1 #define MBFORMAT 2 #define GBFORMAT 3 #define TBFORMAT 4 #define PBFORMAT 5 #define OVFORMAT 9 typedef long long count_t; struct tstat; struct devtstat; struct sstat; struct netpertask; /* ** miscellaneous flags */ #define RRBOOT 0x0001 #define RRLAST 0x0002 #define RRNETATOP 0x0004 #define RRNETATOPD 0x0008 #define RRACCTACTIVE 0x0010 #define RRIOSTAT 0x0020 #define RRDOCKSTAT 0x0040 #define RRGPUSTAT 0x0080 struct visualize { char (*show_samp) (time_t, int, struct devtstat *, struct sstat *, int, unsigned int, char); void (*show_error) (const char *, ...); void (*show_end) (void); void (*show_usage) (void); }; /* ** external values */ extern struct utsname utsname; extern int utsnodenamelen; extern time_t pretime; extern time_t curtime; extern unsigned long interval; extern unsigned long sampcnt; extern char screen; extern int linelen; extern char acctreason; extern char deviatonly; extern char usecolors; extern char threadview; extern char calcpss; extern char rawname[]; extern char rawreadflag; extern unsigned int begintime, endtime; extern char flaglist[]; extern struct visualize vis; extern int osrel; extern int osvers; extern int ossub; extern unsigned short hertz; extern unsigned int pagesize; extern unsigned int nrgpus; extern int supportflags; extern int cpubadness; extern int membadness; extern int swpbadness; extern int dskbadness; extern int netbadness; extern int pagbadness; extern int almostcrit; /* ** bit-values for supportflags */ #define ACCTACTIVE 0x00000001 #define IOSTAT 0x00000004 #define NETATOP 0x00000010 #define NETATOPD 0x00000020 #define DOCKSTAT 0x00000040 #define GPUSTAT 0x00000080 /* ** in rawlog file, the four least significant bits ** are moved to the per-sample flags and therefor dummy ** in the support flags of the general header */ #define RAWLOGNG (ACCTACTIVE|IOSTAT|NETATOP|NETATOPD) /* ** structure containing the start-addresses of functions for visualization */ char generic_samp (time_t, int, struct devtstat *, struct sstat *, int, unsigned int, char); void generic_error(const char *, ...); void generic_end (void); void generic_usage(void); /* ** miscellaneous prototypes */ int atopsar(int, char *[]); char *convtime(time_t, char *); char *convdate(time_t, char *); int hhmm2secs(char *, unsigned int *); int daysecs(time_t); char *val2valstr(count_t, char *, int, int, int); char *val2memstr(count_t, char *, int, int, int); char *val2cpustr(count_t, char *); char *val2Hzstr(count_t, char *); int val2elapstr(int, char *); int compcpu(const void *, const void *); int compdsk(const void *, const void *); int compmem(const void *, const void *); int compnet(const void *, const void *); int compgpu(const void *, const void *); int compusr(const void *, const void *); int compnam(const void *, const void *); int compcon(const void *, const void *); int cpucompar (const void *, const void *); int gpucompar (const void *, const void *); int diskcompar(const void *, const void *); int intfcompar(const void *, const void *); int ifbcompar(const void *, const void *); int nfsmcompar(const void *, const void *); int contcompar(const void *, const void *); count_t subcount(count_t, count_t); void rawread(void); char rawwrite (time_t, int, struct devtstat *, struct sstat *, int, unsigned int, char); int numeric(char *); void getalarm(int); unsigned long long getboot(void); char *getstrvers(void); unsigned short getnumvers(void); void ptrverify(const void *, const char *, ...); void cleanstop(int); void prusage(char *); int droprootprivs(void); void regainrootprivs(void); FILE *fopen_tryroot(const char *, const char *); void netatop_ipopen(void); void netatop_probe(void); void netatop_signoff(void); void netatop_gettask(pid_t, char, struct tstat *); unsigned int netatop_exitstore(void); void netatop_exiterase(void); void netatop_exithash(char); void netatop_exitfind(unsigned long, struct tstat *, struct tstat *); atop-2.4.0/atopsar.c0000664000203100020310000021720113416466037013614 0ustar gerlofgerlof/* ** ATOP - System & Process Monitor ** ** The program 'atop'/'atopsar' offers the possibility to view the activity of ** the system on system-level as well as process-level. ** ** This source-file contains the 'atopsar'-functionality, that makes use ** of the 'atop'-framework. ** ========================================================================== ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Initial: July 2007 ** -------------------------------------------------------------------------- ** Copyright (C) 2007-2010 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 ** -------------------------------------------------------------------------- */ static const char rcsid[] = "$Id: atopsar.c,v 1.28 2010/11/26 06:19:43 gerlof Exp $"; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "atop.h" #include "ifprop.h" #include "photosyst.h" #include "photoproc.h" #include "gpucom.h" #define MAXFL 64 /* maximum number of command-line flags */ /* ** color definitions */ #define COLSETHEAD "\033[30;43m" /* black on yellow */ #define COLSETMED "\033[36m" /* cyan */ #define COLSETHIGH "\033[31m" /* red */ #define COLRESET "\033[00m" /* reset any color */ /* ** miscellaneous values */ static unsigned int nsamples = 9999999; static char stampalways; static char usemarkers; static char allresources; static int numreports; static time_t saved_begintime; static unsigned int repeathead = 9999999; static unsigned int summarycnt = 1; static char *datemsg = "-------------------------- analysis " "date: %s --------------------------\n"; /* ** structure definition for print-functions */ struct pridef { char wanted; /* selected option (boolean) */ char *cntcat; /* used categories of counters */ char flag; /* flag on command line */ void (*prihead)(); /* print header of list */ int (*priline)(struct sstat *, struct tstat *, struct tstat **, int, time_t, time_t, time_t, int, int, int, char *, int, int, int, int, int, int); /* print counters per line (excl. time) */ char *about; /* statistics about what */ }; extern struct pridef pridef[]; /* table of print-functions */ extern int pricnt; /* total number of print-functions */ static time_t daylim; /* last second of day in epoch */ static int prinow; /* current selection */ static char coloron; /* boolean: colors active now */ /* ** local prototypes */ static void engine(void); static void pratopsaruse(char *); static void reportlive(time_t, int, struct sstat *); static char reportraw (time_t, int, struct devtstat *, struct sstat *, int, unsigned int, char); static void reportheader(struct utsname *, time_t); static time_t daylimit(time_t); int atopsar(int argc, char *argv[]) { register int i, c; struct rlimit rlim; char *p, *flaglist; usecolors = 't'; /* ** interpret command-line arguments & flags */ if (argc > 1) { /* ** gather all flags for the print-functions */ flaglist = malloc(pricnt+32); ptrverify(flaglist, "Malloc failed for %d flags\n", pricnt+32); for (i=0; i < pricnt; i++) flaglist[i] = pridef[i].flag; flaglist[i] = 0; /* ** add generic flags */ strcat(flaglist, "b:e:SxCMHr:R:aA"); while ((c=getopt(argc, argv, flaglist)) != EOF) { switch (c) { case '?': /* usage wanted ? */ pratopsaruse(argv[0]); break; case 'b': /* begin time ? */ if ( !hhmm2secs(optarg, &begintime) ) pratopsaruse(argv[0]); saved_begintime = begintime; break; case 'e': /* end time ? */ if ( !hhmm2secs(optarg, &endtime) ) pratopsaruse(argv[0]); break; case 'r': /* reading of file data ? */ strncpy(rawname, optarg, RAWNAMESZ-1); rawreadflag++; break; case 'R': /* summarize samples */ if (!numeric(optarg)) pratopsaruse(argv[0]); summarycnt = atoi(optarg); if (summarycnt < 1) pratopsaruse(argv[0]); break; case 'S': /* timestamp on every line */ stampalways = 1; break; case 'x': /* never use colors */ usecolors = 0; break; case 'C': /* always use colors */ usecolors = 'a'; break; case 'M': /* markers for overload */ usemarkers = 1; break; case 'H': /* repeat headers */ repeathead = 23; /* define default */ if (isatty(1)) { struct winsize wsz; if ( ioctl(1, TIOCGWINSZ, &wsz) != -1) repeathead = wsz.ws_row - 1; } break; case 'a': /* every interval all units */ allresources = 1; break; case 'A': /* all reports wanted ? */ for (i=0; i < pricnt; i++) pridef[i].wanted = 1; numreports = pricnt; break; default: /* gather report-flags */ for (i=0; i < pricnt; i++) { if (pridef[i].flag == c && pridef[i].wanted == 0 ) { pridef[i].wanted = 1; numreports++; break; } } if (i == pricnt) pratopsaruse(argv[0]); } } free(flaglist); /* ** get optional interval-value and ** optional number of samples */ if (optind < argc && optind < MAXFL) { if (rawreadflag) pratopsaruse(argv[0]); if (!numeric(argv[optind])) pratopsaruse(argv[0]); interval = atoi(argv[optind]); optind++; if (optind < argc) { if (!numeric(argv[optind]) ) pratopsaruse(argv[0]); if ( (nsamples = atoi(argv[optind])) < 1) pratopsaruse(argv[0]); } } else /* if no interval specified, read from logfile */ { rawreadflag++; } } else /* if no flags specified at all, read from logfile */ { rawreadflag++; } /* ** if no report-flags have been specified, take the first ** option in the print-list as default */ if (numreports == 0) { pridef[0].wanted = 1; numreports = 1; } /* ** set stdout output on line-basis */ setvbuf(stdout, (char *)0, _IOLBF, BUFSIZ); /* ** if only use colors when the output is directed to a tty, ** be sure that output is directed to a tty */ if (usecolors == 't') { if (! isatty(1) ) usecolors = 0; } /* ** check if raw data from a file must be viewed */ if (rawreadflag) { /* ** select own reportraw-function to be called ** by the rawread function */ vis.show_samp = reportraw; for (i=0; i < pricnt; i++) { if ( pridef[i].wanted ) { prinow = i; daylim = 0; begintime = saved_begintime; rawread(); printf("\n"); } } cleanstop(0); } /* ** live data must be gathered ** ** determine the name of this node (without domain-name) ** and the kernel-version */ (void) uname(&utsname); if ( (p = strchr(utsname.nodename, '.')) ) *p = '\0'; sscanf(utsname.release, "%d.%d.%d", &osrel, &osvers, &ossub); /* ** determine the clock rate and memory page size for this machine */ hertz = sysconf(_SC_CLK_TCK); pagesize = sysconf(_SC_PAGESIZE); /* ** determine start-time for gathering current statistics */ curtime = time(0); /* ** regain the root-priviliges that we dropped at the beginning ** to do some priviliged work now */ regainrootprivs(); /* ** lock in memory to get reliable samples (also when ** memory is low); ** ignored if not running under superuser privileges! */ rlim.rlim_cur = RLIM_INFINITY; rlim.rlim_max = RLIM_INFINITY; (void) setrlimit(RLIMIT_MEMLOCK, &rlim); (void) mlockall(MCL_CURRENT|MCL_FUTURE); /* ** increment CPU scheduling-priority to get reliable samples (also ** during heavy CPU load); ** ignored if not running under superuser privileges! */ if ( nice(-20) == -1) ; /* ** determine properties (like speed) of all interfaces */ initifprop(); /* ** since privileged activities are finished now, there is no ** need to keep running under root-privileges, so switch ** effective user-id to real user-id */ if (! droprootprivs() ) cleanstop(42); /* ** start live reporting */ engine(); return 0; } /* ** engine() that drives the main-loop for atopsar */ static void engine(void) { struct sigaction sigact; void getusr1(int); int nrgpus; /* number of GPUs */ int nrgpuproc, /* number of GPU procs */ gpustats=0; /* boolean: request sent */ /* ** reserve space for system-level statistics */ static struct sstat *cursstat; /* current */ static struct sstat *presstat; /* previous */ static struct sstat *devsstat; /* deviation */ static struct sstat *hlpsstat; /* ** initialization: allocate required memory dynamically */ cursstat = calloc(1, sizeof(struct sstat)); presstat = calloc(1, sizeof(struct sstat)); devsstat = calloc(1, sizeof(struct sstat)); ptrverify(cursstat, "Malloc failed for current sysstats\n"); ptrverify(presstat, "Malloc failed for prev sysstats\n"); ptrverify(devsstat, "Malloc failed for deviate sysstats\n"); /* ** install the signal-handler for ALARM and SIGUSR1 (both triggers ** for the next sample) */ memset(&sigact, 0, sizeof sigact); sigact.sa_handler = getusr1; sigaction(SIGUSR1, &sigact, (struct sigaction *)0); memset(&sigact, 0, sizeof sigact); sigact.sa_handler = getalarm; sigaction(SIGALRM, &sigact, (struct sigaction *)0); if (interval > 0) alarm(interval); /* ** print overall report header */ reportheader(&utsname, time(0)); /* ** open socket to the atopgpud daemon for GPU statistics */ nrgpus = gpud_init(); /* ** MAIN-LOOP: ** - Wait for the requested number of seconds or for other trigger ** ** - System-level counters ** get current counters ** calculate the differences with the previous sample ** ** - Call the print-function to visualize the differences */ for (sampcnt=0; sampcnt < nsamples+1; sampcnt++) { /* ** wait for alarm-signal to arrive or ** wait for SIGUSR1 in case of an interval of 0. */ if (sampcnt > 0) pause(); /* ** gather time info for this sample */ pretime = curtime; curtime = time(0); /* seconds since 1-1-1970 */ /* ** send request for statistics to atopgpud */ if (nrgpus) gpustats = gpud_statrequest(); /* ** take a snapshot of the current system-level statistics ** and calculate the deviations (i.e. calculate the activity ** during the last sample) */ hlpsstat = cursstat; /* swap current/prev. stats */ cursstat = presstat; presstat = hlpsstat; photosyst(cursstat); /* obtain new counters */ /* ** receive and parse response from atopgpud */ if (nrgpus && gpustats) { nrgpuproc = gpud_statresponse(nrgpus, cursstat->gpu.gpu, NULL); // connection lost or timeout on receive? if (nrgpuproc == -1) { int ng; // try to reconnect ng = gpud_init(); if (ng != nrgpus) // no success nrgpus = 0; if (nrgpus) { // request for stats again if (gpud_statrequest()) { // receive stats response nrgpuproc = gpud_statresponse(nrgpus, cursstat->gpu.gpu, NULL); // persistent failure? if (nrgpuproc == -1) nrgpus = 0; } } } cursstat->gpu.nrgpus = nrgpus; } /* ** calculate deviations, i.e. activity during interval */ deviatsyst(cursstat, presstat, devsstat, curtime-pretime > 0 ? curtime-pretime : 1); /* ** activate the report-function to visualize the deviations */ reportlive(curtime, curtime-pretime > 0 ? curtime-pretime : 1, devsstat); } /* end of main-loop */ } /* ** report function to print a new sample in case of live measurements */ static void reportlive(time_t curtime, int numsecs, struct sstat *ss) { char timebuf[16], datebuf[16]; int i, nr = numreports, rv; static unsigned int curline, headline; /* ** printing more reports needs another way of handling compared ** to printing one report */ if (numreports > 1) { /* ** skip first sample */ if (sampcnt == 0) return; printf(datemsg, convdate(curtime, datebuf)); for (i=0; i < pricnt && nr > 0; i++) { if ( !pridef[i].wanted ) continue; nr--; /* ** print header-line */ printf("\n"); if (usecolors) printf(COLSETHEAD); printf("%s ", convtime(curtime-numsecs, timebuf)); (pridef[i].prihead)(osvers, osrel, ossub); if (usecolors) printf(COLRESET); printf("\n"); /* ** print line with statistical counters */ printf("%s ", convtime(curtime, timebuf)); if ( !(pridef[i].priline)(ss, (struct tstat *)0, 0, 0, numsecs, numsecs*hertz, hertz, osvers, osrel, ossub, stampalways ? timebuf : " ", 0, 0, 0, 0, 0, 0) ) { /* ** print line has failed; ** do not call function again */ pridef[i].wanted = 0; if (--numreports == 0) cleanstop(1); } } printf("\n"); } else /* just one report to be printed */ { /* ** search required report */ for (i=0; i < pricnt; i++) if ( pridef[i].wanted ) break; /* ** verify if we have passed midnight of some day */ if (curtime > daylim) { printf(datemsg, convdate(curtime, datebuf)); daylim = daylimit(curtime); curline++; } /* ** print first header */ if (sampcnt == 0) { /* ** print header-line */ printf("\n"); if (usecolors) printf(COLSETHEAD); printf("%s ", convtime(curtime, timebuf)); (pridef[i].prihead)(osvers, osrel, ossub); if (usecolors) printf(COLRESET); printf("\n"); curline+=2; headline = repeathead; return; } /* ** print line with statistical counters */ printf("%s ", convtime(curtime, timebuf)); if ( !(rv = (pridef[i].priline)(ss, (struct tstat *)0, 0, 0, numsecs, numsecs*hertz, hertz, osvers, osrel, ossub, stampalways ? timebuf : " ", 0, 0, 0, 0, 0, 0) ) ) { /* ** print line has failed; ** do not call function again */ cleanstop(1); } curline+=rv; if (curline >= headline) { headline = curline + repeathead; /* ** print header-line */ printf("\n"); if (usecolors) printf(COLSETHEAD); printf("%s ", convtime(curtime, timebuf)); (pridef[i].prihead)(osvers, osrel, ossub); if (usecolors) printf(COLRESET); printf("\n"); curline+=2; } } } /* ** report function to print a new sample in case of logged measurements */ static char reportraw(time_t curtime, int numsecs, struct devtstat *devtstat, struct sstat *sstat, int nexit, unsigned int noverflow, char flags) { static char firstcall = 1; char timebuf[16], datebuf[16]; unsigned int rv; static unsigned int curline, headline, sampsum, totalsec, totalexit, lastnpres, lastntrun, lastntslpi, lastntslpu, lastnzomb; static time_t lasttime; static struct sstat totsyst; /* ** is this function still wanted? */ if ( ! pridef[prinow].wanted ) return '\0'; /* ** when this is first call to this function, ** print overall header with system information */ if (firstcall) { reportheader(&utsname, time(0)); firstcall = 0; } /* ** verify if we have passed midnight */ if (curtime > daylim) { printf(datemsg, convdate(curtime, datebuf)); daylim = daylimit(curtime); curline++; } /* ** when this is the first record for a new report, ** initialize various variables */ if (sampcnt == 1) { /* ** initialize variables for new report */ pretime = curtime; curline = 1; headline = 0; sampsum = summarycnt + 1; totalsec = 0; totalexit = 0; memset(&totsyst, 0, sizeof totsyst); return '\0'; } /* ** check if a (new) report header needs to be printed */ if (curline >= headline) { headline = curline + repeathead; /* ** print header-line */ printf("\n"); if (usecolors) printf(COLSETHEAD); printf("%s ", convtime(pretime, timebuf)); (pridef[prinow].prihead)(osvers, osrel, ossub); if (usecolors) printf(COLRESET); printf("\n"); curline+=2; } /* ** when current record contains log-restart indicator, ** print message and reinitialize variables */ if (flags & RRBOOT) { /* ** when accumulating counters, print results upto ** the *previous* record */ if (summarycnt > 1 && sampcnt <= sampsum && totalsec) { printf("%s ", convtime(lasttime, timebuf)); rv = (pridef[prinow].priline)(&totsyst, (struct tstat *)0, 0, 0, totalsec, totalsec*hertz, hertz, osvers, osrel, ossub, stampalways ? timebuf : " ", lastnpres, lastntrun, lastntslpi, lastntslpu, totalexit, lastnzomb); if (rv == 0) { curline++; pridef[prinow].wanted = 0; /* not call again */ if (--numreports == 0) cleanstop(1); } else { curline += rv; } } /* ** print restart-line in case of logging restarted */ printf("%s ", convtime(curtime, timebuf)); printf("......................... logging restarted " ".........................\n"); pretime = curtime; curline++; /* ** reinitialize variables */ sampsum = summarycnt + sampcnt; totalsec = 0; totalexit = 0; memset(&totsyst, 0, sizeof totsyst); return '\0'; } /* ** when no accumulation is required, ** just print current sample */ if (summarycnt == 1) { printf("%s ", convtime(curtime, timebuf)); rv = (pridef[prinow].priline) (sstat, devtstat->taskall, devtstat->procall, devtstat->nprocall, numsecs, numsecs*hertz, hertz, osvers, osrel, ossub, stampalways ? timebuf : " ", devtstat->ntaskall, devtstat->totrun, devtstat->totslpi, devtstat->totslpu, nexit, devtstat->totzombie); if (rv == 0) { curline++; pridef[prinow].wanted = 0; /* not call again */ if (--numreports == 0) cleanstop(1); } else { curline += rv; } } else /* accumulation is required */ { char *cp = pridef[prinow].cntcat; /* ** maintain totals per category */ while (*cp) { totalsyst(*cp, sstat, &totsyst); cp++; } totalsec += numsecs; totalexit += nexit; /* ** remember some values in case the next record ** contains the log-restart indicator */ lasttime = curtime; lastnpres = devtstat->nprocall; lastntrun = devtstat->totrun; lastntslpi = devtstat->totslpi; lastntslpu = devtstat->totslpu; lastnzomb = devtstat->totzombie; /* ** print line only if needed */ if (sampcnt >= sampsum || ( (flags&RRLAST) && totalsec) ) { /* ** print output line for required report */ printf("%s ", convtime(curtime, timebuf)); rv = (pridef[prinow].priline) (&totsyst, (struct tstat *)0, 0, 0, totalsec, totalsec*hertz, hertz, osvers, osrel, ossub, stampalways ? timebuf : " ", devtstat->ntaskall, devtstat->totrun, devtstat->totslpi, devtstat->totslpu, totalexit, devtstat->totzombie); if (rv == 0) { curline++; pridef[prinow].wanted = 0; /* not call again */ if (--numreports == 0) cleanstop(1); } else { curline += rv; } sampsum = summarycnt + sampcnt; totalsec = 0; totalexit = 0; memset(&totsyst, 0, sizeof totsyst); } else { rv = 1; } } if (!rv) { /* ** print for line has failed; ** never call this function again */ pridef[prinow].wanted = 0; if (--numreports == 0) cleanstop(1); } pretime = curtime; return '\0'; } /* ** print overall header */ static void reportheader(struct utsname *uname, time_t mtime) { char cdate[16]; printf("\n%s %s %s %s %s\n\n", uname->nodename, uname->release, uname->version, uname->machine, convdate(mtime, cdate)); } /* ** print usage of atopsar command */ void pratopsaruse(char *myname) { int i; fprintf(stderr, "Usage: %s [-flags] [-r file|date|y...] [-R cnt] [-b hh:mm] [-e hh:mm]\n", myname); fprintf(stderr, "\t\tor\n"); fprintf(stderr, "Usage: %s [-flags] interval [samples]\n", myname); fprintf(stderr, "\n"); fprintf(stderr, "\tToday's atop logfile is used by default!\n"); fprintf(stderr, "\n"); fprintf(stderr, "\tGeneric flags:\n"); fprintf(stderr, "\t -r read statistical data from specific atop logfile\n"); fprintf(stderr, "\t (pathname, or date in format YYYYMMDD, or y[y..])\n"); fprintf(stderr, "\t -R summarize samples into one sample\n"); fprintf(stderr, "\t -b begin showing data from specified time\n"); fprintf(stderr, "\t -e finish showing data after specified time\n"); fprintf(stderr, "\t -S print timestamp on every line in case of more " "resources\n"); fprintf(stderr, "\t -x never use colors to indicate overload" " (default: only if tty)\n"); fprintf(stderr, "\t -C always use colors to indicate overload" " (default: only if tty)\n"); fprintf(stderr, "\t -M use markers to indicate overload " "(* = critical, + = almost)\n"); fprintf(stderr, "\t -H repeat report headers " "(in case of tty: depending on screen lines)\n"); fprintf(stderr, "\t -a print all resources, even when inactive\n"); fprintf(stderr, "\n"); fprintf(stderr, "\tSpecific flags to select reports:\n"); fprintf(stderr, "\t -A print all available reports\n"); for (i=0; i < pricnt; i++) fprintf(stderr, "\t -%c %s\n", pridef[i].flag, pridef[i].about); fprintf(stderr, "\n"); fprintf(stderr, "Please refer to the man-page of 'atopsar' " "for more details.\n"); cleanstop(1); } /* ** calculate the epoch-value for the last second ** of the day given a certain epoch */ static time_t daylimit(time_t timval) { struct tm *tp = localtime(&timval); tp->tm_hour = 23; tp->tm_min = 59; tp->tm_sec = 59; return mktime(tp); } /* ** function to be called before printing a statistics line ** to switch on colors when necessary */ static void preprint(unsigned int badness) { if (usecolors) { if (badness >= 100) { coloron = 1; printf(COLSETHIGH); } else { if (almostcrit && badness >= almostcrit) { coloron = 1; printf(COLSETMED); } } } } /* ** function to be called after printing a statistics line ** to switch off colors when necessary and print a line feed */ static void postprint(unsigned int badness) { if (coloron) { coloron = 0; printf(COLRESET); } if (usemarkers) { if (badness >= 100) { printf(" *"); } else { if (almostcrit && badness >= almostcrit) printf(" +"); } } printf("\n"); } /* ** function the handle the default flags for atopsar as ** read from the file ~/.atoprc */ void do_atopsarflags(char *val) { int i, j; for (i=0; val[i]; i++) { switch (val[i]) { case '-': break; case 'S': /* timestamp on every line */ stampalways = 1; break; case 'x': /* always colors for overload */ usecolors = 0; break; case 'C': /* always colors for overload */ usecolors = 'a'; break; case 'M': /* markers for overload */ usemarkers = 1; break; case 'H': /* repeat headers */ repeathead = 23; /* define default */ if (isatty(1)) { struct winsize wsz; if ( ioctl(1, TIOCGWINSZ, &wsz) != -1) repeathead = wsz.ws_row - 1; } break; case 'a': /* every interval all units */ allresources = 1; break; case 'A': /* all reports wanted ? */ for (j=0; j < pricnt; j++) pridef[j].wanted = 1; numreports = pricnt; break; default: /* gather report-flags */ for (j=0; j < pricnt; j++) { if (pridef[j].flag == val[i] && pridef[j].wanted == 0 ) { pridef[j].wanted = 1; numreports++; break; } } } } } /**************************************************************************/ /* Functions to print statistics */ /**************************************************************************/ /* ** CPU statistics */ static void cpuhead(int osvers, int osrel, int ossub) { printf("cpu %%usr %%nice %%sys %%irq %%softirq %%steal %%guest " " %%wait %%idle _cpu_"); } static int cpuline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { register int i, nlines = 1; count_t cputot; unsigned int badness; /* ** print overall statistics */ cputot = ss->cpu.all.stime + ss->cpu.all.utime + ss->cpu.all.ntime + ss->cpu.all.itime + ss->cpu.all.wtime + ss->cpu.all.Itime + ss->cpu.all.Stime + ss->cpu.all.steal; if (cputot == 0) cputot = 1; /* avoid divide-by-zero */ if (cpubadness) badness = ((cputot - ss->cpu.all.itime - ss->cpu.all.wtime) * 100.0 / cputot) * 100 / cpubadness; else badness = 0; preprint(badness); printf("all %5.0lf %5.0lf %4.0lf %4.0lf %8.0lf %7.0f %6.0f %6.0lf %5.0lf", (double) (ss->cpu.all.utime * 100.0) / cputot * ss->cpu.nrcpu, (double) (ss->cpu.all.ntime * 100.0) / cputot * ss->cpu.nrcpu, (double) (ss->cpu.all.stime * 100.0) / cputot * ss->cpu.nrcpu, (double) (ss->cpu.all.Itime * 100.0) / cputot * ss->cpu.nrcpu, (double) (ss->cpu.all.Stime * 100.0) / cputot * ss->cpu.nrcpu, (double) (ss->cpu.all.steal * 100.0) / cputot * ss->cpu.nrcpu, (double) (ss->cpu.all.guest * 100.0) / cputot * ss->cpu.nrcpu, (double) (ss->cpu.all.wtime * 100.0) / cputot * ss->cpu.nrcpu, (double) (ss->cpu.all.itime * 100.0) / cputot * ss->cpu.nrcpu); postprint(badness); /* ** print per-cpu statistics */ if (ss->cpu.nrcpu > 1) { for (i=0; i < ss->cpu.nrcpu; i++) { cputot = ss->cpu.cpu[i].stime + ss->cpu.cpu[i].utime + ss->cpu.cpu[i].ntime + ss->cpu.cpu[i].itime + ss->cpu.cpu[i].wtime + ss->cpu.cpu[i].Itime + ss->cpu.cpu[i].Stime + ss->cpu.cpu[i].steal; if (cputot == 0) cputot = 1; /* avoid divide-by-zero */ if (cpubadness) badness = ((cputot - ss->cpu.cpu[i].itime - ss->cpu.cpu[i].wtime) * 100.0 / cputot) * 100 / cpubadness; else badness = 0; printf("%s ", tstamp); preprint(badness); printf("%4d %5.0lf %5.0lf %4.0lf %4.0lf %8.0lf " "%7.0f %6.0lf %6.0lf %5.0lf", i, (double)(ss->cpu.cpu[i].utime * 100.0) / cputot, (double)(ss->cpu.cpu[i].ntime * 100.0) / cputot, (double)(ss->cpu.cpu[i].stime * 100.0) / cputot, (double)(ss->cpu.cpu[i].Itime * 100.0) / cputot, (double)(ss->cpu.cpu[i].Stime * 100.0) / cputot, (double)(ss->cpu.cpu[i].steal * 100.0) / cputot, (double)(ss->cpu.cpu[i].guest * 100.0) / cputot, (double)(ss->cpu.cpu[i].wtime * 100.0) / cputot, (double)(ss->cpu.cpu[i].itime * 100.0) / cputot); postprint(badness); nlines++; } } return nlines; } /* ** GPU statistics */ static void gpuhead(int osvers, int osrel, int ossub) { printf(" busaddr gpubusy membusy memocc memtot memuse gputype" " _gpu_"); } static int gpuline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { static char firstcall = 1; register long i, nlines = 0; char fmt1[16], fmt2[16]; count_t avgmemuse; for (i=0; i < ss->gpu.nrgpus; i++) /* per GPU */ { /* ** determine whether or not the GPU has been active ** during interval */ int wasactive; wasactive = ss->gpu.gpu[i].gpuperccum + ss->gpu.gpu[i].memperccum; if (wasactive == -2) // metrics not available? wasactive = 0; if (ss->gpu.gpu[i].samples == 0) avgmemuse = ss->gpu.gpu[i].memusenow; else avgmemuse = ss->gpu.gpu[i].memusecum / ss->gpu.gpu[i].samples; // memusage > 512 MiB (rather arbitrary)? // if (avgmemuse > 512*1024) wasactive = 1; /* ** print for the first sample all GPUs that are found; ** afterwards print only info about the GPUs ** that were really active during the interval */ if (!firstcall && !allresources && !wasactive) continue; if (nlines++) printf("%s ", tstamp); if (ss->gpu.gpu[i].samples == 0) ss->gpu.gpu[i].samples = 1; if (ss->gpu.gpu[i].gpuperccum == -1) strcpy(fmt1, "N/A"); else snprintf(fmt1, sizeof fmt1, "%lld%%", ss->gpu.gpu[i].gpuperccum / ss->gpu.gpu[i].samples); if (ss->gpu.gpu[i].memperccum == -1) strcpy(fmt2, "N/A"); else snprintf(fmt2, sizeof fmt2, "%lld%%", ss->gpu.gpu[i].memperccum / ss->gpu.gpu[i].samples); if (ss->gpu.gpu[i].memtotnow == 0) ss->gpu.gpu[i].memtotnow = 1; printf("%2ld/%9.9s %7s %7s %5lld%% %5lldM %5lldM %s\n", i, ss->gpu.gpu[i].busid, fmt1, fmt2, ss->gpu.gpu[i].memusenow*100/ss->gpu.gpu[i].memtotnow, ss->gpu.gpu[i].memtotnow / 1024, ss->gpu.gpu[i].memusenow / 1024, ss->gpu.gpu[i].type); } if (nlines == 0) { printf("\n"); nlines++; } firstcall = 0; return nlines; } /* ** other processor statistics */ static void prochead(int osvers, int osrel, int ossub) { printf("pswch/s devintr/s clones/s loadavg1 loadavg5 loadavg15 " " _load_"); } static int procline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { printf("%7.0lf %9.0lf %9.2lf %8.2lf %8.2lf %8.2lf\n", (double)ss->cpu.csw / deltasec, (double)ss->cpu.devint / deltasec, (double)ss->cpu.nprocs / deltasec, ss->cpu.lavg1, ss->cpu.lavg5, ss->cpu.lavg15); return 1; } /* ** process statistics */ static void taskhead(int osvers, int osrel, int ossub) { printf("clones/s pexit/s curproc curzomb thrrun thrslpi thrslpu " "_procthr_"); } static int taskline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { if (ppres == 0) { printf("report not available for live measurements.....\n"); return 0; } if (ts) /* process statistics available */ { printf("%8.2lf %7.2lf %7d %7d %6d %7d %7d\n", (double)ss->cpu.nprocs / deltasec, (double)pexit / deltasec, nactproc-pexit, pzombie, ntrun, ntslpi, ntslpu); } else { printf("%8.2lf %7.2lf %7d %7d\n", (double)ss->cpu.nprocs / deltasec, (double)pexit / deltasec, nactproc-pexit, pzombie); } return 1; } /* ** memory- & swap-usage */ static void memhead(int osvers, int osrel, int ossub) { printf("memtotal memfree buffers cached dirty slabmem" " swptotal swpfree _mem_" ); } static int memline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { unsigned int mbadness, sbadness; if (membadness) mbadness = ((ss->mem.physmem - ss->mem.freemem - ss->mem.cachemem - ss->mem.buffermem) * 100.0 / ss->mem.physmem) * 100 / membadness; else mbadness = 0; if (swpbadness) sbadness = ((ss->mem.totswap - ss->mem.freeswap) * 100.0 / ss->mem.totswap) * 100 / swpbadness; else sbadness = 0; preprint(mbadness >= sbadness ? mbadness : sbadness); printf("%7lldM %6lldM %6lldM %5lldM %4lldM %6lldM %7lldM %6lldM", ss->mem.physmem * (pagesize / 1024) /1024, ss->mem.freemem * (pagesize / 1024) /1024, ss->mem.buffermem * (pagesize / 1024) /1024, ss->mem.cachemem * (pagesize / 1024) /1024, ss->mem.cachedrt * (pagesize / 1024) /1024, ss->mem.slabmem * (pagesize / 1024) /1024, ss->mem.totswap * (pagesize / 1024) /1024, ss->mem.freeswap * (pagesize / 1024) /1024); postprint(mbadness >= sbadness ? mbadness : sbadness); return 1; } /* ** swapping statistics */ static void swaphead(int osvers, int osrel, int ossub) { printf("pagescan/s swapin/s swapout/s " " commitspc commitlim _swap_"); } static int swapline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { unsigned int badness; if (membadness) badness = (ss->mem.swouts / deltasec * pagbadness) * 100 / membadness; else badness = 0; /* ** take care that this line is anyhow colored for ** 'almost critical' in case of swapouts > 1 per second */ if (ss->mem.swouts / deltasec > 0 && pagbadness && almostcrit && badness < almostcrit) badness = almostcrit; if (ss->mem.commitlim && ss->mem.committed > ss->mem.commitlim) badness = 100; /* force colored output */ preprint(badness); printf("%10.2lf %9.2lf %9.2lf %9lluM %9lluM", (double)ss->mem.pgscans / deltasec, (double)ss->mem.swins / deltasec, (double)ss->mem.swouts / deltasec, ss->mem.committed * (pagesize / 1024) / 1024, ss->mem.commitlim * (pagesize / 1024) / 1024); postprint(badness); return 1; } /* ** swapping statistics */ static void psihead(int osvers, int osrel, int ossub) { printf("cs_10_60_300 ms_10_60_300 mf_10_60_300 " "is_10_60_300 if_10_60_300"); } static int psiline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { if (!ss->psi.present) { printf("no PSI stats available for this system .....\n"); return 0; } printf("%3.0f%%%3.0f%%%3.0f%% %3.0f%%%3.0f%%%3.0f%% " "%3.0f%%%3.0f%%%3.0f%% %3.0f%%%3.0f%%%3.0f%% " "%3.0f%%%3.0f%%%3.0f%%\n", ss->psi.cpusome.avg10, ss->psi.cpusome.avg60, ss->psi.cpusome.avg300, ss->psi.memsome.avg10, ss->psi.memsome.avg60, ss->psi.memsome.avg300, ss->psi.memfull.avg10, ss->psi.memfull.avg60, ss->psi.memfull.avg300, ss->psi.iosome.avg10, ss->psi.iosome.avg60, ss->psi.iosome.avg300, ss->psi.iofull.avg10, ss->psi.iofull.avg60, ss->psi.iofull.avg300); return 1; } /* ** disk statistics */ static void lvmhead(int osvers, int osrel, int ossub) { printf("disk busy read/s KB/read " "writ/s KB/writ avque avserv _lvm_"); } static void mddhead(int osvers, int osrel, int ossub) { printf("disk busy read/s KB/read " "writ/s KB/writ avque avserv _mdd_"); } static void dskhead(int osvers, int osrel, int ossub) { printf("disk busy read/s KB/read " "writ/s KB/writ avque avserv _dsk_"); } static int gendskline(struct sstat *ss, char *tstamp, char selector) { static char firstcall = 1; register int i, nlines = 0, nunit = 0; count_t mstot, iotot; struct perdsk *dp; unsigned int badness; switch (selector) { case 'l': dp = ss->dsk.lvm; nunit = ss->dsk.nlvm; break; case 'm': dp = ss->dsk.mdd; nunit = ss->dsk.nmdd; break; case 'd': dp = ss->dsk.dsk; nunit = ss->dsk.ndsk; break; default: return 0; } mstot = (ss->cpu.all.stime + ss->cpu.all.utime + ss->cpu.all.ntime + ss->cpu.all.itime + ss->cpu.all.wtime + ss->cpu.all.Itime + ss->cpu.all.Stime + ss->cpu.all.steal ) * (count_t)1000 / hertz / ss->cpu.nrcpu; for (i=0; i < nunit; i++, dp++) { char *pn; int len; if ( (iotot = dp->nread + dp->nwrite) == 0 && !firstcall && !allresources ) continue; /* no activity on this disk */ /* ** disk was active during last interval; print info */ if (nlines++) printf("%s ", tstamp); if (dskbadness) badness = (dp->io_ms * 100.0 / mstot) * 100/dskbadness; else badness = 0; preprint(badness); if ( (len = strlen(dp->name)) > 14) pn = dp->name + len - 14; else pn = dp->name; printf("%-14s %3.0lf%% %6.1lf %7.1lf %7.1lf %7.1lf " "%5.1lf %6.2lf ms", pn, mstot ? (double)dp->io_ms * 100.0 / mstot : 0.0, mstot ? (double)dp->nread * 1000.0 / mstot : 0.0, dp->nread ? (double)dp->nrsect / dp->nread / 2.0 : 0.0, mstot ? (double)dp->nwrite * 1000.0 / mstot : 0.0, dp->nwrite ? (double)dp->nwsect / dp->nwrite / 2.0 : 0.0, dp->io_ms ? (double)dp->avque / dp->io_ms : 0.0, iotot ? (double)dp->io_ms / iotot : 0.0); postprint(badness); } if (nlines == 0) { printf("\n"); nlines++; } firstcall = 0; return nlines; } static int lvmline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { return gendskline(ss, tstamp, 'l'); } static int mddline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { return gendskline(ss, tstamp, 'm'); } static int dskline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { return gendskline(ss, tstamp, 'd'); } /* ** NFS client statistics */ static void nfmhead(int osvers, int osrel, int ossub) { printf("mounted_device physread/s physwrit/s" " _nfm_"); } static int nfmline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { static char firstcall = 1; register long i, nlines = 0; char *pn, state; int len; for (i=0; i < ss->nfs.nfsmounts.nrmounts; i++) /* per NFS mount */ { /* ** print for the first sample all mounts that ** are found; afterwards print only the mounts ** that were really active during the interval */ if (firstcall || allresources || ss->nfs.nfsmounts.nfsmnt[i].age < deltasec || ss->nfs.nfsmounts.nfsmnt[i].bytestotread || ss->nfs.nfsmounts.nfsmnt[i].bytestotwrite ) { if (nlines++) printf("%s ", tstamp); if ( (len = strlen(ss->nfs.nfsmounts.nfsmnt[i].mountdev)) > 38) pn = ss->nfs.nfsmounts.nfsmnt[i].mountdev + len - 38; else pn = ss->nfs.nfsmounts.nfsmnt[i].mountdev; if (ss->nfs.nfsmounts.nfsmnt[i].age < deltasec) state = 'M'; else state = ' '; printf("%-38s %10.3lfK %10.3lfK %c\n", pn, (double)ss->nfs.nfsmounts.nfsmnt[i].bytestotread / 1024 / deltasec, (double)ss->nfs.nfsmounts.nfsmnt[i].bytestotwrite / 1024 / deltasec, state); } } if (nlines == 0) { printf("\n"); nlines++; } firstcall= 0; return nlines; } static void nfchead(int osvers, int osrel, int ossub) { printf(" rpc/s rpcread/s rpcwrite/s retrans/s autrefresh/s " " _nfc_"); } static int nfcline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { printf("%10.2lf %10.2lf %10.2lf %10.2lf %12.2lf\n", (double)ss->nfs.client.rpccnt / deltasec, (double)ss->nfs.client.rpcread / deltasec, (double)ss->nfs.client.rpcwrite / deltasec, (double)ss->nfs.client.rpcretrans / deltasec, (double)ss->nfs.client.rpcautrefresh / deltasec); return 1; } static void nfshead(int osvers, int osrel, int ossub) { printf(" rpc/s rpcread/s rpcwrite/s MBcr/s MBcw/s " "nettcp/s netudp/s _nfs_"); } static int nfsline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { printf("%7.2lf %10.2lf %10.2lf %6.2lf %7.2lf %9.2lf %8.2lf\n", (double)ss->nfs.server.rpccnt / deltasec, (double)ss->nfs.server.rpcread / deltasec, (double)ss->nfs.server.rpcwrite / deltasec, (double)ss->nfs.server.nrbytes / 1024.0 / 1024.0 / deltasec, (double)ss->nfs.server.nwbytes / 1024.0 / 1024.0 / deltasec, (double)ss->nfs.server.nettcpcnt / deltasec, (double)ss->nfs.server.netudpcnt / deltasec); return 1; } /* ** network-interface statistics */ static void ibhead(int osvers, int osrel, int ossub) { printf("controller port busy ipack/s opack/s " "igbps ogbps maxgbps lanes _ib_"); } static int ibline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { static char firstcall = 1; register long i, nlines = 0; double busy; unsigned int badness; for (i=0; i < ss->ifb.nrports; i++) /* per interface */ { count_t ival, oval; /* ** print for the first sample all ports that ** are found; afterwards print only the ports ** that were really active during the interval */ if (!firstcall && !allresources && !ss->ifb.ifb[i].rcvb && !ss->ifb.ifb[i].sndb) continue; /* ** convert byte-transfers to bit-transfers (* 8) ** convert bit-transfers to megabit-transfers (/ 1000000) ** per second */ ival = ss->ifb.ifb[i].rcvb*ss->ifb.ifb[i].lanes/125000/deltasec; oval = ss->ifb.ifb[i].sndb*ss->ifb.ifb[i].lanes/125000/deltasec; /* ** calculate busy-percentage for port */ busy = (ival > oval ? ival*100 : oval*100)/ss->ifb.ifb[i].rate; if (nlines++) printf("%s ", tstamp); if (netbadness) badness = busy * 100 / netbadness; else badness = 0; preprint(badness); printf("%-10s %4hd %4.0f%% %7.1lf %7.1lf %5lld %5lld %7lld %5d", ss->ifb.ifb[i].ibname, ss->ifb.ifb[i].portnr, busy, (double)ss->ifb.ifb[i].rcvp / deltasec, (double)ss->ifb.ifb[i].sndp / deltasec, ival, oval, ss->ifb.ifb[i].rate / 1000, ss->ifb.ifb[i].lanes); postprint(badness); } if (nlines == 0) { printf("\n"); nlines++; } firstcall = 0; return nlines; } /* ** network-interface statistics */ static void ifhead(int osvers, int osrel, int ossub) { printf("interf busy ipack/s opack/s iKbyte/s oKbyte/s " "imbps ombps maxmbps_if_"); } static int ifline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { static char firstcall = 1; register long i, nlines = 0; double busy; char busyval[16], dupval; unsigned int badness; char *pn; int len; for (i=0; i < ss->intf.nrintf; i++) /* per interface */ { count_t ival, oval; /* ** print for the first sample all interfaces which ** are found; afterwards print only the interfaces ** which were really active during the interval */ if (!firstcall && !allresources && !ss->intf.intf[i].rpack && !ss->intf.intf[i].spack) continue; /* ** convert byte-transfers to bit-transfers (* 8) ** convert bit-transfers to megabit-transfers (/ 1000000) ** per second */ ival = ss->intf.intf[i].rbyte/125000/deltasec; oval = ss->intf.intf[i].sbyte/125000/deltasec; /* ** calculate busy-percentage for interface */ if (ss->intf.intf[i].speed) /* speed known? */ { if (ss->intf.intf[i].duplex) busy = (ival > oval ? ival*100 : oval*100) / ss->intf.intf[i].speed; else busy = (ival + oval) * 100 / ss->intf.intf[i].speed; // especially with wireless, the speed might have // dropped temporarily to a very low value (snapshot) // it might be better to take the speed of the // previous sample if (busy > 100 && ss->intf.intf[i].speed < ss->intf.intf[i].speedp ) { ss->intf.intf[i].speed = ss->intf.intf[i].speedp; if (ss->intf.intf[i].duplex) busy = (ival > oval ? ival*100 : oval*100) / ss->intf.intf[i].speed; else busy = (ival + oval) * 100 / ss->intf.intf[i].speed; } snprintf(busyval, sizeof busyval, "%3.0lf%%", busy); } else { strcpy(busyval, "?"); /* speed unknown */ busy = 0; } if (nlines++) printf("%s ", tstamp); if (ss->intf.intf[i].speed) { if (ss->intf.intf[i].duplex) dupval = 'f'; else dupval = 'h'; } else { dupval = ' '; } if (netbadness) badness = busy * 100 / netbadness; else badness = 0; if ( (len = strlen(ss->intf.intf[i].name)) > 6) pn = ss->intf.intf[i].name + len - 6; else pn = ss->intf.intf[i].name; preprint(badness); printf("%-6s %4s %7.1lf %7.1lf %8.0lf %8.0lf " "%5lld %5lld %7ld %c", pn, busyval, (double)ss->intf.intf[i].rpack / deltasec, (double)ss->intf.intf[i].spack / deltasec, (double)ss->intf.intf[i].rbyte / 1024 / deltasec, (double)ss->intf.intf[i].sbyte / 1024 / deltasec, ival, oval, ss->intf.intf[i].speed, dupval); postprint(badness); } if (nlines == 0) { printf("\n"); nlines++; } firstcall = 0; return nlines; } static void IFhead(int osvers, int osrel, int ossub) { printf("interf ierr/s oerr/s coll/s idrop/s odrop/s " "iframe/s ocarrier/s _if_"); } static int IFline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { static char firstcall = 1; register long i, nlines = 0; char *pn; int len; for (i=0; i < ss->intf.nrintf; i++) /* per interface */ { /* ** print for the first sample all interfaces which ** are found; afterwards print only the interfaces ** which were really active during the interval */ if (!firstcall && !allresources && !ss->intf.intf[i].rpack && !ss->intf.intf[i].spack) continue; if (nlines++) printf("%s ", tstamp); if ( (len = strlen(ss->intf.intf[i].name)) > 6) pn = ss->intf.intf[i].name + len - 6; else pn = ss->intf.intf[i].name; printf("%-6s %6.2lf %6.2lf %6.2lf %7.2lf %7.2lf " "%8.2lf %10.2lf\n", pn, (double)ss->intf.intf[i].rerrs / deltasec, (double)ss->intf.intf[i].serrs / deltasec, (double)ss->intf.intf[i].scollis / deltasec, (double)ss->intf.intf[i].rdrop / deltasec, (double)ss->intf.intf[i].sdrop / deltasec, (double)ss->intf.intf[i].rframe / deltasec, (double)ss->intf.intf[i].scarrier / deltasec); } if (nlines == 0) { printf("\n"); nlines++; } firstcall= 0; return nlines; } /* ** IP version 4 statistics */ static void ipv4head(int osvers, int osrel, int ossub) { printf("inrecv/s outreq/s indeliver/s forward/s " "reasmok/s fragcreat/s _ipv4_"); } static int ipv4line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { printf("%8.1lf %8.1lf %11.1lf %9.1lf %9.1lf %11.1lf\n", (double)ss->net.ipv4.InReceives / deltasec, (double)ss->net.ipv4.OutRequests / deltasec, (double)ss->net.ipv4.InDelivers / deltasec, (double)ss->net.ipv4.Forwarding / deltasec, (double)ss->net.ipv4.ReasmOKs / deltasec, (double)ss->net.ipv4.FragCreates / deltasec); return 1; } static void IPv4head(int osvers, int osrel, int ossub) { printf("in: dsc/s hder/s ader/s unkp/s ratim/s rfail/s " "out: dsc/s nrt/s_ipv4_"); } static int IPv4line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { printf(" %5.1lf %6.1lf %6.1lf %6.1lf %7.1lf %7.1lf " " %5.1lf %5.1lf\n", (double)ss->net.ipv4.InDiscards / deltasec, (double)ss->net.ipv4.InHdrErrors / deltasec, (double)ss->net.ipv4.InAddrErrors / deltasec, (double)ss->net.ipv4.InUnknownProtos / deltasec, (double)ss->net.ipv4.ReasmTimeout / deltasec, (double)ss->net.ipv4.ReasmFails / deltasec, (double)ss->net.ipv4.OutDiscards / deltasec, (double)ss->net.ipv4.OutNoRoutes / deltasec); return 1; } /* ** ICMP version 4 statistics */ static void icmpv4head(int osvers, int osrel, int ossub) { printf("intot/s outtot/s inecho/s inerep/s " "otecho/s oterep/s _icmpv4_" ); } static int icmpv4line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { printf("%7.1lf %8.1lf %8.2lf %8.2lf %8.2lf %8.2lf\n", (double)ss->net.icmpv4.InMsgs / deltasec, (double)ss->net.icmpv4.OutMsgs / deltasec, (double)ss->net.icmpv4.InEchos / deltasec, (double)ss->net.icmpv4.OutEchos / deltasec, (double)ss->net.icmpv4.InEchoReps / deltasec, (double)ss->net.icmpv4.OutEchoReps / deltasec); return 1; } static void ICMPv4head(int osvers, int osrel, int ossub) { printf("ierr/s isq/s ird/s idu/s ite/s " "oerr/s osq/s ord/s odu/s ote/s_icmpv4_"); } static int ICMPv4line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { printf("%6.2lf %5.2lf %5.2lf %5.2lf %5.2lf " "%6.2lf %5.2lf %5.2lf %5.2lf %5.2lf\n", (double)ss->net.icmpv4.InErrors / deltasec, (double)ss->net.icmpv4.InSrcQuenchs / deltasec, (double)ss->net.icmpv4.InRedirects / deltasec, (double)ss->net.icmpv4.InDestUnreachs / deltasec, (double)ss->net.icmpv4.InTimeExcds / deltasec, (double)ss->net.icmpv4.OutErrors / deltasec, (double)ss->net.icmpv4.OutSrcQuenchs / deltasec, (double)ss->net.icmpv4.OutRedirects / deltasec, (double)ss->net.icmpv4.OutDestUnreachs / deltasec, (double)ss->net.icmpv4.OutTimeExcds / deltasec); return 1; } /* ** UDP version 4 statistics */ static void udpv4head(int osvers, int osrel, int ossub) { printf("indgram/s outdgram/s inerr/s noport/s " " _udpv4_"); } static int udpv4line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { printf("%9.1lf %10.1lf %7.2lf %9.2lf\n", (double)ss->net.udpv4.InDatagrams / deltasec, (double)ss->net.udpv4.OutDatagrams / deltasec, (double)ss->net.udpv4.InErrors / deltasec, (double)ss->net.udpv4.NoPorts / deltasec); return 1; } /* ** IP version 6 statistics */ static void ipv6head(int osvers, int osrel, int ossub) { printf("inrecv/s outreq/s inmc/s outmc/s indeliv/s " "reasmok/s fragcre/s _ipv6_"); } static int ipv6line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { printf("%8.1lf %8.1lf %6.1lf %7.1lf %9.1lf %9.1lf %9.1lf\n", (double)ss->net.ipv6.Ip6InReceives / deltasec, (double)ss->net.ipv6.Ip6OutRequests / deltasec, (double)ss->net.ipv6.Ip6InMcastPkts / deltasec, (double)ss->net.ipv6.Ip6OutMcastPkts / deltasec, (double)ss->net.ipv6.Ip6InDelivers / deltasec, (double)ss->net.ipv6.Ip6ReasmOKs / deltasec, (double)ss->net.ipv6.Ip6FragCreates / deltasec); return 1; } static void IPv6head(int osvers, int osrel, int ossub) { printf("in: dsc/s hder/s ader/s unkp/s ratim/s rfail/s " "out: dsc/s nrt/s_ipv6_"); } static int IPv6line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { printf(" %5.1lf %6.1lf %6.1lf %6.1lf %7.1lf %7.1lf " " %5.1lf %5.1lf\n", (double)ss->net.ipv6.Ip6InDiscards / deltasec, (double)ss->net.ipv6.Ip6InHdrErrors / deltasec, (double)ss->net.ipv6.Ip6InAddrErrors / deltasec, (double)ss->net.ipv6.Ip6InUnknownProtos / deltasec, (double)ss->net.ipv6.Ip6ReasmTimeout / deltasec, (double)ss->net.ipv6.Ip6ReasmFails / deltasec, (double)ss->net.ipv6.Ip6OutDiscards / deltasec, (double)ss->net.ipv6.Ip6OutNoRoutes / deltasec); return 1; } /* ** ICMP version 6 statistics */ static void icmpv6head(int osvers, int osrel, int ossub) { printf("intot/s outtot/s inerr/s innsol/s innadv/s " "otnsol/s otnadv/s _icmp6_" ); } static int icmpv6line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { printf("%7.1lf %8.1lf %7.2lf %8.2lf %8.2lf %8.2lf %8.2lf\n", (double)ss->net.icmpv6.Icmp6InMsgs / deltasec, (double)ss->net.icmpv6.Icmp6OutMsgs / deltasec, (double)ss->net.icmpv6.Icmp6InErrors / deltasec, (double)ss->net.icmpv6.Icmp6InNeighborSolicits / deltasec, (double)ss->net.icmpv6.Icmp6InNeighborAdvertisements/ deltasec, (double)ss->net.icmpv6.Icmp6OutNeighborSolicits / deltasec, (double)ss->net.icmpv6.Icmp6OutNeighborAdvertisements /deltasec); return 1; } static void ICMPv6head(int osvers, int osrel, int ossub) { printf("iecho/s ierep/s oerep/s idu/s odu/s ird/s ord/s ite/s " "ote/s _icmpv6_"); } static int ICMPv6line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { printf("%7.2lf %7.2lf %7.2lf %5.2lf %5.2lf " "%5.2lf %5.2lf %5.2lf %5.2lf\n", (double)ss->net.icmpv6.Icmp6InEchos / deltasec, (double)ss->net.icmpv6.Icmp6InEchoReplies / deltasec, (double)ss->net.icmpv6.Icmp6OutEchoReplies / deltasec, (double)ss->net.icmpv6.Icmp6InDestUnreachs / deltasec, (double)ss->net.icmpv6.Icmp6OutDestUnreachs / deltasec, (double)ss->net.icmpv6.Icmp6InRedirects / deltasec, (double)ss->net.icmpv6.Icmp6OutRedirects / deltasec, (double)ss->net.icmpv6.Icmp6InTimeExcds / deltasec, (double)ss->net.icmpv6.Icmp6OutTimeExcds / deltasec); return 1; } /* ** UDP version 6 statistics */ static void udpv6head(int osvers, int osrel, int ossub) { printf("indgram/s outdgram/s inerr/s noport/s " " _udpv6_"); } static int udpv6line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { printf("%9.1lf %10.1lf %7.2lf %9.2lf\n", (double)ss->net.udpv6.Udp6InDatagrams / deltasec, (double)ss->net.udpv6.Udp6OutDatagrams / deltasec, (double)ss->net.udpv6.Udp6InErrors / deltasec, (double)ss->net.udpv6.Udp6NoPorts / deltasec); return 1; } /* ** TCP statistics */ static void tcphead(int osvers, int osrel, int ossub) { printf("insegs/s outsegs/s actopen/s pasopen/s " "nowopen _tcp_"); } static int tcpline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { printf("%8.1lf %9.1lf %9.1lf %9.1lf %7lld\n", (double)ss->net.tcp.InSegs / deltasec, (double)ss->net.tcp.OutSegs / deltasec, (double)ss->net.tcp.ActiveOpens / deltasec, (double)ss->net.tcp.PassiveOpens / deltasec, ss->net.tcp.CurrEstab); return 1; } static void TCPhead(int osvers, int osrel, int ossub) { printf("inerr/s retrans/s attfail/s " "estabreset/s outreset/s _tcp_"); } static int TCPline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { printf("%7.1lf %9.1lf %9.1lf %12.1lf %10.1lf\n", (double)ss->net.tcp.InErrs / deltasec, (double)ss->net.tcp.RetransSegs / deltasec, (double)ss->net.tcp.AttemptFails / deltasec, (double)ss->net.tcp.EstabResets / deltasec, (double)ss->net.tcp.OutRsts / deltasec); return 1; } #if HTTPSTATS static void httphead(int osvers, int osrel, int ossub) { printf("requests/s Kbytes/s bytes/req " "idleworkers busyworkers _http_"); } static int httpline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { printf("%10.2lf %8.2lf %9.2lf %11d %11d\n", (double)ss->www.accesses / deltasec, (double)ss->www.totkbytes / deltasec, ss->www.accesses ? (double)ss->www.totkbytes*1024/ss->www.accesses : 0, ss->www.iworkers, ss->www.bworkers); return 1; } #endif /* ** per-process statistics: top-3 processor consumers */ static void topchead(int osvers, int osrel, int ossub) { printf(" pid command cpu%% | pid command cpu%% | " " pid command cpu%%_top3_"); } static int topcline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { count_t availcpu; if (!ts) { printf("report not available.....\n"); return 0; } /* ** sort process list in cpu order */ qsort(ps, nactproc, sizeof(struct tstat *), compcpu); availcpu = ss->cpu.all.stime + ss->cpu.all.utime + ss->cpu.all.ntime + ss->cpu.all.itime + ss->cpu.all.wtime + ss->cpu.all.Itime + ss->cpu.all.Stime + ss->cpu.all.steal; availcpu /= ss->cpu.nrcpu; if (availcpu == 0) availcpu = 1; /* avoid divide-by-zero */ if (nactproc >= 1 && (ps[0])->cpu.stime + (ps[0])->cpu.utime > 0) printf("%5d %-8.8s %3.0lf%% | ", (ps[0])->gen.pid, (ps[0])->gen.name, (double)((ps[0])->cpu.stime + (ps[0])->cpu.utime)*100.0/availcpu); else printf("%19s | ", " "); if (nactproc >= 2 && (ps[1])->cpu.stime + (ps[1])->cpu.utime > 0) printf("%5d %-8.8s %3.0lf%% | ", (ps[1])->gen.pid, (ps[1])->gen.name, (double)((ps[1])->cpu.stime + (ps[1])->cpu.utime)*100.0/availcpu); else printf("%19s | ", " "); if (nactproc >= 3 && (ps[2])->cpu.stime + (ps[2])->cpu.utime > 0) printf("%5d %-8.8s %3.0lf%%\n", (ps[2])->gen.pid, (ps[2])->gen.name, (double)((ps[2])->cpu.stime + (ps[2])->cpu.utime)*100.0/availcpu); else printf("%19s\n", " "); return 1; } /* ** per-process statistics: top-3 memory consumers */ static void topmhead(int osvers, int osrel, int ossub) { printf(" pid command mem%% | pid command mem%% | " " pid command mem%%_top3_"); } static int topmline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { count_t availmem; if (!ts) { printf("report not available.....\n"); return 0; } /* ** sort process list in memory order */ qsort(ps, nactproc, sizeof(struct tstat *), compmem); availmem = ss->mem.physmem * pagesize/1024; if (nactproc >= 1) printf("%5d %-8.8s %3.0lf%% | ", (ps[0])->gen.pid, (ps[0])->gen.name, (double)(ps[0])->mem.rmem * 100.0 / availmem); else printf("%19s | ", " "); if (nactproc >= 2) printf("%5d %-8.8s %3.0lf%% | ", (ps[1])->gen.pid, (ps[1])->gen.name, (double)(ps[1])->mem.rmem * 100.0 / availmem); else printf("%19s | ", " "); if (nactproc >= 3) printf("%5d %-8.8s %3.0lf%%\n", (ps[2])->gen.pid, (ps[2])->gen.name, (double)(ps[2])->mem.rmem * 100.0 / availmem); else printf("%19s\n", " "); return 1; } /* ** per-process statistics: top-3 disk consumers */ static void topdhead(int osvers, int osrel, int ossub) { printf(" pid command dsk%% | pid command dsk%% | " " pid command dsk%%_top3_"); } static int topdline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { int i; count_t availdsk; if (!ts) { printf("report not available.....\n"); return 0; } if ( !(supportflags & IOSTAT) ) { printf("no per-process disk counters available.....\n"); return 0; } /* ** determine total disk accesses for all processes */ for (i=0, availdsk=0; i < nactproc; i++) { availdsk += (ps[i])->dsk.rio + (ps[i])->dsk.wio; } if (availdsk == 0) availdsk = 1; /* ** sort process list in disk order */ qsort(ps, nactproc, sizeof(struct tstat *), compdsk); if (nactproc >= 1 && (ps[0])->dsk.rio + (ps[0])->dsk.wio > 0) printf("%5d %-8.8s %3.0lf%% | ", (ps[0])->gen.pid, (ps[0])->gen.name, (double)((ps[0])->dsk.rio+(ps[0])->dsk.wio) *100.0/availdsk); else printf("%19s | ", " "); if (nactproc >= 2 && (ps[1])->dsk.rio + (ps[1])->dsk.wio > 0) printf("%5d %-8.8s %3.0lf%% | ", (ps[1])->gen.pid, (ps[1])->gen.name, (double)((ps[1])->dsk.rio+(ps[1])->dsk.wio) *100.0/availdsk); else printf("%19s | ", " "); if (nactproc >= 3 && (ps[2])->dsk.rio + (ps[2])->dsk.wio > 0) printf("%5d %-8.8s %3.0lf%%\n", (ps[2])->gen.pid, (ps[2])->gen.name, (double)((ps[2])->dsk.rio+(ps[2])->dsk.wio) *100.0/availdsk); else printf("%19s\n", " "); return 1; } /* ** per-process statistics: top-3 network consumers */ static void topnhead(int osvers, int osrel, int ossub) { printf(" pid command net%% | pid command net%% | " " pid command net%%_top3_"); } static int topnline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, time_t deltasec, time_t deltatic, time_t hz, int osvers, int osrel, int ossub, char *tstamp, int ppres, int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie) { int i; count_t availnet; count_t totbytes; if (!ts) { printf("report not available.....\n"); return 0; } if ( !(supportflags & NETATOP) ) { printf("no per-process network counters available.....\n"); return 0; } /* ** determine total network accesses for all processes */ for (i=0, availnet=0; i < nactproc; i++) { availnet += (*(ps+i))->net.tcpssz + (*(ps+i))->net.tcprsz + (*(ps+i))->net.udpssz + (*(ps+i))->net.udprsz; } if (availnet == 0) availnet = 1; /* ** sort process list in network order */ qsort(ps, nactproc, sizeof(struct tstat *), compnet); if (nactproc >= 1) { totbytes = (ps[0])->net.tcpssz + (ps[0])->net.tcprsz + (ps[0])->net.udpssz + (ps[0])->net.udprsz; if (totbytes > 0) printf("%5d %-8.8s %3.0lf%% | ", (ps[0])->gen.pid, (ps[0])->gen.name, (double)totbytes * 100.0 / availnet); else printf("%19s | ", " "); } else printf("%19s | ", " "); if (nactproc >= 2) { totbytes = (ps[1])->net.tcpssz + (ps[1])->net.tcprsz + (ps[1])->net.udpssz + (ps[1])->net.udprsz; if (totbytes > 0) printf("%5d %-8.8s %3.0lf%% | ", (ps[1])->gen.pid, (ps[1])->gen.name, (double)totbytes * 100.0 / availnet); else printf("%19s | ", " "); } else printf("%19s | ", " "); if (nactproc >= 3) { totbytes = (ps[2])->net.tcpssz + (ps[2])->net.tcprsz + (ps[2])->net.udpssz + (ps[2])->net.udprsz; if (totbytes > 0) printf("%5d %-8.8s %3.0lf%%\n", (ps[2])->gen.pid, (ps[2])->gen.name, (double)totbytes * 100.0 / availnet); else printf("%19s\n", " "); } else printf("%19s\n", " "); return 1; } /*********************************************************************/ /* Function definition table. */ /* */ /* The layout of this table is as follows: */ /* Column 1: */ /* Boolean which indicates if the specified function is */ /* active during a run of 'atopsar'. When started, */ /* this boolean will be defined 'true' for all entries for */ /* which the command-line flag has been specified. Initially */ /* this column should contain 0 (false), unless this function */ /* is always required. */ /* If no flags are specified for 'atopsar', the first entry */ /* in this table is defined active (default flag). */ /* */ /* Column 2: */ /* Categories of counters used by this function. */ /* c = cpu counters, m = memory counters, */ /* d = disk counters, n = network counters */ /* */ /* Column 3: */ /* Flag which can be used as command-line argument to */ /* select the function defined in this table-entry. Be sure */ /* that a unique character is choosen. */ /* Notice that certain flags are reserved! */ /* */ /* Column 4: */ /* Entry-point of the 'printhead' function. */ /* */ /* Column 5: */ /* Entry-point of the 'printline' function. */ /* */ /* Column 6: */ /* Information about the statistics shown by the function */ /* specified by the table-entry. This text is printed as */ /* command-usage. */ /*********************************************************************/ struct pridef pridef[] = { {0, "c", 'c', cpuhead, cpuline, "cpu utilization", }, {0, "c", 'p', prochead, procline, "process(or) load", }, {0, "c", 'P', taskhead, taskline, "processes & threads", }, {0, "c", 'g', gpuhead, gpuline, "gpu utilization", }, {0, "m", 'm', memhead, memline, "memory & swapspace", }, {0, "m", 's', swaphead, swapline, "swap rate", }, {0, "cmd",'B', psihead, psiline, "pressure stall info (PSI)",}, {0, "cd", 'l', lvmhead, lvmline, "logical volume activity", }, {0, "cd", 'f', mddhead, mddline, "multiple device activity",}, {0, "cd", 'd', dskhead, dskline, "disk activity", }, {0, "n", 'h', ibhead, ibline, "infiniband utilization", }, {0, "n", 'n', nfmhead, nfmline, "NFS client mounts", }, {0, "n", 'j', nfchead, nfcline, "NFS client activity", }, {0, "n", 'J', nfshead, nfsline, "NFS server activity", }, {0, "n", 'i', ifhead, ifline, "net-interf (general)", }, {0, "n", 'I', IFhead, IFline, "net-interf (errors)", }, {0, "n", 'w', ipv4head, ipv4line, "ip v4 (general)", }, {0, "n", 'W', IPv4head, IPv4line, "ip v4 (errors)", }, {0, "n", 'y', icmpv4head, icmpv4line, "icmp v4 (general)", }, {0, "n", 'Y', ICMPv4head, ICMPv4line, "icmp v4 (per type)", }, {0, "n", 'u', udpv4head, udpv4line, "udp v4", }, {0, "n", 'z', ipv6head, ipv6line, "ip v6 (general)", }, {0, "n", 'Z', IPv6head, IPv6line, "ip v6 (errors)", }, {0, "n", 'k', icmpv6head, icmpv6line, "icmp v6 (general)", }, {0, "n", 'K', ICMPv6head, ICMPv6line, "icmp v6 (per type)", }, {0, "n", 'U', udpv6head, udpv6line, "udp v6", }, {0, "n", 't', tcphead, tcpline, "tcp (general)", }, {0, "n", 'T', TCPhead, TCPline, "tcp (errors)", }, #if HTTPSTATS {0, "n", 'h', httphead, httpline, "HTTP activity", }, #endif {0, "", 'O', topchead, topcline, "top-3 processes cpu", }, {0, "", 'G', topmhead, topmline, "top-3 processes memory", }, {0, "", 'D', topdhead, topdline, "top-3 processes disk", }, {0, "", 'N', topnhead, topnline, "top-3 processes network",}, }; int pricnt = sizeof(pridef)/sizeof(struct pridef); atop-2.4.0/deviate.c0000664000203100020310000015377613416466037013604 0ustar gerlofgerlof/* ** 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 functions to calculate the differences for ** the system-level and process-level counters since the previous sample. ** ========================================================================== ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Date: November 1996 ** LINUX-port: June 2000 ** -------------------------------------------------------------------------- ** Copyright (C) 2000-2010 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 ** -------------------------------------------------------------------------- ** ** $Log: deviate.c,v $ ** Revision 1.45 2010/10/23 14:02:03 gerlof ** Show counters for total number of running and sleep (S and D) threads. ** ** Revision 1.44 2010/05/18 19:19:43 gerlof ** Introduce CPU frequency and scaling (JC van Winkel). ** ** Revision 1.43 2010/04/23 12:19:35 gerlof ** Modified mail-address in header. ** ** Revision 1.42 2010/03/04 10:52:08 gerlof ** Support I/O-statistics on logical volumes and MD devices. ** ** Revision 1.41 2009/12/31 11:34:21 gerlof ** Sanity-check to bypass kernel-bug showing 497 days of CPU-consumption. ** ** Revision 1.40 2009/12/17 11:58:25 gerlof ** Gather and display new counters: dirty cache and guest cpu usage. ** ** Revision 1.39 2008/02/25 14:51:18 gerlof ** Experimental code for HTTP-statistics. ** ** Revision 1.38 2008/01/07 11:33:43 gerlof ** Cosmetic changes. ** ** Revision 1.37 2008/01/07 10:17:24 gerlof ** Implement possibility to make summaries. ** ** Revision 1.36 2007/11/05 12:13:16 gerlof ** Match processes not only on pid, but also on start time. ** ** Revision 1.35 2007/11/05 11:42:47 gerlof ** Bug-solution for new-process indicator on 64-bits machines. ** ** Revision 1.34 2007/08/17 09:44:59 gerlof ** Experimental: gather info about HTTP statistics. ** ** Revision 1.33 2007/08/16 11:59:32 gerlof ** Add support for atopsar reporting. ** Concerns addition of lots of counters. ** ** Revision 1.32 2007/07/03 09:01:07 gerlof ** Support Apache-statistics. ** ** Revision 1.31 2007/03/20 13:02:03 gerlof ** Introduction of variable supportflags. ** ** Revision 1.30 2007/03/20 11:18:57 gerlof ** Add counter for cancelled writes. ** ** Revision 1.29 2007/02/13 09:21:04 gerlof ** Removed external declarations. ** ** Revision 1.28 2007/01/22 08:28:18 gerlof ** Support steal-time from /proc/stat. ** ** Revision 1.27 2007/01/18 10:43:18 gerlof ** Support for network-interface busy-percentage (speed and duplex). ** ** Revision 1.26 2006/11/13 13:47:26 gerlof ** Implement load-average counters, context-switches and interrupts. ** ** Revision 1.25 2006/02/07 06:45:33 gerlof ** Removed swap-counter. ** ** Revision 1.24 2006/01/30 09:13:33 gerlof ** Extend memory counters (a.o. page scans). ** ** Revision 1.23 2005/10/31 12:45:29 gerlof ** Support account-record version 3 (used by Mandriva). ** ** Revision 1.22 2005/10/21 09:49:38 gerlof ** Per-user accumulation of resource consumption. ** ** Revision 1.21 2004/12/14 15:05:47 gerlof ** Implementation of patch-recognition for disk and network-statistics. ** ** Revision 1.20 2004/10/28 08:30:51 gerlof ** New counter: vm committed space ** ** Revision 1.19 2004/09/24 10:02:01 gerlof ** Wrong cpu-numbers for system level statistics. ** ** Revision 1.18 2004/09/02 10:49:18 gerlof ** Added sleep-average to process-info. ** ** Revision 1.17 2004/08/31 13:27:04 gerlof ** Add new info for threading. ** ** Revision 1.16 2004/05/07 05:49:40 gerlof ** *** empty log message *** ** ** Revision 1.15 2004/05/06 09:46:55 gerlof ** Ported to kernel-version 2.6. ** ** Revision 1.14 2003/07/07 09:26:33 gerlof ** Cleanup code (-Wall proof). ** ** Revision 1.13 2003/07/03 11:17:49 gerlof ** Corrected calculations for exited processes. ** ** Revision 1.12 2003/06/30 11:30:57 gerlof ** Enlarge counters to 'long long'. ** ** Revision 1.11 2003/06/24 06:21:12 gerlof ** Limit number of system resource lines. ** ** Revision 1.10 2003/01/24 14:20:16 gerlof ** If possible, also show commandline when process has exited. ** ** Revision 1.9 2002/09/16 08:58:08 gerlof ** Add indicator for newly created processes. ** ** Revision 1.8 2002/08/27 04:47:46 gerlof ** Minor comment updates. ** ** Revision 1.7 2002/07/24 11:12:20 gerlof ** Redesigned to ease porting to other UNIX-platforms. ** ** Revision 1.6 2002/07/10 04:59:37 root ** Counters pin/pout renamed to swin/swout (Linux conventions). ** ** Revision 1.5 2002/01/22 13:39:20 gerlof ** Support for number of cpu's. ** ** Revision 1.4 2001/11/22 08:33:10 gerlof ** Add priority per process. ** ** Revision 1.3 2001/11/07 09:18:22 gerlof ** Use /proc instead of /dev/kmem for process-level statistics. ** ** Revision 1.2 2001/10/03 08:58:41 gerlof ** Improved subtraction which is overflow-proof ** ** Revision 1.1 2001/10/02 10:43:23 gerlof ** Initial revision ** */ static const char rcsid[] = "$Id: deviate.c,v 1.45 2010/10/23 14:02:03 gerlof Exp $"; #include #include #include #include #include #include #include #include #include #include #include #include #include #include "atop.h" #include "ifprop.h" #include "photoproc.h" #include "photosyst.h" #define MAX32BITVAL 0x100000000LL static void calcdiff(struct tstat *, struct tstat *, struct tstat *, char, count_t); /* ** calculate the process-activity during the last sample */ void deviattask(struct tstat *curtpres, unsigned long ntaskpres, struct tstat *curpexit, unsigned long nprocexit, struct devtstat *devtstat, struct sstat *devsstat) { register int c, d, pall=0, pact=0; register struct tstat *curstat, *devstat, *thisproc; struct tstat prestat; struct pinfo *pinfo; count_t totusedcpu; char hashtype = 'p'; /* ** needed for sanity check later on... */ totusedcpu = devsstat->cpu.all.stime + devsstat->cpu.all.utime + devsstat->cpu.all.ntime + devsstat->cpu.all.itime + devsstat->cpu.all.wtime + devsstat->cpu.all.Itime + devsstat->cpu.all.Stime + devsstat->cpu.all.steal; /* ** make new list of all tasks in the task-database; ** after handling all task, the left-overs are tasks ** that have disappeared since the previous sample */ pdb_makeresidue(); /* ** remove allocated lists of previous sample and initialize counters */ if (devtstat->taskall) free(devtstat->taskall); if (devtstat->procall) free(devtstat->procall); if (devtstat->procactive) free(devtstat->procactive); memset(devtstat, 0, sizeof *devtstat); /* ** create list for the sample deviations of all tasks */ devtstat->ntaskall = ntaskpres + nprocexit; devtstat->taskall = malloc(devtstat->ntaskall * sizeof(struct tstat)); ptrverify(devtstat->taskall, "Malloc failed for %lu deviated tasks\n", devtstat->ntaskall); /* ** calculate deviations per present task */ for (c=0, thisproc = devtstat->taskall; c < ntaskpres; c++) { char newtask = 0; curstat = curtpres+c; devstat = devtstat->taskall+c; if (curstat->gen.isproc) { thisproc = devstat; // remember last process seen devtstat->nprocall++; if (curstat->gen.state == 'Z') { devtstat->totzombie++; } else { devtstat->totrun += curstat->gen.nthrrun; devtstat->totslpi += curstat->gen.nthrslpi; devtstat->totslpu += curstat->gen.nthrslpu; } } /* ** get previous figures from task-database */ if ( pdb_gettask(curstat->gen.pid, curstat->gen.isproc, curstat->gen.btime, &pinfo)) { /* ** task already present in the previous sample ** ** save stats from previous sample (to use for ** further calculations) and store new statistics ** in task-database */ if (memcmp(curstat, &pinfo->tstat, sizeof(struct tstat)) == EQ) { /* ** no activity for task */ curstat->gen.wasinactive = 1; } else { /* ** save the values of the previous sample ** and overwrite the previous sample in ** the database with the current sample */ prestat = pinfo->tstat; pinfo->tstat = *curstat; curstat->gen.wasinactive = 0; devtstat->ntaskactive++; if (curstat->gen.isproc) { devtstat->nprocactive++; } else { if (thisproc->gen.wasinactive) { thisproc->gen.wasinactive = 0; devtstat->ntaskactive++; devtstat->nprocactive++; } } } } else { /* ** new task which must have been started during ** last interval */ memset(&prestat, 0, sizeof(prestat)); curstat->gen.wasinactive = 0; devtstat->ntaskactive++; if (curstat->gen.isproc) { devtstat->nprocactive++; } else { if (thisproc->gen.wasinactive) { thisproc->gen.wasinactive = 0; devtstat->ntaskactive++; devtstat->nprocactive++; } } /* ** create new task struct */ pinfo = calloc(1, sizeof(struct pinfo)); ptrverify(pinfo, "Malloc failed for new pinfo\n"); pinfo->tstat = *curstat; /* ** add new task to task-database */ pdb_addtask(curstat->gen.pid, pinfo); newtask = 1; } /* ** do the difference calculations */ calcdiff(devstat, curstat, &prestat, newtask, totusedcpu); } /* ** calculate deviations per exited process */ if (nprocexit > 0 && supportflags&NETATOPD) { if (curpexit->gen.pid) hashtype = 'p'; else hashtype = 'b'; netatop_exithash(hashtype); } for (d=c, c=0; c < nprocexit; c++) { /* ** check if this process has been started AND ** finished since previous sample; ** if so, it has no use to check if there is still ** existing info present in the process-database */ curstat = curpexit+c; curstat->gen.wasinactive = 0; devtstat->nprocall++; devtstat->nprocactive++; devtstat->ntaskactive++; if (curstat->gen.pid) /* acctrecord contains pid? */ { if ( pdb_gettask(curstat->gen.pid, 1, curstat->gen.btime, &pinfo)) prestat = pinfo->tstat; else memset(&prestat, 0, sizeof(prestat)); } else { if ( curstat->gen.btime > pretime ) { /* ** process-start and -finish in same interval */ memset(&prestat, 0, sizeof(prestat)); } else { /* ** process must be known in process-database; ** try to match one of the remaining processes ** against this exited one */ if ( pdb_srchresidue(curstat, &pinfo) ) prestat = pinfo->tstat; else memset(&prestat, 0, sizeof(prestat)); } } /* ** now do the calculations */ devstat = devtstat->taskall+d; memset(devstat, 0, sizeof *devstat); devstat->gen = curstat->gen; if ( curstat->gen.pid == 0 ) devstat->gen.pid = prestat.gen.pid; if (!prestat.gen.pid) devstat->gen.excode |= ~(INT_MAX); strcpy(devstat->gen.cmdline, prestat.gen.cmdline); /* ** due to the strange exponent-type storage of values ** in the process accounting record, the resource-value ** in the exit-record might have been smaller than the ** stored value of the last registered sample; in that ** case the deviation should be set to zero */ if (curstat->cpu.stime > prestat.cpu.stime) devstat->cpu.stime = curstat->cpu.stime - prestat.cpu.stime; if (curstat->cpu.utime > prestat.cpu.utime) devstat->cpu.utime = curstat->cpu.utime - prestat.cpu.utime; if (curstat->mem.minflt > prestat.mem.minflt) devstat->mem.minflt = curstat->mem.minflt - prestat.mem.minflt; if (curstat->mem.majflt > prestat.mem.majflt) devstat->mem.majflt = curstat->mem.majflt - prestat.mem.majflt; if (curstat->dsk.rio > (prestat.dsk.rio + prestat.dsk.wio)) devstat->dsk.rio = curstat->dsk.rio - prestat.dsk.rio - prestat.dsk.wio; /* ** try to match the network counters of netatop */ if (supportflags & NETATOPD) { unsigned long val = (hashtype == 'p' ? curstat->gen.pid : curstat->gen.btime); netatop_exitfind(val, devstat, &prestat); } /* ** handle the gpu counters */ if (curstat->gpu.state || prestat.gpu.state) // GPU use? { if (curstat->gpu.state) devstat->gpu.state = curstat->gpu.state; else devstat->gpu.state = prestat.gpu.state; devstat->gpu.nrgpus = curstat->gpu.nrgpus; devstat->gpu.gpulist = curstat->gpu.gpulist; devstat->gpu.gpubusy = curstat->gpu.gpubusy; devstat->gpu.membusy = curstat->gpu.membusy; devstat->gpu.timems = curstat->gpu.timems; devstat->gpu.memnow = curstat->gpu.memnow; devstat->gpu.memcum = curstat->gpu.memcum - prestat.gpu.memcum; devstat->gpu.sample = curstat->gpu.sample - prestat.gpu.sample; } else { devstat->gpu.state = '\0'; } if (prestat.gen.pid > 0) pdb_deltask(prestat.gen.pid, prestat.gen.isproc); d++; } /* ** remove unused entries from RESIDUE chain */ pdb_cleanresidue(); /* ** create and fill other pointer lists */ devtstat->procall = malloc(devtstat->nprocall * sizeof(struct tstat *)); devtstat->procactive = malloc(devtstat->nprocactive * sizeof(struct tstat *)); ptrverify(devtstat->procall, "Malloc failed for %d processes\n", devtstat->nprocall); ptrverify(devtstat->procactive, "Malloc failed for %d active procs\n", devtstat->nprocactive); for (c=0, thisproc=devstat=devtstat->taskall; c < devtstat->ntaskall; c++, devstat++) { if (devstat->gen.isproc) { devtstat->procall[pall++] = devstat; if (! devstat->gen.wasinactive) devtstat->procactive[pact++] = devstat; } } } /* ** calculate the differences between the current sample and ** the previous sample for a task */ static void calcdiff(struct tstat *devstat, struct tstat *curstat, struct tstat *prestat, char newtask, count_t totusedcpu) { /* ** for inactive tasks, set all counters to zero */ if (curstat->gen.wasinactive) memset(devstat, 0, sizeof *devstat); /* ** copy all static values from the current task settings */ devstat->gen = curstat->gen; if (newtask) devstat->gen.excode |= ~(INT_MAX); devstat->cpu.nice = curstat->cpu.nice; devstat->cpu.prio = curstat->cpu.prio; devstat->cpu.rtprio = curstat->cpu.rtprio; devstat->cpu.policy = curstat->cpu.policy; devstat->cpu.curcpu = curstat->cpu.curcpu; devstat->cpu.sleepavg = curstat->cpu.sleepavg; devstat->mem.vexec = curstat->mem.vexec; devstat->mem.vmem = curstat->mem.vmem; devstat->mem.rmem = curstat->mem.rmem; devstat->mem.pmem = curstat->mem.pmem; devstat->mem.vdata = curstat->mem.vdata; devstat->mem.vstack = curstat->mem.vstack; devstat->mem.vlibs = curstat->mem.vlibs; devstat->mem.vswap = curstat->mem.vswap; if (curstat->gpu.state || prestat->gpu.state) // GPU use? { if (curstat->gpu.state) devstat->gpu.state = curstat->gpu.state; else devstat->gpu.state = prestat->gpu.state; devstat->gpu.nrgpus = curstat->gpu.nrgpus; devstat->gpu.gpulist = curstat->gpu.gpulist; devstat->gpu.gpubusy = curstat->gpu.gpubusy; devstat->gpu.membusy = curstat->gpu.membusy; devstat->gpu.memnow = curstat->gpu.memnow; devstat->gpu.timems = curstat->gpu.timems; } else { devstat->gpu.state = '\0'; } /* ** for inactive tasks, only the static values had to be copied, while ** all use counters have been set to zero */ if (curstat->gen.wasinactive) return; devstat->cpu.stime = subcount(curstat->cpu.stime, prestat->cpu.stime); devstat->cpu.utime = subcount(curstat->cpu.utime, prestat->cpu.utime); /* ** particular kernel versions sometimes supply a smaller ** amount for consumed CPU-ticks than a previous sample; ** with unsigned calculations this results in 497 days of ** CPU-consumption so a sanity-check is needed here... */ if (devstat->cpu.stime > totusedcpu) devstat->cpu.stime = 1; if (devstat->cpu.utime > totusedcpu) devstat->cpu.utime = 1; /* ** do further calculations */ devstat->dsk.rio = subcount(curstat->dsk.rio, prestat->dsk.rio); devstat->dsk.rsz = subcount(curstat->dsk.rsz, prestat->dsk.rsz); devstat->dsk.wio = subcount(curstat->dsk.wio, prestat->dsk.wio); devstat->dsk.wsz = subcount(curstat->dsk.wsz, prestat->dsk.wsz); devstat->dsk.cwsz = subcount(curstat->dsk.cwsz, prestat->dsk.cwsz); devstat->mem.vgrow = curstat->mem.vmem - prestat->mem.vmem; devstat->mem.rgrow = curstat->mem.rmem - prestat->mem.rmem; devstat->mem.minflt = subcount(curstat->mem.minflt, prestat->mem.minflt); devstat->mem.majflt = subcount(curstat->mem.majflt, prestat->mem.majflt); /* ** network counters: due to an unload/load of the netatop module, ** previous counters might be larger than the current */ if (curstat->net.tcpsnd >= prestat->net.tcpsnd) devstat->net.tcpsnd = subcount(curstat->net.tcpsnd, prestat->net.tcpsnd); else devstat->net.tcpsnd = curstat->net.tcpsnd; if (curstat->net.tcpssz >= prestat->net.tcpssz) devstat->net.tcpssz = subcount(curstat->net.tcpssz, prestat->net.tcpssz); else devstat->net.tcpssz = curstat->net.tcpssz; if (curstat->net.tcprcv >= prestat->net.tcprcv) devstat->net.tcprcv = subcount(curstat->net.tcprcv, prestat->net.tcprcv); else devstat->net.tcprcv = curstat->net.tcprcv; if (curstat->net.tcprsz >= prestat->net.tcprsz) devstat->net.tcprsz = subcount(curstat->net.tcprsz, prestat->net.tcprsz); else devstat->net.tcprsz = curstat->net.tcprsz; if (curstat->net.udpsnd >= prestat->net.udpsnd) devstat->net.udpsnd = subcount(curstat->net.udpsnd, prestat->net.udpsnd); else devstat->net.udpsnd = curstat->net.udpsnd; if (curstat->net.udpssz >= prestat->net.udpssz) devstat->net.udpssz = subcount(curstat->net.udpssz, prestat->net.udpssz); else devstat->net.udpssz = curstat->net.udpssz; if (curstat->net.udprcv >= prestat->net.udprcv) devstat->net.udprcv = subcount(curstat->net.udprcv, prestat->net.udprcv); else devstat->net.udprcv = curstat->net.udprcv; if (curstat->net.udprsz >= prestat->net.udprsz) devstat->net.udprsz = subcount(curstat->net.udprsz, prestat->net.udprsz); else devstat->net.udprsz = curstat->net.udprsz; if (curstat->gpu.state) { devstat->gpu.memcum = curstat->gpu.memcum - prestat->gpu.memcum; devstat->gpu.sample = curstat->gpu.sample - prestat->gpu.sample; } } /* ** calculate the system-activity during the last sample */ void deviatsyst(struct sstat *cur, struct sstat *pre, struct sstat *dev, long interval) { register int i, j; count_t *cdev, *ccur, *cpre; struct ifprop ifprop; dev->cpu.nrcpu = cur->cpu.nrcpu; dev->cpu.devint = subcount(cur->cpu.devint, pre->cpu.devint); dev->cpu.csw = subcount(cur->cpu.csw, pre->cpu.csw); dev->cpu.nprocs = subcount(cur->cpu.nprocs, pre->cpu.nprocs); dev->cpu.all.stime = subcount(cur->cpu.all.stime, pre->cpu.all.stime); dev->cpu.all.utime = subcount(cur->cpu.all.utime, pre->cpu.all.utime); dev->cpu.all.ntime = subcount(cur->cpu.all.ntime, pre->cpu.all.ntime); dev->cpu.all.itime = subcount(cur->cpu.all.itime, pre->cpu.all.itime); dev->cpu.all.wtime = subcount(cur->cpu.all.wtime, pre->cpu.all.wtime); dev->cpu.all.Itime = subcount(cur->cpu.all.Itime, pre->cpu.all.Itime); dev->cpu.all.Stime = subcount(cur->cpu.all.Stime, pre->cpu.all.Stime); dev->cpu.all.steal = subcount(cur->cpu.all.steal, pre->cpu.all.steal); dev->cpu.all.guest = subcount(cur->cpu.all.guest, pre->cpu.all.guest); dev->cpu.all.instr = subcount(cur->cpu.all.instr, pre->cpu.all.instr); dev->cpu.all.cycle = subcount(cur->cpu.all.cycle, pre->cpu.all.cycle); for (i=0; i < dev->cpu.nrcpu; i++) { count_t ticks; dev->cpu.cpu[i].cpunr = cur->cpu.cpu[i].cpunr; dev->cpu.cpu[i].stime = subcount(cur->cpu.cpu[i].stime, pre->cpu.cpu[i].stime); dev->cpu.cpu[i].utime = subcount(cur->cpu.cpu[i].utime, pre->cpu.cpu[i].utime); dev->cpu.cpu[i].ntime = subcount(cur->cpu.cpu[i].ntime, pre->cpu.cpu[i].ntime); dev->cpu.cpu[i].itime = subcount(cur->cpu.cpu[i].itime, pre->cpu.cpu[i].itime); dev->cpu.cpu[i].wtime = subcount(cur->cpu.cpu[i].wtime, pre->cpu.cpu[i].wtime); dev->cpu.cpu[i].Itime = subcount(cur->cpu.cpu[i].Itime, pre->cpu.cpu[i].Itime); dev->cpu.cpu[i].Stime = subcount(cur->cpu.cpu[i].Stime, pre->cpu.cpu[i].Stime); dev->cpu.cpu[i].steal = subcount(cur->cpu.cpu[i].steal, pre->cpu.cpu[i].steal); dev->cpu.cpu[i].guest = subcount(cur->cpu.cpu[i].guest, pre->cpu.cpu[i].guest); dev->cpu.cpu[i].instr = subcount(cur->cpu.cpu[i].instr, pre->cpu.cpu[i].instr); dev->cpu.cpu[i].cycle = subcount(cur->cpu.cpu[i].cycle, pre->cpu.cpu[i].cycle); ticks = cur->cpu.cpu[i].freqcnt.ticks; dev->cpu.cpu[i].freqcnt.maxfreq = cur->cpu.cpu[i].freqcnt.maxfreq; dev->cpu.cpu[i].freqcnt.cnt = ticks ? subcount(cur->cpu.cpu[i].freqcnt.cnt, pre->cpu.cpu[i].freqcnt.cnt) : cur->cpu.cpu[i].freqcnt.cnt; dev->cpu.cpu[i].freqcnt.ticks = ticks ? subcount(cur->cpu.cpu[i].freqcnt.ticks, pre->cpu.cpu[i].freqcnt.ticks) : cur->cpu.cpu[i].freqcnt.ticks; } dev->cpu.lavg1 = cur->cpu.lavg1; dev->cpu.lavg5 = cur->cpu.lavg5; dev->cpu.lavg15 = cur->cpu.lavg15; dev->mem.physmem = cur->mem.physmem; dev->mem.freemem = cur->mem.freemem; dev->mem.buffermem = cur->mem.buffermem; dev->mem.slabmem = cur->mem.slabmem; dev->mem.slabreclaim = cur->mem.slabreclaim; dev->mem.committed = cur->mem.committed; dev->mem.commitlim = cur->mem.commitlim; dev->mem.cachemem = cur->mem.cachemem; dev->mem.cachedrt = cur->mem.cachedrt; dev->mem.totswap = cur->mem.totswap; dev->mem.freeswap = cur->mem.freeswap; dev->mem.shmem = cur->mem.shmem; dev->mem.shmrss = cur->mem.shmrss; dev->mem.shmswp = cur->mem.shmswp; dev->mem.tothugepage = cur->mem.tothugepage; dev->mem.freehugepage = cur->mem.freehugepage; dev->mem.hugepagesz = cur->mem.hugepagesz; dev->mem.vmwballoon = cur->mem.vmwballoon; dev->mem.swouts = subcount(cur->mem.swouts, pre->mem.swouts); dev->mem.swins = subcount(cur->mem.swins, pre->mem.swins); dev->mem.pgscans = subcount(cur->mem.pgscans, pre->mem.pgscans); dev->mem.pgsteal = subcount(cur->mem.pgsteal, pre->mem.pgsteal); dev->mem.allocstall = subcount(cur->mem.allocstall, pre->mem.allocstall); dev->psi = cur->psi; if (cur->psi.present) { dev->psi.cpusome.total = cur->psi.cpusome.total - pre->psi.cpusome.total; dev->psi.memsome.total = cur->psi.memsome.total - pre->psi.memsome.total; dev->psi.memfull.total = cur->psi.memfull.total - pre->psi.memfull.total; dev->psi.iosome.total = cur->psi.iosome.total - pre->psi.iosome.total; dev->psi.iofull.total = cur->psi.iofull.total - pre->psi.iofull.total; } /* ** structures with network-related counters are considered ** as tables of frequency-counters that have to be subtracted; ** values that do not represent a frequency are corrected afterwards */ for (cdev = (count_t *)&dev->net.ipv4, ccur = (count_t *)&cur->net.ipv4, cpre = (count_t *)&pre->net.ipv4, i = 0; i < (sizeof dev->net.ipv4 / sizeof(count_t)); cdev++, ccur++, cpre++, i++) *cdev = *ccur - *cpre; dev->net.ipv4.Forwarding = cur->net.ipv4.Forwarding; dev->net.ipv4.DefaultTTL = cur->net.ipv4.DefaultTTL; /* ------------- */ for (cdev = (count_t *)&dev->net.icmpv4, ccur = (count_t *)&cur->net.icmpv4, cpre = (count_t *)&pre->net.icmpv4, i = 0; i < (sizeof dev->net.icmpv4 / sizeof(count_t)); cdev++, ccur++, cpre++, i++) *cdev = *ccur - *cpre; /* ------------- */ for (cdev = (count_t *)&dev->net.udpv4, ccur = (count_t *)&cur->net.udpv4, cpre = (count_t *)&pre->net.udpv4, i = 0; i < (sizeof dev->net.udpv4 / sizeof(count_t)); cdev++, ccur++, cpre++, i++) *cdev = *ccur - *cpre; /* ------------- */ for (cdev = (count_t *)&dev->net.ipv6, ccur = (count_t *)&cur->net.ipv6, cpre = (count_t *)&pre->net.ipv6, i = 0; i < (sizeof dev->net.ipv6 / sizeof(count_t)); cdev++, ccur++, cpre++, i++) *cdev = *ccur - *cpre; /* ------------- */ for (cdev = (count_t *)&dev->net.icmpv6, ccur = (count_t *)&cur->net.icmpv6, cpre = (count_t *)&pre->net.icmpv6, i = 0; i < (sizeof dev->net.icmpv6 / sizeof(count_t)); cdev++, ccur++, cpre++, i++) *cdev = *ccur - *cpre; /* ------------- */ for (cdev = (count_t *)&dev->net.udpv6, ccur = (count_t *)&cur->net.udpv6, cpre = (count_t *)&pre->net.udpv6, i = 0; i < (sizeof dev->net.udpv6 / sizeof(count_t)); cdev++, ccur++, cpre++, i++) *cdev = *ccur - *cpre; /* ------------- */ for (cdev = (count_t *)&dev->net.tcp, ccur = (count_t *)&cur->net.tcp, cpre = (count_t *)&pre->net.tcp, i = 0; i < (sizeof dev->net.tcp / sizeof(count_t)); cdev++, ccur++, cpre++, i++) *cdev = *ccur - *cpre; dev->net.tcp.RtoAlgorithm = cur->net.tcp.RtoAlgorithm; dev->net.tcp.RtoMin = cur->net.tcp.RtoMin; dev->net.tcp.RtoMax = cur->net.tcp.RtoMax; dev->net.tcp.MaxConn = cur->net.tcp.MaxConn; dev->net.tcp.CurrEstab = cur->net.tcp.CurrEstab; /* ** calculate deviations for interfaces ** ** refresh all interface properties */ regainrootprivs(); /* get root privileges */ initifprop(); /* refresh interface info */ if (! droprootprivs()) /* drop setuid-root privs */ cleanstop(42); for (i=0; cur->intf.intf[i].name[0]; i++) { strcpy(ifprop.name, cur->intf.intf[i].name); getifprop(&ifprop); cur->intf.intf[i].type = ifprop.type; cur->intf.intf[i].speed = ifprop.speed; cur->intf.intf[i].speedp = ifprop.speed; cur->intf.intf[i].duplex = ifprop.fullduplex; } if (pre->intf.intf[0].name[0] == '\0') /* first sample? */ { for (i=0; cur->intf.intf[i].name[0]; i++) { strcpy(pre->intf.intf[i].name, cur->intf.intf[i].name); pre->intf.intf[i].type = cur->intf.intf[i].type; pre->intf.intf[i].speed = cur->intf.intf[i].speed; pre->intf.intf[i].speedp = cur->intf.intf[i].speedp; pre->intf.intf[i].duplex = cur->intf.intf[i].duplex; } } for (i=0, j=0; cur->intf.intf[i].name[0]; i++, j++) { /* ** be sure that we have the same interface ** (interfaces could have been added or removed since ** previous sample) */ if (strcmp(cur->intf.intf[i].name, pre->intf.intf[j].name) != 0) { // try to resync for (j=0; pre->intf.intf[j].name[0]; j++) { if (strcmp(cur->intf.intf[i].name, pre->intf.intf[j].name) == 0) break; } // resync not succeeded? if (! pre->intf.intf[j].name[0]) { memcpy(&dev->intf.intf[i], &cur->intf.intf[i], sizeof cur->intf.intf[i]); j = 0; continue; } } /* ** calculate interface deviations for this sample */ strcpy(dev->intf.intf[i].name, cur->intf.intf[i].name); dev->intf.intf[i].rbyte = subcount(cur->intf.intf[i].rbyte, pre->intf.intf[j].rbyte); dev->intf.intf[i].rpack = subcount(cur->intf.intf[i].rpack, pre->intf.intf[j].rpack); dev->intf.intf[i].rerrs = subcount(cur->intf.intf[i].rerrs, pre->intf.intf[j].rerrs); dev->intf.intf[i].rdrop = subcount(cur->intf.intf[i].rdrop, pre->intf.intf[j].rdrop); dev->intf.intf[i].rfifo = subcount(cur->intf.intf[i].rfifo, pre->intf.intf[j].rfifo); dev->intf.intf[i].rframe= subcount(cur->intf.intf[i].rframe, pre->intf.intf[j].rframe); dev->intf.intf[i].rcompr= subcount(cur->intf.intf[i].rcompr, pre->intf.intf[j].rcompr); dev->intf.intf[i].rmultic=subcount(cur->intf.intf[i].rmultic, pre->intf.intf[j].rmultic); dev->intf.intf[i].sbyte = subcount(cur->intf.intf[i].sbyte, pre->intf.intf[j].sbyte); dev->intf.intf[i].spack = subcount(cur->intf.intf[i].spack, pre->intf.intf[j].spack); dev->intf.intf[i].serrs = subcount(cur->intf.intf[i].serrs, pre->intf.intf[j].serrs); dev->intf.intf[i].sdrop = subcount(cur->intf.intf[i].sdrop, pre->intf.intf[j].sdrop); dev->intf.intf[i].sfifo = subcount(cur->intf.intf[i].sfifo, pre->intf.intf[j].sfifo); dev->intf.intf[i].scollis= subcount(cur->intf.intf[i].scollis, pre->intf.intf[j].scollis); dev->intf.intf[i].scarrier= subcount(cur->intf.intf[i].scarrier, pre->intf.intf[j].scarrier); dev->intf.intf[i].scompr= subcount(cur->intf.intf[i].scompr, pre->intf.intf[j].scompr); dev->intf.intf[i].type = cur->intf.intf[i].type; dev->intf.intf[i].duplex = cur->intf.intf[i].duplex; dev->intf.intf[i].speed = cur->intf.intf[i].speed; dev->intf.intf[i].speedp = pre->intf.intf[j].speed; cur->intf.intf[i].speedp = pre->intf.intf[j].speed; } dev->intf.intf[i].name[0] = '\0'; dev->intf.nrintf = i; /* ** calculate deviations for disks */ for (i=j=0; cur->dsk.dsk[i].name[0]; i++) { int realj = j; /* ** check if disk has been added or removed since ** previous interval */ if ( strcmp(cur->dsk.dsk[i].name, pre->dsk.dsk[j].name) != 0) { for (j++; pre->dsk.dsk[j].name[0]; j++) { if ( strcmp(cur->dsk.dsk[i].name, pre->dsk.dsk[j].name) == 0) break; } /* ** either the corresponding entry has been found ** in the case that a disk has been removed, or ** an empty entry has been found (all counters ** on zero) in the case that a disk has been added ** during the last sample */ } strcpy(dev->dsk.dsk[i].name, cur->dsk.dsk[i].name); dev->dsk.dsk[i].nread = subcount(cur->dsk.dsk[i].nread, pre->dsk.dsk[j].nread); dev->dsk.dsk[i].nwrite = subcount(cur->dsk.dsk[i].nwrite, pre->dsk.dsk[j].nwrite); dev->dsk.dsk[i].nrsect = subcount(cur->dsk.dsk[i].nrsect, pre->dsk.dsk[j].nrsect); dev->dsk.dsk[i].nwsect = subcount(cur->dsk.dsk[i].nwsect, pre->dsk.dsk[j].nwsect); dev->dsk.dsk[i].io_ms = subcount(cur->dsk.dsk[i].io_ms, pre->dsk.dsk[j].io_ms); dev->dsk.dsk[i].avque = subcount(cur->dsk.dsk[i].avque, pre->dsk.dsk[j].avque); /* ** determine new j */ if (pre->dsk.dsk[j].name) // existing matching entry j++; else j = realj; // empty entry: stick to old j } dev->dsk.dsk[i].name[0] = '\0'; dev->dsk.ndsk = i; /* ** calculate deviations for multiple devices */ for (i=j=0; cur->dsk.mdd[i].name[0]; i++) { int realj = j; /* ** check if md has been added or removed since ** previous interval */ if ( strcmp(cur->dsk.mdd[i].name, pre->dsk.mdd[j].name) != 0) { for (j++; pre->dsk.mdd[j].name[0]; j++) { if ( strcmp(cur->dsk.mdd[i].name, pre->dsk.mdd[j].name) == 0) break; } /* ** either the corresponding entry has been found ** in the case that a md has been removed, or ** an empty entry has been found (all counters ** on zero) in the case that a md has been added ** during the last sample */ } strcpy(dev->dsk.mdd[i].name, cur->dsk.mdd[i].name); dev->dsk.mdd[i].nread = subcount(cur->dsk.mdd[i].nread, pre->dsk.mdd[j].nread); dev->dsk.mdd[i].nwrite = subcount(cur->dsk.mdd[i].nwrite, pre->dsk.mdd[j].nwrite); dev->dsk.mdd[i].nrsect = subcount(cur->dsk.mdd[i].nrsect, pre->dsk.mdd[j].nrsect); dev->dsk.mdd[i].nwsect = subcount(cur->dsk.mdd[i].nwsect, pre->dsk.mdd[j].nwsect); dev->dsk.mdd[i].io_ms = subcount(cur->dsk.mdd[i].io_ms, pre->dsk.mdd[j].io_ms); dev->dsk.mdd[i].avque = subcount(cur->dsk.mdd[i].avque, pre->dsk.mdd[j].avque); /* ** determine new j */ if (pre->dsk.mdd[j].name) // existing matching entry j++; else j = realj; // empty entry: stick to old j } dev->dsk.mdd[i].name[0] = '\0'; dev->dsk.nmdd = i; /* ** calculate deviations for LVM logical volumes */ for (i=j=0; cur->dsk.lvm[i].name[0]; i++) { int realj = j; /* ** check if logical volume has been added or removed since ** previous interval */ if ( strcmp(cur->dsk.lvm[i].name, pre->dsk.lvm[j].name) != 0) { for (j++; pre->dsk.lvm[j].name[0]; j++) { if ( strcmp(cur->dsk.lvm[i].name, pre->dsk.lvm[j].name) == 0) break; } /* ** either the corresponding entry has been found ** in the case that a logical volume has been removed, ** or an empty entry has been found (all counters ** on zero) in the case that a logical volume has ** been added during the last sample */ } strcpy(dev->dsk.lvm[i].name, cur->dsk.lvm[i].name); dev->dsk.lvm[i].nread = subcount(cur->dsk.lvm[i].nread, pre->dsk.lvm[j].nread); dev->dsk.lvm[i].nwrite = subcount(cur->dsk.lvm[i].nwrite, pre->dsk.lvm[j].nwrite); dev->dsk.lvm[i].nrsect = subcount(cur->dsk.lvm[i].nrsect, pre->dsk.lvm[j].nrsect); dev->dsk.lvm[i].nwsect = subcount(cur->dsk.lvm[i].nwsect, pre->dsk.lvm[j].nwsect); dev->dsk.lvm[i].io_ms = subcount(cur->dsk.lvm[i].io_ms, pre->dsk.lvm[j].io_ms); dev->dsk.lvm[i].avque = subcount(cur->dsk.lvm[i].avque, pre->dsk.lvm[j].avque); /* ** determine new j */ if (pre->dsk.lvm[j].name) // existing matching entry j++; else j = realj; // empty entry: stick to old j } dev->dsk.lvm[i].name[0] = '\0'; dev->dsk.nlvm = i; /* ** calculate deviations for NFS */ dev->nfs.server.netcnt = subcount(cur->nfs.server.netcnt, pre->nfs.server.netcnt); dev->nfs.server.netudpcnt = subcount(cur->nfs.server.netudpcnt, pre->nfs.server.netudpcnt); dev->nfs.server.nettcpcnt = subcount(cur->nfs.server.nettcpcnt, pre->nfs.server.nettcpcnt); dev->nfs.server.nettcpcon = subcount(cur->nfs.server.nettcpcon, pre->nfs.server.nettcpcon); dev->nfs.server.rpccnt = subcount(cur->nfs.server.rpccnt, pre->nfs.server.rpccnt); dev->nfs.server.rpcread = subcount(cur->nfs.server.rpcread, pre->nfs.server.rpcread); dev->nfs.server.rpcwrite = subcount(cur->nfs.server.rpcwrite, pre->nfs.server.rpcwrite); dev->nfs.server.rpcbadfmt = subcount(cur->nfs.server.rpcbadfmt, pre->nfs.server.rpcbadfmt); dev->nfs.server.rpcbadaut = subcount(cur->nfs.server.rpcbadaut, pre->nfs.server.rpcbadaut); dev->nfs.server.rpcbadcln = subcount(cur->nfs.server.rpcbadcln, pre->nfs.server.rpcbadcln); dev->nfs.server.rchits = subcount(cur->nfs.server.rchits, pre->nfs.server.rchits); dev->nfs.server.rcmiss = subcount(cur->nfs.server.rcmiss, pre->nfs.server.rcmiss); dev->nfs.server.rcnoca = subcount(cur->nfs.server.rcnoca, pre->nfs.server.rcnoca); dev->nfs.server.nrbytes = subcount(cur->nfs.server.nrbytes, pre->nfs.server.nrbytes); dev->nfs.server.nwbytes = subcount(cur->nfs.server.nwbytes, pre->nfs.server.nwbytes); dev->nfs.client.rpccnt = subcount(cur->nfs.client.rpccnt, pre->nfs.client.rpccnt); dev->nfs.client.rpcread = subcount(cur->nfs.client.rpcread, pre->nfs.client.rpcread); dev->nfs.client.rpcwrite = subcount(cur->nfs.client.rpcwrite, pre->nfs.client.rpcwrite); dev->nfs.client.rpcretrans = subcount(cur->nfs.client.rpcretrans, pre->nfs.client.rpcretrans); dev->nfs.client.rpcautrefresh = subcount(cur->nfs.client.rpcautrefresh, pre->nfs.client.rpcautrefresh); for (i=j=0; i < cur->nfs.nfsmounts.nrmounts; i++, j++) { /* ** check if nfsmounts have been added or removed since ** previous interval */ if ( strcmp(cur->nfs.nfsmounts.nfsmnt[i].mountdev, pre->nfs.nfsmounts.nfsmnt[j].mountdev) != 0) { for (j=0; j < pre->nfs.nfsmounts.nrmounts; j++) { if ( strcmp(cur->nfs.nfsmounts.nfsmnt[i].mountdev, pre->nfs.nfsmounts.nfsmnt[j].mountdev) == 0) break; } /* ** either the corresponding entry has been found ** in the case that a container has been removed, ** or an empty entry has been found (all counters ** on zero) in the case that a container has ** been added during the last sample */ } strcpy(dev->nfs.nfsmounts.nfsmnt[i].mountdev, cur->nfs.nfsmounts.nfsmnt[i].mountdev); dev->nfs.nfsmounts.nfsmnt[i].age = cur->nfs.nfsmounts.nfsmnt[i].age; if (dev->nfs.nfsmounts.nfsmnt[i].age <= interval) memset(&(pre->nfs.nfsmounts.nfsmnt[j]), 0, sizeof(struct pernfsmount)); dev->nfs.nfsmounts.nfsmnt[i].bytesread = subcount(cur->nfs.nfsmounts.nfsmnt[i].bytesread, pre->nfs.nfsmounts.nfsmnt[j].bytesread); dev->nfs.nfsmounts.nfsmnt[i].byteswrite = subcount(cur->nfs.nfsmounts.nfsmnt[i].byteswrite, pre->nfs.nfsmounts.nfsmnt[j].byteswrite); dev->nfs.nfsmounts.nfsmnt[i].bytesdread = subcount(cur->nfs.nfsmounts.nfsmnt[i].bytesdread, pre->nfs.nfsmounts.nfsmnt[j].bytesdread); dev->nfs.nfsmounts.nfsmnt[i].bytesdwrite = subcount(cur->nfs.nfsmounts.nfsmnt[i].bytesdwrite, pre->nfs.nfsmounts.nfsmnt[j].bytesdwrite); dev->nfs.nfsmounts.nfsmnt[i].bytestotread = subcount(cur->nfs.nfsmounts.nfsmnt[i].bytestotread, pre->nfs.nfsmounts.nfsmnt[j].bytestotread); dev->nfs.nfsmounts.nfsmnt[i].bytestotwrite = subcount(cur->nfs.nfsmounts.nfsmnt[i].bytestotwrite, pre->nfs.nfsmounts.nfsmnt[j].bytestotwrite); dev->nfs.nfsmounts.nfsmnt[i].pagesmread = subcount(cur->nfs.nfsmounts.nfsmnt[i].pagesmread, pre->nfs.nfsmounts.nfsmnt[j].pagesmread); dev->nfs.nfsmounts.nfsmnt[i].pagesmwrite = subcount(cur->nfs.nfsmounts.nfsmnt[i].pagesmwrite, pre->nfs.nfsmounts.nfsmnt[j].pagesmwrite); } dev->nfs.nfsmounts.nrmounts = cur->nfs.nfsmounts.nrmounts; /* ** calculate deviations for containers */ for (i=j=0; i < cur->cfs.nrcontainer; i++, j++) { /* ** check if containers have been added or removed since ** previous interval */ if (cur->cfs.cont[i].ctid != pre->cfs.cont[j].ctid) { for (j=0; j < pre->cfs.nrcontainer; j++) { if (cur->cfs.cont[i].ctid == pre->cfs.cont[j].ctid) break; } /* ** either the corresponding entry has been found ** in the case that a container has been removed, ** or an empty entry has been found (all counters ** on zero) in the case that a container has ** been added during the last sample */ } dev->cfs.cont[i].ctid = cur->cfs.cont[i].ctid; dev->cfs.cont[i].numproc = cur->cfs.cont[i].numproc; dev->cfs.cont[i].system = subcount(cur->cfs.cont[i].system, pre->cfs.cont[i].system); dev->cfs.cont[i].user = subcount(cur->cfs.cont[i].user, pre->cfs.cont[i].user); dev->cfs.cont[i].nice = subcount(cur->cfs.cont[i].nice, pre->cfs.cont[i].nice); dev->cfs.cont[i].uptime = subcount(cur->cfs.cont[i].uptime, pre->cfs.cont[i].uptime); dev->cfs.cont[i].physpages = cur->cfs.cont[i].physpages; } dev->cfs.nrcontainer = cur->cfs.nrcontainer; /* ** calculate deviations for GPUs */ for (i=0; i < cur->gpu.nrgpus; i++) { dev->gpu.gpu[i].gpunr = i; strcpy(dev->gpu.gpu[i].type, cur->gpu.gpu[i].type); strcpy(dev->gpu.gpu[i].busid, cur->gpu.gpu[i].busid); dev->gpu.gpu[i].taskstats = cur->gpu.gpu[i].taskstats; dev->gpu.gpu[i].nrprocs = cur->gpu.gpu[i].nrprocs; dev->gpu.gpu[i].gpupercnow = cur->gpu.gpu[i].gpupercnow; dev->gpu.gpu[i].mempercnow = cur->gpu.gpu[i].mempercnow; dev->gpu.gpu[i].memtotnow = cur->gpu.gpu[i].memtotnow; dev->gpu.gpu[i].memusenow = cur->gpu.gpu[i].memusenow; dev->gpu.gpu[i].samples = subcount(cur->gpu.gpu[i].samples, pre->gpu.gpu[i].samples); if (cur->gpu.gpu[i].gpuperccum >= 0) dev->gpu.gpu[i].gpuperccum = subcount(cur->gpu.gpu[i].gpuperccum, pre->gpu.gpu[i].gpuperccum); else dev->gpu.gpu[i].gpuperccum = -1; if (cur->gpu.gpu[i].memusecum >= 0) dev->gpu.gpu[i].memusecum = subcount(cur->gpu.gpu[i].memusecum, pre->gpu.gpu[i].memusecum); else dev->gpu.gpu[i].memusecum = -1; if (cur->gpu.gpu[i].memperccum >= 0) dev->gpu.gpu[i].memperccum = subcount(cur->gpu.gpu[i].memperccum, pre->gpu.gpu[i].memperccum); else dev->gpu.gpu[i].memperccum = -1; } dev->gpu.nrgpus = cur->gpu.nrgpus; /* ** calculate deviations for InfiniBand */ for (i=0; i < cur->ifb.nrports; i++) { strcpy(dev->ifb.ifb[i].ibname, cur->ifb.ifb[i].ibname); dev->ifb.ifb[i].portnr = cur->ifb.ifb[i].portnr; dev->ifb.ifb[i].lanes = cur->ifb.ifb[i].lanes; dev->ifb.ifb[i].rate = cur->ifb.ifb[i].rate; dev->ifb.ifb[i].rcvb = cur->ifb.ifb[i].rcvb - pre->ifb.ifb[i].rcvb; dev->ifb.ifb[i].sndb = cur->ifb.ifb[i].sndb - pre->ifb.ifb[i].sndb; dev->ifb.ifb[i].rcvp = cur->ifb.ifb[i].rcvp - pre->ifb.ifb[i].rcvp; dev->ifb.ifb[i].sndp = cur->ifb.ifb[i].sndp - pre->ifb.ifb[i].sndp; } dev->ifb.nrports = cur->ifb.nrports; #if HTTPSTATS /* ** application-specific counters */ if (cur->www.uptime >= pre->www.uptime) { dev->www.accesses = subcount(cur->www.accesses, pre->www.accesses); dev->www.totkbytes = subcount(cur->www.totkbytes, pre->www.totkbytes); } else { dev->www.accesses = cur->www.accesses; dev->www.totkbytes = cur->www.totkbytes; } dev->www.bworkers = cur->www.bworkers; dev->www.iworkers = cur->www.iworkers; #endif } /* ** add the values of a new sample to a structure holding the totals ** for the indicated category (c=cpu, m=memory, d=disk, n=network). */ void totalsyst(char category, struct sstat *new, struct sstat *tot) { register int i; count_t *ctot, *cnew; switch (category) { case 'c': /* accumulate cpu-related counters */ tot->cpu.nrcpu = new->cpu.nrcpu; tot->cpu.devint += new->cpu.devint; tot->cpu.csw += new->cpu.csw; tot->cpu.nprocs += new->cpu.nprocs; tot->cpu.all.stime += new->cpu.all.stime; tot->cpu.all.utime += new->cpu.all.utime; tot->cpu.all.ntime += new->cpu.all.ntime; tot->cpu.all.itime += new->cpu.all.itime; tot->cpu.all.wtime += new->cpu.all.wtime; tot->cpu.all.Itime += new->cpu.all.Itime; tot->cpu.all.Stime += new->cpu.all.Stime; tot->cpu.all.steal += new->cpu.all.steal; tot->cpu.all.guest += new->cpu.all.guest; if (new->cpu.nrcpu == 1) { tot->cpu.cpu[0] = tot->cpu.all; } else { for (i=0; i < new->cpu.nrcpu; i++) { tot->cpu.cpu[i].cpunr = new->cpu.cpu[i].cpunr; tot->cpu.cpu[i].stime += new->cpu.cpu[i].stime; tot->cpu.cpu[i].utime += new->cpu.cpu[i].utime; tot->cpu.cpu[i].ntime += new->cpu.cpu[i].ntime; tot->cpu.cpu[i].itime += new->cpu.cpu[i].itime; tot->cpu.cpu[i].wtime += new->cpu.cpu[i].wtime; tot->cpu.cpu[i].Itime += new->cpu.cpu[i].Itime; tot->cpu.cpu[i].Stime += new->cpu.cpu[i].Stime; tot->cpu.cpu[i].steal += new->cpu.cpu[i].steal; tot->cpu.cpu[i].guest += new->cpu.cpu[i].guest; } } tot->cpu.lavg1 = new->cpu.lavg1; tot->cpu.lavg5 = new->cpu.lavg5; tot->cpu.lavg15 = new->cpu.lavg15; break; case 'm': /* accumulate memory-related counters */ tot->mem.physmem = new->mem.physmem; tot->mem.freemem = new->mem.freemem; tot->mem.buffermem = new->mem.buffermem; tot->mem.slabmem = new->mem.slabmem; tot->mem.slabreclaim = new->mem.slabreclaim; tot->mem.committed = new->mem.committed; tot->mem.commitlim = new->mem.commitlim; tot->mem.cachemem = new->mem.cachemem; tot->mem.cachedrt = new->mem.cachedrt; tot->mem.totswap = new->mem.totswap; tot->mem.freeswap = new->mem.freeswap; tot->mem.shmem = new->mem.shmem; tot->mem.shmrss = new->mem.shmrss; tot->mem.shmswp = new->mem.shmswp; tot->mem.swouts += new->mem.swouts; tot->mem.swins += new->mem.swins; tot->mem.pgscans += new->mem.pgscans; tot->mem.allocstall += new->mem.allocstall; break; case 'n': /* accumulate network-related counters */ tot->nfs.server.rpccnt += new->nfs.server.rpccnt; tot->nfs.server.rpcread += new->nfs.server.rpcread; tot->nfs.server.rpcwrite += new->nfs.server.rpcwrite; tot->nfs.server.rpcbadfmt += new->nfs.server.rpcbadfmt; tot->nfs.server.rpcbadaut += new->nfs.server.rpcbadaut; tot->nfs.server.rpcbadcln += new->nfs.server.rpcbadcln; tot->nfs.server.netcnt += new->nfs.server.netcnt; tot->nfs.server.nettcpcnt += new->nfs.server.nettcpcnt; tot->nfs.server.netudpcnt += new->nfs.server.netudpcnt; tot->nfs.server.nettcpcon += new->nfs.server.nettcpcon; tot->nfs.server.rchits += new->nfs.server.rchits; tot->nfs.server.rcmiss += new->nfs.server.rcmiss; tot->nfs.server.rcnoca += new->nfs.server.rcnoca; tot->nfs.server.nrbytes += new->nfs.server.nrbytes; tot->nfs.server.nwbytes += new->nfs.server.nwbytes; tot->nfs.client.rpccnt += new->nfs.client.rpccnt; tot->nfs.client.rpcread += new->nfs.client.rpcread; tot->nfs.client.rpcwrite += new->nfs.client.rpcwrite; tot->nfs.client.rpcretrans += new->nfs.client.rpcretrans; tot->nfs.client.rpcautrefresh += new->nfs.client.rpcautrefresh; /* ** other structures with network counters are considered ** as tables of frequency-counters that will be accumulated; ** values that do not represent a frequency are corrected ** afterwards */ for (ctot = (count_t *)&tot->net.ipv4, cnew = (count_t *)&new->net.ipv4, i = 0; i < (sizeof tot->net.ipv4 / sizeof(count_t)); ctot++, cnew++, i++) *ctot += *cnew; tot->net.ipv4.Forwarding = new->net.ipv4.Forwarding; tot->net.ipv4.DefaultTTL = new->net.ipv4.DefaultTTL; /* ------------- */ for (ctot = (count_t *)&tot->net.icmpv4, cnew = (count_t *)&new->net.icmpv4, i = 0; i < (sizeof tot->net.icmpv4 / sizeof(count_t)); ctot++, cnew++, i++) *ctot += *cnew; /* ------------- */ for (ctot = (count_t *)&tot->net.udpv4, cnew = (count_t *)&new->net.udpv4, i = 0; i < (sizeof tot->net.udpv4 / sizeof(count_t)); ctot++, cnew++, i++) *ctot += *cnew; /* ------------- */ for (ctot = (count_t *)&tot->net.ipv6, cnew = (count_t *)&new->net.ipv6, i = 0; i < (sizeof tot->net.ipv6 / sizeof(count_t)); ctot++, cnew++, i++) *ctot += *cnew; /* ------------- */ for (ctot = (count_t *)&tot->net.icmpv6, cnew = (count_t *)&new->net.icmpv6, i = 0; i < (sizeof tot->net.icmpv6 / sizeof(count_t)); ctot++, cnew++, i++) *ctot += *cnew; /* ------------- */ for (ctot = (count_t *)&tot->net.udpv6, cnew = (count_t *)&new->net.udpv6, i = 0; i < (sizeof tot->net.udpv6 / sizeof(count_t)); ctot++, cnew++, i++) *ctot += *cnew; /* ------------- */ for (ctot = (count_t *)&tot->net.tcp, cnew = (count_t *)&new->net.tcp, i = 0; i < (sizeof tot->net.tcp / sizeof(count_t)); ctot++, cnew++, i++) *ctot += *cnew; tot->net.tcp.RtoAlgorithm = new->net.tcp.RtoAlgorithm; tot->net.tcp.RtoMin = new->net.tcp.RtoMin; tot->net.tcp.RtoMax = new->net.tcp.RtoMax; tot->net.tcp.MaxConn = new->net.tcp.MaxConn; tot->net.tcp.CurrEstab = new->net.tcp.CurrEstab; for (i=0; new->intf.intf[i].name[0]; i++) { /* ** check if an interface has been added or removed; ** in that case, zero all counters */ if (strcmp(new->intf.intf[i].name, tot->intf.intf[i].name) != 0) { tot->intf.intf[i].rbyte = 0; tot->intf.intf[i].rpack = 0; tot->intf.intf[i].rerrs = 0; tot->intf.intf[i].rdrop = 0; tot->intf.intf[i].rfifo = 0; tot->intf.intf[i].rframe = 0; tot->intf.intf[i].rcompr = 0; tot->intf.intf[i].rmultic = 0; tot->intf.intf[i].sbyte = 0; tot->intf.intf[i].spack = 0; tot->intf.intf[i].serrs = 0; tot->intf.intf[i].sdrop = 0; tot->intf.intf[i].sfifo = 0; tot->intf.intf[i].scollis = 0; tot->intf.intf[i].scarrier = 0; tot->intf.intf[i].scompr = 0; } /* ** accumulate counters for this sample */ strcpy(tot->intf.intf[i].name, new->intf.intf[i].name); tot->intf.intf[i].rbyte += new->intf.intf[i].rbyte; tot->intf.intf[i].rpack += new->intf.intf[i].rpack; tot->intf.intf[i].rerrs += new->intf.intf[i].rerrs; tot->intf.intf[i].rdrop += new->intf.intf[i].rdrop; tot->intf.intf[i].rfifo += new->intf.intf[i].rfifo; tot->intf.intf[i].rframe += new->intf.intf[i].rframe; tot->intf.intf[i].rcompr += new->intf.intf[i].rcompr; tot->intf.intf[i].rmultic += new->intf.intf[i].rmultic; tot->intf.intf[i].sbyte += new->intf.intf[i].sbyte; tot->intf.intf[i].spack += new->intf.intf[i].spack; tot->intf.intf[i].serrs += new->intf.intf[i].serrs; tot->intf.intf[i].sdrop += new->intf.intf[i].sdrop; tot->intf.intf[i].sfifo += new->intf.intf[i].sfifo; tot->intf.intf[i].scollis += new->intf.intf[i].scollis; tot->intf.intf[i].scarrier+= new->intf.intf[i].scarrier; tot->intf.intf[i].scompr += new->intf.intf[i].scompr; tot->intf.intf[i].type = new->intf.intf[i].type; tot->intf.intf[i].speed = new->intf.intf[i].speed; tot->intf.intf[i].duplex = new->intf.intf[i].duplex; } tot->intf.intf[i].name[0] = '\0'; tot->intf.nrintf = i; #if HTTPSTATS tot->www.accesses += new->www.accesses; tot->www.totkbytes += new->www.totkbytes; tot->www.bworkers = new->www.bworkers; tot->www.iworkers = new->www.iworkers; #endif break; case 'd': /* accumulate disk-related counters */ for (i=0; new->dsk.dsk[i].name[0]; i++) { strcpy(tot->dsk.dsk[i].name, new->dsk.dsk[i].name); tot->dsk.dsk[i].nread += new->dsk.dsk[i].nread; tot->dsk.dsk[i].nwrite += new->dsk.dsk[i].nwrite; tot->dsk.dsk[i].nrsect += new->dsk.dsk[i].nrsect; tot->dsk.dsk[i].nwsect += new->dsk.dsk[i].nwsect; tot->dsk.dsk[i].io_ms += new->dsk.dsk[i].io_ms; tot->dsk.dsk[i].avque += new->dsk.dsk[i].avque; } tot->dsk.dsk[i].name[0] = '\0'; tot->dsk.ndsk = i; for (i=0; new->dsk.lvm[i].name[0]; i++) { strcpy(tot->dsk.lvm[i].name, new->dsk.lvm[i].name); tot->dsk.lvm[i].nread += new->dsk.lvm[i].nread; tot->dsk.lvm[i].nwrite += new->dsk.lvm[i].nwrite; tot->dsk.lvm[i].nrsect += new->dsk.lvm[i].nrsect; tot->dsk.lvm[i].nwsect += new->dsk.lvm[i].nwsect; tot->dsk.lvm[i].io_ms += new->dsk.lvm[i].io_ms; tot->dsk.lvm[i].avque += new->dsk.lvm[i].avque; } tot->dsk.lvm[i].name[0] = '\0'; tot->dsk.nlvm = i; for (i=0; new->dsk.mdd[i].name[0]; i++) { strcpy(tot->dsk.mdd[i].name, new->dsk.mdd[i].name); tot->dsk.mdd[i].nread += new->dsk.mdd[i].nread; tot->dsk.mdd[i].nwrite += new->dsk.mdd[i].nwrite; tot->dsk.mdd[i].nrsect += new->dsk.mdd[i].nrsect; tot->dsk.mdd[i].nwsect += new->dsk.mdd[i].nwsect; tot->dsk.mdd[i].io_ms += new->dsk.mdd[i].io_ms; tot->dsk.mdd[i].avque += new->dsk.mdd[i].avque; } tot->dsk.mdd[i].name[0] = '\0'; tot->dsk.nmdd = i; break; } } /* ** Generic function to subtract two counters taking into ** account the possibility of overflow of a 32-bit kernel-counter. */ count_t subcount(count_t newval, count_t oldval) { if (newval >= oldval) return newval - oldval; else return MAX32BITVAL + newval - oldval; } atop-2.4.0/gpucom.c0000644000203100020310000003145113416466037013434 0ustar gerlofgerlof/* ** 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 functions to interface with the atopgpud ** daemon that maintains statistics about the processor and memory ** utilization of the GPUs. ** ================================================================ ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Initial: April/August 2018 ** ** 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. */ #include #include #include #include #include #include #include #include #include "atop.h" #include "photosyst.h" #include "photoproc.h" #include "gpucom.h" #define DUMMY ' ' #define GPUDELIM '@' #define PIDDELIM '#' #define GPUDPORT 59123 static void gputype_parse(char *); static void gpustat_parse(int, char *, int, struct pergpu *, struct gpupidstat *); static void gpuparse(int, char *, struct pergpu *); static void pidparse(int, char *, struct gpupidstat *); static int rcvuntil(int, char *, int); static int actsock = -1; static int numgpus; static char **gpubusid; // array with char* to busid strings static char **gputypes; // array with char* to type strings static char *gputasks; // array with chars with tasksupport booleans /* ** Open TCP connection to port of atopgpud and ** obtain type information of every GPU. ** ** Return value: ** number of GPUs */ int gpud_init(void) { struct sockaddr_in name; socklen_t namelen = sizeof name; char typereq[] = {'T', APIVERSION}; uint32_t prelude; char *buf; int version, length; struct timeval rcvtimeout = {2, 0}; // 2 seconds /* ** get local socket */ if ( (actsock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket creation"); return 0; } /* ** connect to server port */ memset(&name, 0, sizeof name); name.sin_family = AF_INET; name.sin_addr.s_addr = htonl(INADDR_LOOPBACK); name.sin_port = htons(GPUDPORT); if (connect(actsock, (struct sockaddr *)&name, namelen) == -1) goto close_and_return; /* ** set receive timeout, not to block atop forever ** in case something fails in the commmunication */ (void) setsockopt(actsock, SOL_SOCKET, SO_RCVTIMEO, &rcvtimeout, sizeof rcvtimeout); /* ** send request: GPU types */ if ( write(actsock, typereq, sizeof typereq) < sizeof typereq) { perror("send type request to atopgpud"); goto close_and_return; } /* ** receive response: GPU types */ if (rcvuntil(actsock, (char *)&prelude, sizeof prelude) == -1) { perror("receive prelude from atopgpud"); goto close_and_return; } prelude = ntohl(prelude); // big endian to native endianess version = (prelude >> 24) & 0xff; length = prelude & 0xffffff; if (version != APIVERSION) { fprintf(stderr, "wrong API version from atopgpud: %d %d\n", version, APIVERSION); goto close_and_return; } if (length > 8192) // sanity check { fprintf(stderr, "unexpected response length atopgpud: %d\n", length); goto close_and_return; } buf = malloc(length+1); ptrverify(buf, "Malloc failed for gpu rcvbuf\n"); if ( rcvuntil(actsock, buf, length) == -1) { perror("receive type request from atopgpud"); goto close_and_return; } buf[length] = '\0'; gputype_parse(buf); numgpus = numgpus <= MAXGPU ? numgpus : MAXGPU; return numgpus; close_and_return: close(actsock); actsock = -1; return 0; } /* ** Transmit status request for all GPUs. ** ** Calling parameters: ** void ** ** Return value: ** 0 in case of failure ** 1 in case of success */ int gpud_statrequest(void) { char statreq[] = {'S', APIVERSION}; if (actsock == -1) return 0; if ( write(actsock, statreq, sizeof statreq) < sizeof statreq) { close(actsock); actsock = -1; return 0; } return 1; } /* ** Receive status response for all GPUs. ** ** Calling parameters: ** *ggs pointer to allocated array of pergpu structs ** **gps pointer to pointer in which addresses to gpupidstat structs ** are returned ** can be NULL pointer is caller is not interested in proc stats ** ** Return value: ** number of gpupidstat addresses (i.e. per-process info) ** -1 in case of failure */ int gpud_statresponse(int maxgpu, struct pergpu *ggs, struct gpupidstat **gps) { uint32_t prelude; char *buf = NULL, *p; int version, length; int pids = 0; if (actsock == -1) return -1; /* ** receive 4-bytes introducer: ** first byte: API version ** next three bytes: length of string that follows */ if ( rcvuntil(actsock, (char *)&prelude, sizeof prelude) == -1) { perror("receive 4-byte prelude from atopgpud"); goto close_and_return; } prelude = ntohl(prelude); // big endian to native endianess version = (prelude >> 24) & 0xff; length = prelude & 0xffffff; if (version != APIVERSION) { fprintf(stderr, "wrong API version from atopgpud: %d %d\n", version, APIVERSION); goto close_and_return; } if (length > 8192) // sanity check { fprintf(stderr, "unexpected response length atopgpud: %d\n", length); goto close_and_return; } buf = malloc(length+1); ptrverify(buf, "Malloc failed for gpu rcvbuf\n"); /* ** receive statistics string */ if ( rcvuntil(actsock, buf, length) == -1) { perror("receive stats string from atopgpud"); goto close_and_return; } *(buf+length) = '\0'; /* ** determine number of per-process stats ** and malloc space to parse these stats */ for (p=buf; *p; p++) { if (*p == PIDDELIM) pids++; } if (gps) { if (pids) { *gps = malloc(pids * sizeof(struct gpupidstat)); ptrverify(gps, "Malloc failed for gpu pidstats\n"); memset(*gps, 0, pids * sizeof(struct gpupidstat)); } else { *gps = NULL; } } /* ** parse stats string for per-gpu stats */ gpustat_parse(version, buf, maxgpu, ggs, gps ? *gps : NULL); free(buf); return pids; close_and_return: if (buf) free(buf); close(actsock); actsock = -1; return -1; } /* ** Receive given number of bytes from given socket ** into given buffer address */ static int rcvuntil(int sock, char *buf, int size) { int remain = size, n; while (remain) { n = read(sock, buf, remain); if (n <= 0) return -1; buf += n; remain -= n; } return size; } /* ** Parse response string from server on 'T' request ** ** Store the type, busid and tasksupport of every GPU in ** static pointer tables */ static void gputype_parse(char *buf) { char *p, *start, **bp, **tp, *cp; /* ** determine number of GPUs */ if ( sscanf(buf, "%d@", &numgpus) != 1) { close(actsock); actsock = -1; return; } for (p=buf; *p; p++) // search for first delimiter { if (*p == GPUDELIM) { p++; break; } } /* ** parse GPU info and build arrays of pointers to the ** busid strings, type strings and tasksupport strings. */ if (numgpus) // GPUs present anyhow? { int field; gpubusid = bp = malloc((numgpus+1) * sizeof(char *)); gputypes = tp = malloc((numgpus+1) * sizeof(char *)); gputasks = cp = malloc((numgpus) * sizeof(char )); ptrverify(gpubusid, "Malloc failed for gpu busids\n"); ptrverify(gputypes, "Malloc failed for gpu types\n"); ptrverify(gputasks, "Malloc failed for gpu tasksup\n"); for (field=0, start=p; ; p++) { if (*p == ' ' || *p == '\0' || *p == GPUDELIM) { switch(field) { case 0: if (p-start <= MAXGPUBUS) *bp++ = start; else *bp++ = p - MAXGPUBUS; break; case 1: if (p-start <= MAXGPUTYPE) *tp++ = start; else *tp++ = p - MAXGPUTYPE; break; case 2: *cp++ = *start; break; } field++; start = p+1; if (*p == '\0') break; if (*p == GPUDELIM) field = 0; *p = '\0'; } } *bp = NULL; *tp = NULL; } } /* ** Parse entire response string from server. ** ** Every series with counters on GPU level is introduced ** with a '@' delimiter. ** Every series with counters on process level is introduced ** with a '#' delimiter (last part of the GPU level data). */ static void gpustat_parse(int version, char *buf, int maxgpu, struct pergpu *gg, struct gpupidstat *gp) { char *p, *start, delimlast; int gpunum = 0; /* ** parse stats string */ for (p=start=buf, delimlast=DUMMY; gpunum <= maxgpu; p++) { char delimnow; if (*p != '\0' && *p != GPUDELIM && *p != PIDDELIM) continue; /* ** next delimiter or end-of-string found */ delimnow = *p; *p = 0; switch (delimlast) { case DUMMY: break; case GPUDELIM: gpuparse(version, start, gg); strcpy(gg->type, gputypes[gpunum]); strcpy(gg->busid, gpubusid[gpunum]); gpunum++; gg++; break; case PIDDELIM: if (gp) { pidparse(version, start, gp); gp->gpu.nrgpus++; gp->gpu.gpulist = 1<<(gpunum-1); gp++; (gg-1)->nrprocs++; } } if (delimnow == 0 || *(p+1) == 0) break; start = p+1; delimlast = delimnow; } } /* ** Parse GPU statistics string */ static void gpuparse(int version, char *p, struct pergpu *gg) { switch (version) { case 1: (void) sscanf(p, "%d %d %lld %lld %lld %lld %lld %lld", &(gg->gpupercnow), &(gg->mempercnow), &(gg->memtotnow), &(gg->memusenow), &(gg->samples), &(gg->gpuperccum), &(gg->memperccum), &(gg->memusecum)); gg->nrprocs = 0; break; } } /* ** Parse PID statistics string */ static void pidparse(int version, char *p, struct gpupidstat *gp) { switch (version) { case 1: (void) sscanf(p, "%c %ld %d %d %lld %lld %lld %lld", &(gp->gpu.state), &(gp->pid), &(gp->gpu.gpubusy), &(gp->gpu.membusy), &(gp->gpu.timems), &(gp->gpu.memnow), &(gp->gpu.memcum), &(gp->gpu.sample)); break; } } /* ** Merge the GPU per-process counters with the other ** per-process counters */ static int compgpupid(const void *, const void *); void gpumergeproc(struct tstat *curtpres, int ntaskpres, struct tstat *curpexit, int nprocexit, struct gpupidstat *gpuproc, int nrgpuproc) { struct gpupidstat **gpp; int t, g, gpuleft = nrgpuproc; /* ** make pointer list for elements in gpuproc */ gpp = malloc(nrgpuproc * sizeof(struct gpupidstat *)); ptrverify(gpp, "Malloc failed for process list\n"); for (g=0; g < nrgpuproc; g++) gpp[g] = gpuproc + g; /* ** sort the list with pointers in order of pid */ if (nrgpuproc > 1) qsort(gpp, nrgpuproc, sizeof(struct gpupidstat *), compgpupid); /* ** accumulate entries that contain stats from same PID ** on different GPUs */ for (g=1; g < nrgpuproc; g++) { if (gpp[g-1]->pid == gpp[g]->pid) { struct gpupidstat *p = gpp[g-1], *q = gpp[g]; p->gpu.nrgpus += q->gpu.nrgpus; p->gpu.gpulist |= q->gpu.gpulist; if (p->gpu.gpubusy != -1) p->gpu.gpubusy += q->gpu.gpubusy; if (p->gpu.membusy != -1) p->gpu.membusy += q->gpu.membusy; if (p->gpu.timems != -1) p->gpu.timems += q->gpu.timems; p->gpu.memnow += q->gpu.memnow; p->gpu.memcum += q->gpu.memcum; p->gpu.sample += q->gpu.sample; if (nrgpuproc-g-1 > 0) memmove(&(gpp[g]), &(gpp[g+1]), (nrgpuproc-g-1) * sizeof p); nrgpuproc--; g--; } } /* ** merge gpu stats with sorted task list of active processes */ for (t=g=0; t < ntaskpres && g < nrgpuproc; t++) { if (curtpres[t].gen.isproc) { if (curtpres[t].gen.pid == gpp[g]->pid) { curtpres[t].gpu = gpp[g]->gpu; gpp[g++] = NULL; if (--gpuleft == 0 || g >= nrgpuproc) break; } // anyhow resync while ( curtpres[t].gen.pid > gpp[g]->pid) { if (++g >= nrgpuproc) break; } } } if (gpuleft == 0) { free(gpp); return; } /* ** compact list with pointers to remaining pids */ for (g=t=0; g < nrgpuproc; g++) { if (gpp[g] == NULL) { for (; t < nrgpuproc; t++) { if (gpp[t]) { gpp[g] = gpp[t]; gpp[t] = NULL; break; } } } } /* ** merge remaining gpu stats with task list of exited processes */ for (t=0; t < nprocexit && gpuleft; t++) { if (curpexit[t].gen.isproc) { for (g=0; g < gpuleft; g++) { if (gpp[g] == NULL) continue; if (curpexit[t].gen.pid == gpp[g]->pid) { curpexit[t].gpu = gpp[g]->gpu; gpp[g] = NULL; gpuleft--; } } } } free(gpp); } static int compgpupid(const void *a, const void *b) { return (*((struct gpupidstat **)a))->pid - (*((struct gpupidstat **)b))->pid; } atop-2.4.0/gpucom.h0000644000203100020310000000057113416466037013440 0ustar gerlofgerlof#ifndef __GPUCOM__ #define __GPUCOM__ #define APIVERSION 1 struct gpupidstat { long pid; struct gpu gpu; }; int gpud_init(void); int gpud_statrequest(void); int gpud_statresponse(int, struct pergpu *, struct gpupidstat **); void gpumergeproc(struct tstat *, int, struct tstat *, int, struct gpupidstat *, int); #endif atop-2.4.0/ifprop.c0000664000203100020310000001132113416466037013435 0ustar gerlofgerlof/* ** 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. ** ** ========================================================================== ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Date: January 2007 ** -------------------------------------------------------------------------- ** Copyright (C) 2007-2010 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 ** -------------------------------------------------------------------------- ** ** $Id: ifprop.c,v 1.5 2010/04/23 12:19:35 gerlof Exp $ ** $Log: ifprop.c,v $ ** Revision 1.5 2010/04/23 12:19:35 gerlof ** Modified mail-address in header. ** ** Revision 1.4 2007/02/13 10:34:06 gerlof ** Removal of external declarations. ** */ #include #include #include #include #include #include #include #include #include #include typedef __u64 u64; typedef __u32 u32; typedef __u16 u16; typedef __u8 u8; #include #include #ifndef SPEED_UNKNOWN #define SPEED_UNKNOWN -1 #endif #include "atop.h" #include "ifprop.h" #include "photosyst.h" static struct ifprop ifprops[MAXINTF]; /* ** function searches for the properties of a particular interface ** the interface name should be filled in the struct ifprop before ** calling this function ** ** return value reflects true or false */ int getifprop(struct ifprop *ifp) { register int i; for (i=0; ifprops[i].name[0]; i++) { if (strcmp(ifp->name, ifprops[i].name) == 0) { *ifp = ifprops[i]; return 1; } } ifp->type = '?'; ifp->speed = 0; ifp->fullduplex = 0; return 0; } /* ** function stores properties of all interfaces in a static ** table to be queried later on ** ** this function should be called with superuser privileges! */ void initifprop(void) { FILE *fp; char *cp, linebuf[2048]; int i=0, sockfd; struct ethtool_cmd ethcmd; struct ifreq ifreq; struct iwreq iwreq; /* ** open /proc/net/dev to obtain all interface names and open ** a socket to determine the properties for each interface */ if ( (fp = fopen("/proc/net/dev", "r")) == NULL) return; if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { fclose(fp); return; } /* ** read every name and obtain properties */ while ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { /* ** skip lines containing a '|' symbol (headers) */ if ( strchr(linebuf, '|') != NULL) continue; if ( (cp = strchr(linebuf, ':')) != NULL) *cp = ' '; /* subst ':' by space */ sscanf(linebuf, "%15s", ifprops[i].name); /* ** determine properties of ethernet interface */ memset(&ifreq, 0, sizeof ifreq); memset(ðcmd, 0, sizeof ethcmd); strncpy((void *)&ifreq.ifr_ifrn.ifrn_name, ifprops[i].name, sizeof ifreq.ifr_ifrn.ifrn_name-1); ifreq.ifr_ifru.ifru_data = (void *)ðcmd; ethcmd.cmd = ETHTOOL_GSET; if ( ioctl(sockfd, SIOCETHTOOL, &ifreq) == 0) { ifprops[i].type = 'e'; // type ethernet ifprops[i].speed = ethtool_cmd_speed(ðcmd); if (ifprops[i].speed == (u32)SPEED_UNKNOWN) ifprops[i].speed = 0; switch (ethcmd.duplex) { case DUPLEX_FULL: ifprops[i].fullduplex = 1; break; default: ifprops[i].fullduplex = 0; } if (++i >= MAXINTF-1) break; else continue; } /* ** determine properties of wireless interface */ memset(&iwreq, 0, sizeof iwreq); strncpy(iwreq.ifr_ifrn.ifrn_name, ifprops[i].name, sizeof iwreq.ifr_ifrn.ifrn_name-1); if ( ioctl(sockfd, SIOCGIWRATE, &iwreq) == 0) { ifprops[i].type = 'w'; // type wireless ifprops[i].fullduplex = 0; ifprops[i].speed = (iwreq.u.bitrate.value + 500000) / 1000000; if (++i >= MAXINTF-1) break; else continue; } ifprops[i].type = '?'; // type unknown ifprops[i].fullduplex = 0; ifprops[i].speed = 0; if (++i >= MAXINTF-1) break; } close(sockfd); fclose(fp); } atop-2.4.0/ifprop.h0000664000203100020310000000042713416466037013447 0ustar gerlofgerlofstruct ifprop { char type; /* type: 'e' (ethernet) */ /* 'w' (wireless) */ char name[31]; /* name of interface */ long int speed; /* in megabits per second */ char fullduplex; /* boolean */ }; int getifprop(struct ifprop *); void initifprop(void); atop-2.4.0/netatopd.h0000664000203100020310000000065313416466037013767 0ustar gerlofgerlof#define SEMAKEY 1541961 #define NETEXITFILE "/var/run/netatop.log" #define MYMAGIC (unsigned int) 0xfeedb0b0 struct naheader { u_int32_t magic; // magic number MYMAGIC u_int32_t curseq; // sequence number of last netpertask u_int16_t hdrlen; // length of this header u_int16_t ntplen; // length of netpertask structure pid_t mypid; // PID of netatopd itself }; atop-2.4.0/netatop.h0000664000203100020310000000225413416466037013622 0ustar gerlofgerlof#define COMLEN 16 struct taskcount { unsigned long long tcpsndpacks; unsigned long long tcpsndbytes; unsigned long long tcprcvpacks; unsigned long long tcprcvbytes; unsigned long long udpsndpacks; unsigned long long udpsndbytes; unsigned long long udprcvpacks; unsigned long long udprcvbytes; /* space for future extensions */ }; struct netpertask { pid_t id; // tgid or tid (depending on command) unsigned long btime; char command[COMLEN]; struct taskcount tc; }; /* ** getsocktop commands */ #define NETATOP_BASE_CTL 15661 // just probe if the netatop module is active #define NETATOP_PROBE (NETATOP_BASE_CTL) // force garbage collection to make finished processes available #define NETATOP_FORCE_GC (NETATOP_BASE_CTL+1) // wait until all finished processes are read (blocks until done) #define NETATOP_EMPTY_EXIT (NETATOP_BASE_CTL+2) // get info for finished process (blocks until available) #define NETATOP_GETCNT_EXIT (NETATOP_BASE_CTL+3) // get counters for thread group (i.e. process): input is 'id' (pid) #define NETATOP_GETCNT_TGID (NETATOP_BASE_CTL+4) // get counters for thread: input is 'id' (tid) #define NETATOP_GETCNT_PID (NETATOP_BASE_CTL+5) atop-2.4.0/netatopif.c0000664000203100020310000002633713416466037014144 0ustar gerlofgerlof/* ** 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 functions to interface with the netatop ** module in the kernel. That module keeps track of network activity ** per process and thread. ** ================================================================ ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Date: August/September 2012 ** ** 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "atop.h" #include "photoproc.h" #include "netatop.h" #include "netatopd.h" static int netsock = -1; static int netexitfd = -1; static struct naheader *nahp; static int semid = -1; static unsigned long lastseq; /* ** storage of last exited tasks read from exitfile ** every exitstore struct is registered in hash buckets, ** by its pid or by its begintime */ struct exitstore { struct exitstore *next; unsigned char isused; struct netpertask npt; }; #define NHASH 1024 // must be power of two! #define HASHCALC(x) ((x)&(NHASH-1)) static struct exitstore *esbucket[NHASH]; static struct exitstore *exitall; static int exitnum; static char exithash; static void fill_networkcnt(struct tstat *, struct tstat *, struct exitstore *); /* ** open a raw socket to the IP layer (root privs required) */ void netatop_ipopen(void) { netsock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW); } /* ** check if at this moment the netatop kernel module is loaded and ** the netatopd daemon is active */ void netatop_probe(void) { struct sembuf semdecr = {1, -1, SEM_UNDO}; socklen_t sl = 0; struct stat exstat; /* ** check if IP socket is open */ if (netsock == -1) return; /* ** probe if the netatop module is active */ if ( getsockopt(netsock, SOL_IP, NETATOP_PROBE, NULL, &sl) != 0) { supportflags &= ~NETATOP; supportflags &= ~NETATOPD; return; } // set appropriate support flag supportflags |= NETATOP; /* ** check if the netatopd daemon is active to register exited tasks ** and decrement semaphore to indicate that we want to subscribe */ if (semid == -1) { if ( (semid = semget(SEMAKEY, 0, 0)) == -1 || semop(semid, &semdecr, 1) == -1 ) { supportflags &= ~NETATOPD; return; } } if (semctl(semid, 0, GETVAL, 0) != 1) { supportflags &= ~NETATOPD; return; } /* ** check if exitfile still open and not removed by netatopd */ if (netexitfd != -1) { if ( fstat(netexitfd, &exstat) == 0 && exstat.st_nlink > 0 ) // not removed { supportflags |= NETATOPD; return; } else { (void) close(netexitfd); if (nahp) munmap(nahp, sizeof *nahp); netexitfd = -1; nahp = NULL; } } /* ** open file with compressed stats of exited tasks ** and (re)mmap the start record, mainly to obtain current sequence */ if (netexitfd == -1) { if ( (netexitfd = open(NETEXITFILE, O_RDONLY, 0)) == -1) { supportflags &= ~NETATOPD; return; } } if ( (nahp = mmap((void *)0, sizeof *nahp, PROT_READ, MAP_SHARED, netexitfd, 0)) == (void *) -1) { (void) close(netexitfd); netexitfd = -1; nahp = NULL; supportflags &= ~NETATOPD; return; } /* ** if this is a new incarnation of the netatopd daemon, ** position seek pointer on first task that is relevant to us ** and remember last sequence number to know where to start */ (void) lseek(netexitfd, 0, SEEK_END); lastseq = nahp->curseq; // set appropriate support flag supportflags |= NETATOPD; } void netatop_signoff(void) { struct sembuf semincr = {1, +1, SEM_UNDO}; if (netsock == -1 || nahp == NULL) return; if (supportflags & NETATOPD) { regainrootprivs(); (void) semop(semid, &semincr, 1); kill(nahp->mypid, SIGHUP); if (! droprootprivs()) cleanstop(42); (void) munmap(nahp, sizeof *nahp); (void) close(netexitfd); } } /* ** read network counters for one existing task ** (type 'g' for thread group or type 't' for thread) */ void netatop_gettask(pid_t id, char type, struct tstat *tp) { struct netpertask npt; socklen_t socklen = sizeof npt; int cmd = (type == 'g' ? NETATOP_GETCNT_TGID : NETATOP_GETCNT_PID); /* ** if kernel module netatop not active on this system, skip call */ if (!(supportflags & NETATOP) ) { memset(&tp->net, 0, sizeof tp->net); return; } /* ** get statistics of this process/thread */ npt.id = id; regainrootprivs(); if (getsockopt(netsock, SOL_IP, cmd, &npt, &socklen) != 0) { memset(&tp->net, 0, sizeof tp->net); if (! droprootprivs()) cleanstop(42); if (errno == ENOPROTOOPT || errno == EPERM) { supportflags &= ~NETATOP; supportflags &= ~NETATOPD; close(netsock); netsock = -1; } return; } if (! droprootprivs()) cleanstop(42); /* ** statistics available: fill counters */ tp->net.tcpsnd = npt.tc.tcpsndpacks; tp->net.tcprcv = npt.tc.tcprcvpacks; tp->net.tcpssz = npt.tc.tcpsndbytes; tp->net.tcprsz = npt.tc.tcprcvbytes; tp->net.udpsnd = npt.tc.udpsndpacks; tp->net.udprcv = npt.tc.udprcvpacks; tp->net.udpssz = npt.tc.udpsndbytes; tp->net.udprsz = npt.tc.udprcvbytes; } /* ** read all exited processes that have been added to the exitfile ** and store them into memory */ unsigned int netatop_exitstore(void) { socklen_t socklen = 0, nexitnet, sz, nr=0; unsigned long uncomplen; unsigned char nextsize; unsigned char readbuf[nahp->ntplen+100]; unsigned char databuf[nahp->ntplen]; struct netpertask *tmp = (struct netpertask *)databuf; struct exitstore *esp; regainrootprivs(); /* ** force garbage collection: ** netatop module builds new list of exited processes that ** can be read by netatopd and written to exitfile */ if (getsockopt(netsock, SOL_IP, NETATOP_FORCE_GC, NULL, &socklen)!=0) { if (! droprootprivs()) cleanstop(42); if (errno == ENOPROTOOPT || errno == EPERM) { supportflags &= ~NETATOP; supportflags &= ~NETATOPD; close(netsock); netsock = -1; } return 0; } /* ** wait until list of exited processes is read by netatopd ** and available to be read by atop */ if (getsockopt(netsock, SOL_IP, NETATOP_EMPTY_EXIT, 0, &socklen) !=0) { if (! droprootprivs()) cleanstop(42); if (errno == ENOPROTOOPT || errno == EPERM) { supportflags &= ~NETATOP; supportflags &= ~NETATOPD; close(netsock); netsock = -1; } return 0; } if (! droprootprivs()) cleanstop(42); /* ** verify how many exited processes are available to be read ** from the exitfile */ nexitnet = nahp->curseq - lastseq; lastseq = nahp->curseq; /* ** allocate storage for all exited processes */ exitall = malloc(nexitnet * sizeof(struct exitstore)); ptrverify(exitall, "Malloc failed for %d exited netprocs\n", nexitnet); memset(exitall, 0, nexitnet * sizeof(struct exitstore)); esp = exitall; /* ** read next byte from exitfile that specifies the length ** of the next record */ if ( read(netexitfd, &nextsize, 1) != 1) return 0; /* ** read the next record and (if possible) the byte specifying ** the size of the next record */ while ( (sz = read(netexitfd, readbuf, nextsize+1)) >= nextsize) { /* ** decompress record and store it */ uncomplen = nahp->ntplen; if (nahp->ntplen <= sizeof(struct netpertask)) { (void) uncompress((Byte *)&(esp->npt), &uncomplen, readbuf, nextsize); } else { (void) uncompress((Byte *)databuf, &uncomplen, readbuf, nextsize); esp->npt = *tmp; } esp++; nr++; /* ** check if we have read all records */ if (nr == nexitnet) { /* ** if we have read one byte too many: ** reposition seek pointer */ if (sz > nextsize) (void) lseek(netexitfd, -1, SEEK_CUR); break; } /* ** prepare reading next record */ if (sz > nextsize) nextsize = readbuf[nextsize]; else break; // unexpected: more requested than available } exitnum = nr; return nr; } /* ** remove all stored exited processes from the hash bucket list */ void netatop_exiterase(void) { free(exitall); memset(esbucket, 0, sizeof esbucket); exitnum = 0; } /* ** add all stored tasks to a hash bucket, either ** by pid (argument 'p') or by begintime (argument 'b') */ void netatop_exithash(char hashtype) { int i, h; struct exitstore *esp; for (i=0, esp=exitall; i < exitnum; i++, esp++) { if (hashtype == 'p') h = HASHCALC(esp->npt.id); else h = HASHCALC(esp->npt.btime); esp->next = esbucket[h]; esbucket[h] = esp; } exithash = hashtype; } /* ** search for relevant exited network task and ** update counters in tstat struct */ void netatop_exitfind(unsigned long key, struct tstat *dev, struct tstat *pre) { int h = HASHCALC(key); struct exitstore *esp; /* ** if bucket empty, forget about it */ if ( (esp = esbucket[h]) == NULL) return; /* ** search thru hash bucket list */ for (; esp; esp=esp->next) { switch (exithash) { case 'p': // search by PID if (key != esp->npt.id) continue; /* ** correct PID found */ fill_networkcnt(dev, pre, esp); break; case 'b': // search by begintime if (esp->isused) continue; if (key != esp->npt.btime) continue; /* ** btime is okay; additional checks required */ if ( strcmp(esp->npt.command, pre->gen.name) != 0) continue; if (esp->npt.tc.tcpsndpacks < pre->net.tcpsnd || esp->npt.tc.tcpsndbytes < pre->net.tcpssz || esp->npt.tc.tcprcvpacks < pre->net.tcprcv || esp->npt.tc.tcprcvbytes < pre->net.tcprsz || esp->npt.tc.udpsndpacks < pre->net.udpsnd || esp->npt.tc.udpsndbytes < pre->net.udpssz || esp->npt.tc.udprcvpacks < pre->net.udprcv || esp->npt.tc.udprcvbytes < pre->net.udprsz ) continue; esp->isused = 1; fill_networkcnt(dev, pre, esp); break; } } } static void fill_networkcnt(struct tstat *dev, struct tstat *pre, struct exitstore *esp) { dev->net.tcpsnd = esp->npt.tc.tcpsndpacks - pre->net.tcpsnd; dev->net.tcpssz = esp->npt.tc.tcpsndbytes - pre->net.tcpssz; dev->net.tcprcv = esp->npt.tc.tcprcvpacks - pre->net.tcprcv; dev->net.tcprsz = esp->npt.tc.tcprcvbytes - pre->net.tcprsz; dev->net.udpsnd = esp->npt.tc.udpsndpacks - pre->net.udpsnd; dev->net.udpssz = esp->npt.tc.udpsndbytes - pre->net.udpssz; dev->net.udprcv = esp->npt.tc.udprcvpacks - pre->net.udprcv; dev->net.udprsz = esp->npt.tc.udprcvbytes - pre->net.udprsz; } atop-2.4.0/netlink.c0000664000203100020310000001172213416466037013607 0ustar gerlofgerlof#include #include #include #include #include #include #include #include #include #include #include #include #include /* ** generic macro's */ #define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN)) #define GENLMSG_PAYLOAD(glh) (NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN) #define NLA_DATA(na) ((void *)((char*)(na) + NLA_HDRLEN)) #define NLA_PAYLOAD(len) (len - NLA_HDRLEN) /* ** function prototypes */ static int nlsock_open(void); static int nlsock_sendcmd(int, __u16, __u32, __u8, __u16, void *, int); static int nlsock_getfam(int); static int getnumcpu(void); /* ** message format to communicate with NETLINK */ struct msgtemplate { struct nlmsghdr n; struct genlmsghdr g; char buf[2048]; }; int netlink_open(void) { int nlsock, famid; char cpudef[64]; /* ** open the netlink socket */ nlsock = nlsock_open(); /* ** get the family id for the TASKSTATS family */ famid = nlsock_getfam(nlsock); /* ** determine maximum number of CPU's for this system ** and specify mask to register all cpu's */ sprintf(cpudef, "0-%d", getnumcpu() -1); /* ** indicate to listen for processes from all CPU's */ if (nlsock_sendcmd(nlsock, famid, getpid(), TASKSTATS_CMD_GET, TASKSTATS_CMD_ATTR_REGISTER_CPUMASK, &cpudef, strlen(cpudef)+1) == -1) { fprintf(stderr, "register cpumask failed\n"); return -1; } return nlsock; } int netlink_recv(int nlsock, int flags) { int len; struct msgtemplate msg; if ( (len = recv(nlsock, &msg, sizeof msg, flags)) == -1) return -errno; // negative: errno if (msg.n.nlmsg_type == NLMSG_ERROR || !NLMSG_OK(&msg.n, len)) { struct nlmsgerr *err = NLMSG_DATA(&msg); return err->error; // negative: errno } return len; // 0 or positive value } static int nlsock_getfam(int nlsock) { int len; struct nlattr *nlattr; struct msgtemplate msg; nlsock_sendcmd(nlsock, GENL_ID_CTRL, getpid(), CTRL_CMD_GETFAMILY, CTRL_ATTR_FAMILY_NAME, TASKSTATS_GENL_NAME, sizeof TASKSTATS_GENL_NAME); if ( (len = recv(nlsock, &msg, sizeof msg, 0)) == -1) { perror("receive NETLINK family"); exit(1); } if (msg.n.nlmsg_type == NLMSG_ERROR || !NLMSG_OK(&msg.n, len)) { struct nlmsgerr *err = NLMSG_DATA(&msg); fprintf(stderr, "receive NETLINK family, errno %d\n", err->error); exit(1); } nlattr = (struct nlattr *) GENLMSG_DATA(&msg); nlattr = (struct nlattr *) ((char *) nlattr + NLA_ALIGN(nlattr->nla_len)); if (nlattr->nla_type != CTRL_ATTR_FAMILY_ID) { fprintf(stderr, "unexpected family id\n"); exit(1); } return *(__u16 *) NLA_DATA(nlattr); } static int nlsock_open(void) { int nlsock, rcvsz = 256*1024; struct sockaddr_nl nlsockaddr; if ( (nlsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC) ) == -1) { perror("open NETLINK socket"); exit(1); } if (setsockopt(nlsock, SOL_SOCKET, SO_RCVBUF, &rcvsz, sizeof rcvsz) == -1) { perror("set length receive buffer"); exit(1); } memset(&nlsockaddr, 0, sizeof nlsockaddr); nlsockaddr.nl_family = AF_NETLINK; if (bind(nlsock, (struct sockaddr *) &nlsockaddr, sizeof nlsockaddr) == -1) { perror("bind NETLINK socket"); close(nlsock); exit(1); } return nlsock; } static int nlsock_sendcmd(int nlsock, __u16 nlmsg_type, __u32 nlmsg_pid, __u8 genl_cmd, __u16 nla_type, void *nla_data, int nla_len) { struct nlattr *na; struct sockaddr_nl nlsockaddr; int rv, buflen; char *buf; struct msgtemplate msg; msg.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); msg.n.nlmsg_type = nlmsg_type; msg.n.nlmsg_flags = NLM_F_REQUEST; msg.n.nlmsg_seq = 0; msg.n.nlmsg_pid = nlmsg_pid; msg.g.cmd = genl_cmd; msg.g.version = 0x1; na = (struct nlattr *) GENLMSG_DATA(&msg); na->nla_type = nla_type; na->nla_len = nla_len + 1 + NLA_HDRLEN; memcpy(NLA_DATA(na), nla_data, nla_len); msg.n.nlmsg_len += NLMSG_ALIGN(na->nla_len); buf = (char *) &msg; buflen = msg.n.nlmsg_len ; memset(&nlsockaddr, 0, sizeof(nlsockaddr)); nlsockaddr.nl_family = AF_NETLINK; while ((rv = sendto(nlsock, buf, buflen, 0, (struct sockaddr *) &nlsockaddr, sizeof(nlsockaddr))) < buflen) { if (rv == -1) { if (errno != EAGAIN) { perror("sendto NETLINK"); return -1; } } else { buf += rv; buflen -= rv; } } return 0; } static int getnumcpu(void) { FILE *fp; char linebuf[4096], label[256]; int cpunum, maxcpu = 0; if ( (fp = fopen("/proc/stat", "r")) != NULL) { while ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { sscanf(linebuf, "%255s", label); if ( strncmp("cpu", label, 3) == 0 && strlen(label) >3) { cpunum = atoi(&label[3]); if (maxcpu < cpunum) maxcpu = cpunum; } if ( strncmp("int", label, 3) == 0) break; } fclose(fp); } return maxcpu+1; } atop-2.4.0/netstats.h0000644000203100020310000000607513416466037014020 0ustar gerlofgerlof/* ** structures defined from the output of /proc/net/snmp and /proc/net/snmp6 */ struct ipv4_stats { count_t Forwarding; count_t DefaultTTL; count_t InReceives; count_t InHdrErrors; count_t InAddrErrors; count_t ForwDatagrams; count_t InUnknownProtos; count_t InDiscards; count_t InDelivers; count_t OutRequests; count_t OutDiscards; count_t OutNoRoutes; count_t ReasmTimeout; count_t ReasmReqds; count_t ReasmOKs; count_t ReasmFails; count_t FragOKs; count_t FragFails; count_t FragCreates; }; struct icmpv4_stats { count_t InMsgs; count_t InErrors; count_t InDestUnreachs; count_t InTimeExcds; count_t InParmProbs; count_t InSrcQuenchs; count_t InRedirects; count_t InEchos; count_t InEchoReps; count_t InTimestamps; count_t InTimestampReps; count_t InAddrMasks; count_t InAddrMaskReps; count_t OutMsgs; count_t OutErrors; count_t OutDestUnreachs; count_t OutTimeExcds; count_t OutParmProbs; count_t OutSrcQuenchs; count_t OutRedirects; count_t OutEchos; count_t OutEchoReps; count_t OutTimestamps; count_t OutTimestampReps; count_t OutAddrMasks; count_t OutAddrMaskReps; }; struct udpv4_stats { count_t InDatagrams; count_t NoPorts; count_t InErrors; count_t OutDatagrams; }; struct tcp_stats { count_t RtoAlgorithm; count_t RtoMin; count_t RtoMax; count_t MaxConn; count_t ActiveOpens; count_t PassiveOpens; count_t AttemptFails; count_t EstabResets; count_t CurrEstab; count_t InSegs; count_t OutSegs; count_t RetransSegs; count_t InErrs; count_t OutRsts; }; struct ipv6_stats { count_t Ip6InReceives; count_t Ip6InHdrErrors; count_t Ip6InTooBigErrors; count_t Ip6InNoRoutes; count_t Ip6InAddrErrors; count_t Ip6InUnknownProtos; count_t Ip6InTruncatedPkts; count_t Ip6InDiscards; count_t Ip6InDelivers; count_t Ip6OutForwDatagrams; count_t Ip6OutRequests; count_t Ip6OutDiscards; count_t Ip6OutNoRoutes; count_t Ip6ReasmTimeout; count_t Ip6ReasmReqds; count_t Ip6ReasmOKs; count_t Ip6ReasmFails; count_t Ip6FragOKs; count_t Ip6FragFails; count_t Ip6FragCreates; count_t Ip6InMcastPkts; count_t Ip6OutMcastPkts; }; struct icmpv6_stats { count_t Icmp6InMsgs; count_t Icmp6InErrors; count_t Icmp6InDestUnreachs; count_t Icmp6InPktTooBigs; count_t Icmp6InTimeExcds; count_t Icmp6InParmProblems; count_t Icmp6InEchos; count_t Icmp6InEchoReplies; count_t Icmp6InGroupMembQueries; count_t Icmp6InGroupMembResponses; count_t Icmp6InGroupMembReductions; count_t Icmp6InRouterSolicits; count_t Icmp6InRouterAdvertisements; count_t Icmp6InNeighborSolicits; count_t Icmp6InNeighborAdvertisements; count_t Icmp6InRedirects; count_t Icmp6OutMsgs; count_t Icmp6OutDestUnreachs; count_t Icmp6OutPktTooBigs; count_t Icmp6OutTimeExcds; count_t Icmp6OutParmProblems; count_t Icmp6OutEchoReplies; count_t Icmp6OutRouterSolicits; count_t Icmp6OutNeighborSolicits; count_t Icmp6OutNeighborAdvertisements; count_t Icmp6OutRedirects; count_t Icmp6OutGroupMembResponses; count_t Icmp6OutGroupMembReductions; }; struct udpv6_stats { count_t Udp6InDatagrams; count_t Udp6NoPorts; count_t Udp6InErrors; count_t Udp6OutDatagrams; }; atop-2.4.0/parseable.c0000664000203100020310000004563413416466037014112 0ustar gerlofgerlof/* ** 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. ** ** ========================================================================== ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Date: February 2007 ** -------------------------------------------------------------------------- ** Copyright (C) 2007-2010 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 ** -------------------------------------------------------------------------- ** ** $Id: parseable.c,v 1.13 2010/10/23 14:02:19 gerlof Exp $ ** $Log: parseable.c,v $ ** Revision 1.13 2010/10/23 14:02:19 gerlof ** Show counters for total number of running and sleep (S and D) threads. ** ** Revision 1.12 2010/05/18 19:20:55 gerlof ** Introduce CPU frequency and scaling (JC van Winkel). ** ** Revision 1.11 2010/04/23 12:19:35 gerlof ** Modified mail-address in header. ** ** Revision 1.10 2010/03/04 10:52:21 gerlof ** Support I/O-statistics on logical volumes and MD devices. ** ** Revision 1.9 2010/01/08 14:46:42 gerlof ** Added label RESET in case of a sample with values since boot. ** ** Revision 1.8 2009/12/19 22:32:14 gerlof ** Add new counters to parseable output. ** ** Revision 1.7 2008/03/06 09:08:29 gerlof ** Bug-solution regarding parseable output of PPID. ** ** Revision 1.6 2008/03/06 08:38:03 gerlof ** Register/show ppid of a process. ** ** Revision 1.5 2008/01/18 08:03:40 gerlof ** Show information about the number of threads in state 'running', ** 'interruptible sleeping' and 'non-interruptible sleeping'. ** ** Revision 1.4 2007/12/11 13:33:12 gerlof ** Cosmetic change. ** ** Revision 1.3 2007/08/16 12:00:11 gerlof ** Add support for atopsar reporting. ** Concerns networking-counters that have been changed. ** ** Revision 1.2 2007/03/20 13:01:12 gerlof ** Introduction of variable supportflags. ** ** Revision 1.1 2007/02/19 11:55:43 gerlof ** Initial revision ** */ #include #include #include #include #include #include #include "atop.h" #include "photosyst.h" #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_PRG(); void print_PRC(); void print_PRM(); void print_PRD(); void print_PRN(); void print_PRE(); /* ** table with possible labels and the corresponding ** print-function for parseable output */ struct labeldef { char *label; int valid; void (*prifunc)(char *, struct sstat *, struct tstat *, int); }; static struct labeldef labeldef[] = { { "CPU", 0, print_CPU }, { "cpu", 0, print_cpu }, { "CPL", 0, print_CPL }, { "GPU", 0, print_GPU }, { "MEM", 0, print_MEM }, { "SWP", 0, print_SWP }, { "PAG", 0, print_PAG }, { "PSI", 0, print_PSI }, { "LVM", 0, print_LVM }, { "MDD", 0, print_MDD }, { "DSK", 0, print_DSK }, { "NFM", 0, print_NFM }, { "NFC", 0, print_NFC }, { "NFS", 0, print_NFS }, { "NET", 0, print_NET }, { "IFB", 0, print_IFB }, { "PRG", 0, print_PRG }, { "PRC", 0, print_PRC }, { "PRM", 0, print_PRM }, { "PRD", 0, print_PRD }, { "PRN", 0, print_PRN }, { "PRE", 0, print_PRE }, }; static int numlabels = sizeof labeldef/sizeof(struct labeldef); /* ** analyse the parse-definition string that has been ** passed as argument with the flag -P */ int parsedef(char *pd) { register int i; char *p, *ep = pd + strlen(pd); /* ** check if string passed bahind -P is not another flag */ if (*pd == '-') { fprintf(stderr, "flag -P should be followed by label list\n"); return 0; } /* ** check list of comma-separated labels */ while (pd < ep) { /* ** exchange comma by null-byte */ if ( (p = strchr(pd, ',')) ) *p = 0; else p = ep-1; /* ** check if the next label exists */ for (i=0; i < numlabels; i++) { if ( strcmp(labeldef[i].label, pd) == 0) { labeldef[i].valid = 1; break; } } /* ** non-existing label has been used */ if (i == numlabels) { /* ** check if special label 'ALL' has been used */ if ( strcmp("ALL", pd) == 0) { for (i=0; i < numlabels; i++) labeldef[i].valid = 1; break; } else { fprintf(stderr, "label %s not found\n", pd); return 0; } } pd = p+1; } setbuf(stdout, (char *)0); return 1; } /* ** produce parseable output for an interval */ char parseout(time_t curtime, int numsecs, struct devtstat *devtstat, struct sstat *sstat, int nexit, unsigned int noverflow, char flag) { register int i; char datestr[32], timestr[32], header[256]; /* ** print reset-label for sample-values since boot */ if (flag&RRBOOT) printf("RESET\n"); /* ** search all labels which are selected before */ for (i=0; i < numlabels; i++) { if (labeldef[i].valid) { /* ** prepare generic columns */ convdate(curtime, datestr); convtime(curtime, timestr); snprintf(header, sizeof header, "%s %s %ld %s %s %d", labeldef[i].label, utsname.nodename, curtime, datestr, timestr, numsecs); /* ** call a selected print-function */ (labeldef[i].prifunc)(header, sstat, devtstat->taskall, devtstat->ntaskall); } } /* ** print separator */ printf("SEP\n"); return '\0'; } /* ** print functions for system-level statistics */ void calc_freqscale(count_t maxfreq, count_t cnt, count_t ticks, count_t *freq, int *freqperc) { // if ticks != 0, do full calcs if (maxfreq && ticks) { *freq=cnt/ticks; *freqperc=100* *freq / maxfreq; } else if (maxfreq) // max frequency is known so % can be calculated { *freq=cnt; *freqperc=100*cnt/maxfreq; } else if (cnt) // no max known, set % to 100 { *freq=cnt; *freqperc=100; } else // nothing is known: set freq to 0, % to 100 { *freq=0; *freqperc=100; } } void print_CPU(char *hp, struct sstat *ss, struct tstat *ps, int nact) { count_t maxfreq=0; count_t cnt=0; count_t ticks=0; count_t freq; int freqperc; int i; // calculate average clock frequency for (i=0; i < ss->cpu.nrcpu; i++) { cnt += ss->cpu.cpu[i].freqcnt.cnt; ticks += ss->cpu.cpu[i].freqcnt.ticks; } maxfreq = ss->cpu.cpu[0].freqcnt.maxfreq; calc_freqscale(maxfreq, cnt, ticks, &freq, &freqperc); if (ss->cpu.all.instr == 1) { ss->cpu.all.instr = 0; ss->cpu.all.cycle = 0; } printf("%s %u %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %d %lld %lld\n", hp, hertz, ss->cpu.nrcpu, ss->cpu.all.stime, ss->cpu.all.utime, ss->cpu.all.ntime, ss->cpu.all.itime, ss->cpu.all.wtime, ss->cpu.all.Itime, ss->cpu.all.Stime, ss->cpu.all.steal, ss->cpu.all.guest, freq, freqperc, ss->cpu.all.instr, ss->cpu.all.cycle ); } void print_cpu(char *hp, struct sstat *ss, struct tstat *ps, int nact) { register int i; count_t maxfreq=0; count_t cnt=0; count_t ticks=0; count_t freq; int freqperc; for (i=0; i < ss->cpu.nrcpu; i++) { cnt = ss->cpu.cpu[i].freqcnt.cnt; ticks = ss->cpu.cpu[i].freqcnt.ticks; maxfreq= ss->cpu.cpu[0].freqcnt.maxfreq; calc_freqscale(maxfreq, cnt, ticks, &freq, &freqperc); printf("%s %u %d %lld %lld %lld " "%lld %lld %lld %lld %lld %lld %lld %d %lld %lld\n", hp, hertz, i, ss->cpu.cpu[i].stime, ss->cpu.cpu[i].utime, ss->cpu.cpu[i].ntime, ss->cpu.cpu[i].itime, ss->cpu.cpu[i].wtime, ss->cpu.cpu[i].Itime, ss->cpu.cpu[i].Stime, ss->cpu.cpu[i].steal, ss->cpu.cpu[i].guest, freq, freqperc, ss->cpu.cpu[i].instr, ss->cpu.cpu[i].cycle ); } } void print_CPL(char *hp, struct sstat *ss, struct tstat *ps, int nact) { printf("%s %lld %.2f %.2f %.2f %lld %lld\n", hp, ss->cpu.nrcpu, ss->cpu.lavg1, ss->cpu.lavg5, ss->cpu.lavg15, ss->cpu.csw, ss->cpu.devint); } void print_GPU(char *hp, struct sstat *ss, struct tstat *ps, int nact) { int i; for (i=0; i < ss->gpu.nrgpus; i++) { printf("%s %d %s %s %d %d %lld %lld %lld %lld %lld %lld\n", hp, i, ss->gpu.gpu[i].busid, ss->gpu.gpu[i].type, ss->gpu.gpu[i].gpupercnow, ss->gpu.gpu[i].mempercnow, ss->gpu.gpu[i].memtotnow, ss->gpu.gpu[i].memusenow, ss->gpu.gpu[i].samples, ss->gpu.gpu[i].gpuperccum, ss->gpu.gpu[i].memperccum, ss->gpu.gpu[i].memusecum); } } void print_MEM(char *hp, struct sstat *ss, struct tstat *ps, int nact) { printf( "%s %u %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld\n", hp, pagesize, ss->mem.physmem, ss->mem.freemem, ss->mem.cachemem, ss->mem.buffermem, ss->mem.slabmem, ss->mem.cachedrt, ss->mem.slabreclaim, ss->mem.vmwballoon, ss->mem.shmem, ss->mem.shmrss, ss->mem.shmswp, ss->mem.hugepagesz, ss->mem.tothugepage, ss->mem.freehugepage); } void print_SWP(char *hp, struct sstat *ss, struct tstat *ps, int nact) { printf( "%s %u %lld %lld %lld %lld %lld\n", hp, pagesize, ss->mem.totswap, ss->mem.freeswap, (long long)0, ss->mem.committed, ss->mem.commitlim); } void print_PAG(char *hp, struct sstat *ss, struct tstat *ps, int nact) { printf("%s %u %lld %lld %lld %lld %lld\n", hp, pagesize, ss->mem.pgscans, ss->mem.allocstall, (long long)0, ss->mem.swins, ss->mem.swouts); } void print_PSI(char *hp, struct sstat *ss, struct tstat *ps, int nact) { printf("%s %c %.1f %.1f %.1f %llu %.1f %.1f %.1f %llu " "%.1f %.1f %.1f %llu %.1f %.1f %.1f %llu %.1f %.1f %.1f %llu\n", hp, ss->psi.present ? 'y' : 'n', ss->psi.cpusome.avg10, ss->psi.cpusome.avg60, ss->psi.cpusome.avg300, ss->psi.cpusome.total, ss->psi.memsome.avg10, ss->psi.memsome.avg60, ss->psi.memsome.avg300, ss->psi.memsome.total, ss->psi.memfull.avg10, ss->psi.memfull.avg60, ss->psi.memfull.avg300, ss->psi.memfull.total, ss->psi.iosome.avg10, ss->psi.iosome.avg60, ss->psi.iosome.avg300, ss->psi.iosome.total, ss->psi.iofull.avg10, ss->psi.iofull.avg60, ss->psi.iofull.avg300, ss->psi.iofull.total); } void print_LVM(char *hp, struct sstat *ss, struct tstat *ps, int nact) { register int i; for (i=0; ss->dsk.lvm[i].name[0]; i++) { printf( "%s %s %lld %lld %lld %lld %lld\n", hp, ss->dsk.lvm[i].name, ss->dsk.lvm[i].io_ms, ss->dsk.lvm[i].nread, ss->dsk.lvm[i].nrsect, ss->dsk.lvm[i].nwrite, ss->dsk.lvm[i].nwsect); } } void print_MDD(char *hp, struct sstat *ss, struct tstat *ps, int nact) { register int i; for (i=0; ss->dsk.mdd[i].name[0]; i++) { printf( "%s %s %lld %lld %lld %lld %lld\n", hp, ss->dsk.mdd[i].name, ss->dsk.mdd[i].io_ms, ss->dsk.mdd[i].nread, ss->dsk.mdd[i].nrsect, ss->dsk.mdd[i].nwrite, ss->dsk.mdd[i].nwsect); } } void print_DSK(char *hp, struct sstat *ss, struct tstat *ps, int nact) { register int i; for (i=0; ss->dsk.dsk[i].name[0]; i++) { printf( "%s %s %lld %lld %lld %lld %lld\n", hp, ss->dsk.dsk[i].name, ss->dsk.dsk[i].io_ms, ss->dsk.dsk[i].nread, ss->dsk.dsk[i].nrsect, ss->dsk.dsk[i].nwrite, ss->dsk.dsk[i].nwsect); } } void print_NFM(char *hp, struct sstat *ss, struct tstat *ps, int nact) { register int i; for (i=0; i < ss->nfs.nfsmounts.nrmounts; i++) { printf("%s %s %lld %lld %lld %lld %lld %lld %lld %lld\n", hp, ss->nfs.nfsmounts.nfsmnt[i].mountdev, ss->nfs.nfsmounts.nfsmnt[i].bytestotread, ss->nfs.nfsmounts.nfsmnt[i].bytestotwrite, ss->nfs.nfsmounts.nfsmnt[i].bytesread, ss->nfs.nfsmounts.nfsmnt[i].byteswrite, ss->nfs.nfsmounts.nfsmnt[i].bytesdread, ss->nfs.nfsmounts.nfsmnt[i].bytesdwrite, ss->nfs.nfsmounts.nfsmnt[i].pagesmread, ss->nfs.nfsmounts.nfsmnt[i].pagesmwrite); } } void print_NFC(char *hp, struct sstat *ss, struct tstat *ps, int nact) { printf( "%s %lld %lld %lld %lld %lld\n", hp, ss->nfs.client.rpccnt, ss->nfs.client.rpcread, ss->nfs.client.rpcwrite, ss->nfs.client.rpcretrans, ss->nfs.client.rpcautrefresh); } void print_NFS(char *hp, struct sstat *ss, struct tstat *ps, int nact) { printf( "%s %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld " "%lld %lld %lld %lld %lld\n", hp, ss->nfs.server.rpccnt, ss->nfs.server.rpcread, ss->nfs.server.rpcwrite, ss->nfs.server.nrbytes, ss->nfs.server.nwbytes, ss->nfs.server.rpcbadfmt, ss->nfs.server.rpcbadaut, ss->nfs.server.rpcbadcln, ss->nfs.server.netcnt, ss->nfs.server.nettcpcnt, ss->nfs.server.netudpcnt, ss->nfs.server.nettcpcon, ss->nfs.server.rchits, ss->nfs.server.rcmiss, ss->nfs.server.rcnoca); } void print_NET(char *hp, struct sstat *ss, struct tstat *ps, int nact) { register int i; printf( "%s %s %lld %lld %lld %lld %lld %lld %lld %lld\n", hp, "upper", ss->net.tcp.InSegs, ss->net.tcp.OutSegs, ss->net.udpv4.InDatagrams + ss->net.udpv6.Udp6InDatagrams, ss->net.udpv4.OutDatagrams + ss->net.udpv6.Udp6OutDatagrams, ss->net.ipv4.InReceives + ss->net.ipv6.Ip6InReceives, ss->net.ipv4.OutRequests + ss->net.ipv6.Ip6OutRequests, ss->net.ipv4.InDelivers + ss->net.ipv6.Ip6InDelivers, ss->net.ipv4.ForwDatagrams + ss->net.ipv6.Ip6OutForwDatagrams); for (i=0; ss->intf.intf[i].name[0]; i++) { printf( "%s %s %lld %lld %lld %lld %ld %d\n", hp, ss->intf.intf[i].name, ss->intf.intf[i].rpack, ss->intf.intf[i].rbyte, ss->intf.intf[i].spack, ss->intf.intf[i].sbyte, ss->intf.intf[i].speed, ss->intf.intf[i].duplex); } } void print_IFB(char *hp, struct sstat *ss, struct tstat *ps, int nact) { register int i; for (i=0; i < ss->ifb.nrports; i++) { printf( "%s %s %hd %hd %lld %lld %lld %lld %lld\n", hp, ss->ifb.ifb[i].ibname, ss->ifb.ifb[i].portnr, ss->ifb.ifb[i].lanes, ss->ifb.ifb[i].rate, ss->ifb.ifb[i].rcvb, ss->ifb.ifb[i].sndb, ss->ifb.ifb[i].rcvp, ss->ifb.ifb[i].sndp); } } /* ** print functions for process-level statistics */ void print_PRG(char *hp, struct sstat *ss, struct tstat *ps, int nact) { register int i, exitcode; for (i=0; i < nact; i++, ps++) { if (ps->gen.excode & 0xff) // killed by signal? exitcode = (ps->gen.excode & 0x7f) + 256; else 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\n", hp, ps->gen.pid, ps->gen.name, ps->gen.state, ps->gen.ruid, ps->gen.rgid, ps->gen.tgid, ps->gen.nthr, exitcode, ps->gen.btime, ps->gen.cmdline, ps->gen.ppid, ps->gen.nthrrun, ps->gen.nthrslpi, ps->gen.nthrslpu, ps->gen.euid, ps->gen.egid, ps->gen.suid, ps->gen.sgid, ps->gen.fsuid, ps->gen.fsgid, ps->gen.elaps, ps->gen.isproc ? 'y':'n', ps->gen.vpid, ps->gen.ctid, ps->gen.container[0] ? ps->gen.container:"-"); } } void print_PRC(char *hp, struct sstat *ss, struct tstat *ps, int nact) { register int i; for (i=0; i < nact; i++, ps++) { printf("%s %d (%s) %c %u %lld %lld %d %d %d %d %d %d %d %c\n", hp, ps->gen.pid, ps->gen.name, ps->gen.state, hertz, ps->cpu.utime, ps->cpu.stime, ps->cpu.nice, ps->cpu.prio, ps->cpu.rtprio, ps->cpu.policy, ps->cpu.curcpu, ps->cpu.sleepavg, ps->gen.tgid, ps->gen.isproc ? 'y':'n'); } } void print_PRM(char *hp, struct sstat *ss, struct tstat *ps, int nact) { register int i; for (i=0; i < nact; i++, ps++) { printf("%s %d (%s) %c %u %lld %lld %lld %lld %lld %lld " "%lld %lld %lld %lld %lld %d %c %lld\n", hp, ps->gen.pid, ps->gen.name, ps->gen.state, pagesize, ps->mem.vmem, ps->mem.rmem, ps->mem.vexec, ps->mem.vgrow, ps->mem.rgrow, ps->mem.minflt, ps->mem.majflt, ps->mem.vlibs, ps->mem.vdata, ps->mem.vstack, ps->mem.vswap, ps->gen.tgid, ps->gen.isproc ? 'y':'n', ps->mem.pmem == (unsigned long long)-1LL ? 0:ps->mem.pmem); } } void print_PRD(char *hp, struct sstat *ss, struct tstat *ps, int nact) { register int i; for (i=0; i < nact; i++, ps++) { printf("%s %d (%s) %c %c %c %lld %lld %lld %lld %lld %d n %c\n", hp, ps->gen.pid, ps->gen.name, ps->gen.state, 'n', supportflags & IOSTAT ? 'y' : 'n', ps->dsk.rio, ps->dsk.rsz, ps->dsk.wio, ps->dsk.wsz, ps->dsk.cwsz, ps->gen.tgid, ps->gen.isproc ? 'y':'n'); } } void print_PRN(char *hp, struct sstat *ss, struct tstat *ps, int nact) { register int i; for (i=0; i < nact; i++, ps++) { printf("%s %d (%s) %c %c %lld %lld %lld %lld %lld %lld " "%lld %lld %d %d %d %c\n", hp, ps->gen.pid, ps->gen.name, ps->gen.state, supportflags & NETATOP ? 'y' : 'n', ps->net.tcpsnd, ps->net.tcpssz, ps->net.tcprcv, ps->net.tcprsz, ps->net.udpsnd, ps->net.udpssz, ps->net.udprcv, ps->net.udprsz, 0, 0, ps->gen.tgid, ps->gen.isproc ? 'y':'n'); } } void print_PRE(char *hp, struct sstat *ss, struct tstat *ps, int nact) { register int i; for (i=0; i < nact; i++, ps++) { printf("%s %d (%s) %c %c %d %x %d %d %lld %lld %lld\n", hp, ps->gen.pid, ps->gen.name, ps->gen.state, ps->gpu.state == '\0' ? 'N':ps->gpu.state, ps->gpu.nrgpus, ps->gpu.gpulist, ps->gpu.gpubusy, ps->gpu.membusy, ps->gpu.memnow, ps->gpu.memcum, ps->gpu.sample); } } atop-2.4.0/parseable.h0000664000203100020310000000016313416466037014103 0ustar gerlofgerlofint parsedef(char *); char parseout(time_t, int, struct devtstat *, struct sstat *, int, unsigned int, char); atop-2.4.0/photoproc.c0000664000203100020310000004365313416466037014170 0ustar gerlofgerlof/* ** ATOP - System & Process Monitor ** ** The program 'atop' offers the possibility to view the activity of ** the system on system-level as well as process-/thread-level. ** ** This source-file contains functions to read the process-administration ** of every running process from kernel-space and extract the required ** activity-counters. ** ========================================================================== ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Date: November 1996 ** LINUX-port: June 2000 ** -------------------------------------------------------------------------- ** Copyright (C) 2000-2010 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 ** -------------------------------------------------------------------------- ** ** $Log: photoproc.c,v $ ** Revision 1.33 2010/04/23 12:19:35 gerlof ** Modified mail-address in header. ** ** Revision 1.32 2009/11/27 13:44:00 gerlof ** euid, suid, fsuid, egid, sgid and fsgid also registered. ** ** Revision 1.31 2008/03/06 08:38:14 gerlof ** Register/show ppid of a process. ** ** Revision 1.30 2008/01/18 07:36:29 gerlof ** Gather information about the state of the individual threads. ** ** Revision 1.29 2007/11/05 12:26:10 gerlof ** Detect disappearing /proc/stat file when process exits ** (credits: Rene Rebe). ** ** Revision 1.28 2007/03/27 10:53:59 gerlof ** Bug-solution: only allow IOSTAT when patches are not installed. ** ** Revision 1.27 2007/03/21 14:21:37 gerlof ** Handle io counters maintained from 2.6.20 ** ** Revision 1.26 2007/02/13 10:32:34 gerlof ** Removal of external declarations. ** ** Revision 1.25 2007/01/15 09:00:14 gerlof ** Add new function to count actual number of processes. ** ** Revision 1.24 2006/02/07 06:47:35 gerlof ** Removed swap-counter. ** ** Revision 1.23 2005/10/21 09:49:57 gerlof ** Per-user accumulation of resource consumption. ** ** Revision 1.22 2004/12/14 15:05:58 gerlof ** Implementation of patch-recognition for disk and network-statistics. ** ** Revision 1.21 2004/09/23 09:07:49 gerlof ** Solved segmentation fault by checking tval. ** ** Revision 1.20 2004/09/08 06:01:01 gerlof ** Correct the priority of a process by adding 100 (the kernel ** subtracts 100 when showing the value via /proc). ** ** Revision 1.19 2004/09/02 10:49:45 gerlof ** Added sleep-average to process-info. ** ** Revision 1.18 2004/08/31 09:51:36 gerlof ** Gather information about underlying threads. ** ** Revision 1.17 2003/07/07 09:26:59 gerlof ** Cleanup code (-Wall proof). ** ** Revision 1.16 2003/06/30 11:30:43 gerlof ** Enlarge counters to 'long long'. ** ** Revision 1.15 2003/02/06 12:09:23 gerlof ** Exchange tab-character in command-line by space. ** ** Revision 1.14 2003/01/24 14:19:39 gerlof ** Exchange newline byte in command-line by space. ** ** Revision 1.13 2003/01/17 14:21:41 root ** Change-directory to /proc to optimize opening /proc-files ** via relative path-names i.s.o. absolute path-names. ** ** Revision 1.12 2003/01/17 07:31:29 gerlof ** Store the full command-line for every process. ** ** Revision 1.11 2003/01/06 13:03:09 gerlof ** Improved command-name parsing (command-names containing a close-bracket ** were not parsed correctly). ** ** Revision 1.10 2002/10/03 11:12:39 gerlof ** Modify (effective) uid/gid to real uid/gid. ** ** Revision 1.9 2002/07/24 11:13:31 gerlof ** Changed to ease porting to other UNIX-platforms. ** ** Revision 1.8 2002/07/08 09:27:45 gerlof ** Avoid buffer overflow during sprintf by using snprintf. ** ** Revision 1.7 2002/01/22 13:39:53 gerlof ** Support for number of cpu's. ** ** Revision 1.6 2001/11/22 08:33:43 gerlof ** Add priority per process. ** ** Revision 1.5 2001/11/13 08:26:15 gerlof ** Small bug-fixes. ** ** Revision 1.4 2001/11/07 09:18:43 gerlof ** Use /proc instead of /dev/kmem for process-level statistics. ** ** Revision 1.3 2001/10/04 13:57:34 gerlof ** Explicit include of sched.h (i.s.o. linux/sched.h via linux/mm.h). ** ** Revision 1.2 2001/10/04 08:47:26 gerlof ** Improved verification of kernel-symbol addresses ** ** Revision 1.1 2001/10/02 10:43:29 gerlof ** Initial revision ** */ static const char rcsid[] = "$Id: photoproc.c,v 1.33 2010/04/23 12:19:35 gerlof Exp $"; #include #include #include #include #include #include #include #include #include "atop.h" #include "photoproc.h" #define SCANSTAT "%c %d %*d %*d %*d %*d " \ "%*d %lld %*d %lld %*d %lld " \ "%lld %*d %*d %d %d %*d " \ "%*d %ld %lld %lld %*d %*d " \ "%*d %*d %*d %*d %*d %*d " \ "%*d %*d %*d %*d %*d %*d " \ "%d %d %d " /* ATOP-extension line of /proc/pid/stat */ #define ATOPSTAT "%lld %llu %lld %llu %lld %llu %lld %llu " \ "%lld %llu %lld %llu %lld %lld" static int procstat(struct tstat *, unsigned long long, char); static int procstatus(struct tstat *); static int procio(struct tstat *); static int proccont(struct tstat *); static void proccmd(struct tstat *); static void procsmaps(struct tstat *); unsigned long photoproc(struct tstat *tasklist, int maxtask) { static int firstcall = 1; static unsigned long long bootepoch; register struct tstat *curtask; FILE *fp; DIR *dirp; struct dirent *entp; char origdir[1024], dockstat=0; unsigned long tval=0; /* ** one-time initialization stuff */ if (firstcall) { /* ** check if this kernel offers io-statistics per task */ regainrootprivs(); if ( (fp = fopen("/proc/1/io", "r")) ) { supportflags |= IOSTAT; fclose(fp); } if (! droprootprivs()) cleanstop(42); /* ** find epoch time of boot moment */ bootepoch = getboot(); firstcall = 0; } /* ** probe if the netatop module and (optionally) the ** netatopd daemon are active */ regainrootprivs(); netatop_probe(); if (! droprootprivs()) cleanstop(42); /* ** read all subdirectory-names below the /proc directory */ if ( getcwd(origdir, sizeof origdir) == NULL) { perror("save current dir"); cleanstop(53); } if ( chdir("/proc") == -1) { perror("change to /proc"); cleanstop(54); } dirp = opendir("."); while ( (entp = readdir(dirp)) && tval < maxtask ) { /* ** skip non-numerical names */ if (!isdigit(entp->d_name[0])) continue; /* ** change to the process' subdirectory */ if ( chdir(entp->d_name) != 0 ) continue; /* ** gather process-level information */ curtask = tasklist+tval; if ( !procstat(curtask, bootepoch, 1)) /* from /proc/pid/stat */ { if ( chdir("..") == -1); continue; } if ( !procstatus(curtask) ) /* from /proc/pid/status */ { if ( chdir("..") == -1); continue; } if ( !procio(curtask) ) /* from /proc/pid/io */ { if ( chdir("..") == -1); continue; } proccmd(curtask); /* from /proc/pid/cmdline */ dockstat += proccont(curtask); /* from /proc/pid/cpuset */ /* ** reading the smaps file for every process with every sample ** is a really 'expensive' from a CPU consumption point-of-view, ** so gathering this info is optional */ if (calcpss) procsmaps(curtask); /* from /proc/pid/smaps */ // read network stats from netatop netatop_gettask(curtask->gen.tgid, 'g', curtask); tval++; /* increment for process-level info */ /* ** if needed (when number of threads is larger than 1): ** read and fill new entries with thread-level info */ if (curtask->gen.nthr > 1) { DIR *dirtask; struct dirent *tent; curtask->gen.nthrrun = 0; curtask->gen.nthrslpi = 0; curtask->gen.nthrslpu = 0; /* ** open underlying task directory */ if ( chdir("task") == 0 ) { dirtask = opendir("."); while ((tent=readdir(dirtask)) && tvald_name[0] == '.' || chdir(tent->d_name) != 0 ) continue; if ( !procstat(curthr, bootepoch, 0)) { if ( chdir("..") == -1); continue; } if ( !procstatus(curthr) ) { if ( chdir("..") == -1); continue; } if ( !procio(curthr) ) { if ( chdir("..") == -1); continue; } strcpy(curthr->gen.container, curtask->gen.container); switch (curthr->gen.state) { case 'R': curtask->gen.nthrrun += 1; break; case 'S': curtask->gen.nthrslpi += 1; break; case 'D': curtask->gen.nthrslpu += 1; break; } curthr->gen.nthr = 1; // read network stats from netatop netatop_gettask(curthr->gen.pid, 't', curthr); // all stats read now tval++; /* increment thread-level */ if ( chdir("..") == -1); /* thread */ } closedir(dirtask); if ( chdir("..") == -1); /* leave task */ } } if ( chdir("..") == -1); /* leave process-level directry */ } closedir(dirp); if ( chdir(origdir) == -1) { perror(origdir); cleanstop(55); } if (dockstat) supportflags |= DOCKSTAT; else supportflags &= ~DOCKSTAT; return tval; } /* ** count number of tasks in the system, i.e. ** the number of processes plus the total number of threads */ unsigned long counttasks(void) { unsigned long nr=0; char linebuf[256]; FILE *fp; DIR *dirp; struct dirent *entp; char origdir[1024]; /* ** determine total number of threads */ if ( (fp = fopen("/proc/loadavg", "r")) != NULL) { if ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { if ( sscanf(linebuf, "%*f %*f %*f %*d/%lu", &nr) < 1) cleanstop(53); } else cleanstop(53); fclose(fp); } else cleanstop(53); /* ** add total number of processes */ if ( getcwd(origdir, sizeof origdir) == NULL) cleanstop(53); if ( chdir("/proc") == -1) cleanstop(53); dirp = opendir("."); while ( (entp = readdir(dirp)) ) { /* ** count subdirectory names under /proc starting with a digit */ if (isdigit(entp->d_name[0])) nr++; } closedir(dirp); if ( chdir(origdir) == -1) cleanstop(53); return nr; } /* ** open file "stat" and obtain required info */ static int procstat(struct tstat *curtask, unsigned long long bootepoch, char isproc) { FILE *fp; int nr; char line[4096], *p, *cmdhead, *cmdtail; if ( (fp = fopen("stat", "r")) == NULL) return 0; if ( (nr = fread(line, 1, sizeof line-1, fp)) == 0) { fclose(fp); return 0; } line[nr] = '\0'; // terminate string /* ** fetch command name */ cmdhead = strchr (line, '('); cmdtail = strrchr(line, ')'); if (!cmdhead || !cmdtail || cmdtail < cmdhead) // parsing failed? { fclose(fp); return 0; } if ( (nr = cmdtail-cmdhead-1) > PNAMLEN) nr = PNAMLEN; p = curtask->gen.name; memcpy(p, cmdhead+1, nr); *(p+nr) = 0; while ( (p = strchr(p, '\n')) != NULL) { *p = '?'; p++; } /* ** fetch other values */ curtask->gen.isproc = isproc; curtask->cpu.rtprio = 0; curtask->cpu.policy = 0; curtask->gen.excode = 0; sscanf(line, "%d", &(curtask->gen.pid)); /* fetch pid */ nr = sscanf(cmdtail+2, SCANSTAT, &(curtask->gen.state), &(curtask->gen.ppid), &(curtask->mem.minflt), &(curtask->mem.majflt), &(curtask->cpu.utime), &(curtask->cpu.stime), &(curtask->cpu.prio), &(curtask->cpu.nice), &(curtask->gen.btime), &(curtask->mem.vmem), &(curtask->mem.rmem), &(curtask->cpu.curcpu), &(curtask->cpu.rtprio), &(curtask->cpu.policy)); if (nr < 12) /* parsing failed? */ { fclose(fp); return 0; } /* ** normalization */ curtask->gen.btime = (curtask->gen.btime+bootepoch)/hertz; curtask->cpu.prio += 100; /* was subtracted by kernel */ curtask->mem.vmem /= 1024; curtask->mem.rmem *= pagesize/1024; fclose(fp); switch (curtask->gen.state) { case 'R': curtask->gen.nthrrun = 1; break; case 'S': curtask->gen.nthrslpi = 1; break; case 'D': curtask->gen.nthrslpu = 1; break; } return 1; } /* ** open file "status" and obtain required info */ static int procstatus(struct tstat *curtask) { FILE *fp; char line[4096]; if ( (fp = fopen("status", "r")) == NULL) return 0; curtask->gen.nthr = 1; /* for compat with 2.4 */ curtask->cpu.sleepavg = 0; /* for compat with 2.4 */ curtask->mem.vgrow = 0; /* calculated later */ curtask->mem.rgrow = 0; /* calculated later */ while (fgets(line, sizeof line, fp)) { if (memcmp(line, "Tgid:", 5) ==0) { sscanf(line, "Tgid: %d", &(curtask->gen.tgid)); continue; } if (memcmp(line, "Pid:", 4) ==0) { sscanf(line, "Pid: %d", &(curtask->gen.pid)); continue; } if (memcmp(line, "SleepAVG:", 9)==0) { sscanf(line, "SleepAVG: %d%%", &(curtask->cpu.sleepavg)); continue; } if (memcmp(line, "Uid:", 4)==0) { sscanf(line, "Uid: %d %d %d %d", &(curtask->gen.ruid), &(curtask->gen.euid), &(curtask->gen.suid), &(curtask->gen.fsuid)); continue; } if (memcmp(line, "Gid:", 4)==0) { sscanf(line, "Gid: %d %d %d %d", &(curtask->gen.rgid), &(curtask->gen.egid), &(curtask->gen.sgid), &(curtask->gen.fsgid)); continue; } if (memcmp(line, "envID:", 6) ==0) { sscanf(line, "envID: %d", &(curtask->gen.ctid)); continue; } if (memcmp(line, "VPid:", 5) ==0) { sscanf(line, "VPid: %d", &(curtask->gen.vpid)); continue; } if (memcmp(line, "Threads:", 8)==0) { sscanf(line, "Threads: %d", &(curtask->gen.nthr)); continue; } if (memcmp(line, "VmData:", 7)==0) { sscanf(line, "VmData: %lld", &(curtask->mem.vdata)); continue; } if (memcmp(line, "VmStk:", 6)==0) { sscanf(line, "VmStk: %lld", &(curtask->mem.vstack)); continue; } if (memcmp(line, "VmExe:", 6)==0) { sscanf(line, "VmExe: %lld", &(curtask->mem.vexec)); continue; } if (memcmp(line, "VmLib:", 6)==0) { sscanf(line, "VmLib: %lld", &(curtask->mem.vlibs)); continue; } if (memcmp(line, "VmSwap:", 7)==0) { sscanf(line, "VmSwap: %lld", &(curtask->mem.vswap)); continue; } if (memcmp(line, "SigQ:", 5)==0) break; } fclose(fp); return 1; } /* ** open file "io" (>= 2.6.20) and obtain required info */ #define IO_READ "read_bytes:" #define IO_WRITE "write_bytes:" #define IO_CWRITE "cancelled_write_bytes:" static int procio(struct tstat *curtask) { FILE *fp; char line[4096]; count_t dskrsz=0, dskwsz=0, dskcwsz=0; if (supportflags & IOSTAT) { regainrootprivs(); if ( (fp = fopen("io", "r")) ) { while (fgets(line, sizeof line, fp)) { if (memcmp(line, IO_READ, sizeof IO_READ -1) == 0) { sscanf(line, "%*s %llu", &dskrsz); dskrsz /= 512; // in sectors continue; } if (memcmp(line, IO_WRITE, sizeof IO_WRITE -1) == 0) { sscanf(line, "%*s %llu", &dskwsz); dskwsz /= 512; // in sectors continue; } if (memcmp(line, IO_CWRITE, sizeof IO_CWRITE -1) == 0) { sscanf(line, "%*s %llu", &dskcwsz); dskcwsz /= 512; // in sectors continue; } } fclose(fp); curtask->dsk.rsz = dskrsz; curtask->dsk.rio = dskrsz; // to enable sort curtask->dsk.wsz = dskwsz; curtask->dsk.wio = dskwsz; // to enable sort curtask->dsk.cwsz = dskcwsz; } if (! droprootprivs()) cleanstop(42); } return 1; } /* ** store the full command line; the command-line may contain: ** - null-bytes as a separator between the arguments ** - newlines (e.g. arguments for awk or sed) ** - tabs (e.g. arguments for awk or sed) ** these special bytes will be converted to spaces */ static void proccmd(struct tstat *curtask) { FILE *fp; register int i, nr; memset(curtask->gen.cmdline, 0, CMDLEN+1); if ( (fp = fopen("cmdline", "r")) != NULL) { register char *p = curtask->gen.cmdline; nr = fread(p, 1, CMDLEN, fp); fclose(fp); if (nr >= 0) /* anything read ? */ { for (i=0; i < nr-1; i++, p++) { switch (*p) { case '\0': case '\n': case '\t': *p = ' '; } } } } } /* ** store the Docker container ID, retrieved from the cpuset ** that could look like this: ** /system.slice/docker-af78216c2a230f1aa5dce56cbf[SNAP].scope (e.g. CentOS) ** /docker/af78216c2a230f1aa5dce56cbf[SNAP] (e.g. openSUSE and Ubuntu)) */ #define CIDPREFIX "docker" #define CIDSIZE 12 static int proccont(struct tstat *curtask) { FILE *fp; char line[80]; if ( (fp = fopen("cpuset", "r")) != NULL) { register char *p; if ( fgets(line, sizeof line, fp) ) { // default string (so if not used) is "/" if (line[1] && (p = strstr(line, CIDPREFIX)) ) { memcpy(curtask->gen.container, p + sizeof CIDPREFIX, CIDSIZE); fclose(fp); return 1; } } fclose(fp); } return 0; } /* ** open file "smaps" and obtain required info */ static void procsmaps(struct tstat *curtask) { FILE *fp; char line[4096]; count_t pssval; /* ** open the file (always succeeds, even if no root privs) */ regainrootprivs(); if ( (fp = fopen("smaps", "r")) ) { curtask->mem.pmem = 0; while (fgets(line, sizeof line, fp)) { if (memcmp(line, "Pss:", 4) != 0) continue; // PSS line found to be accumulated sscanf(line, "Pss: %llu", &pssval); curtask->mem.pmem += pssval; } /* ** verify if fgets returned NULL due to error i.s.o. EOF */ if (ferror(fp)) curtask->mem.pmem = (unsigned long long)-1LL; fclose(fp); } else { curtask->mem.pmem = (unsigned long long)-1LL; } if (! droprootprivs()) cleanstop(42); } atop-2.4.0/photoproc.h0000664000203100020310000001457513416466037014176 0ustar gerlofgerlof/* ** 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. ** ** Include-file describing process-level counters maintained and functions ** to access the process-database. ** ================================================================ ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Date: November 1996 ** LINUX-port: June 2000 ** ** 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. */ #define PNAMLEN 15 #define CMDLEN 255 /* ** structure containing only relevant process-info extracted ** from kernel's process-administration */ struct tstat { /* GENERAL TASK INFO */ struct gen { 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) */ } gen; /* CPU STATISTICS */ struct cpu { 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 ifuture[4]; /* reserved for future use */ count_t cfuture[4]; /* reserved for future use */ } cpu; /* DISK STATISTICS */ struct dsk { 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 { 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 cfuture[4]; /* reserved for future use */ } mem; /* NETWORK STATISTICS */ struct net { 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 { 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; }; struct pinfo { struct pinfo *phnext; /* next process in hash chain */ struct pinfo *prnext; /* next process in residue chain */ struct pinfo *prprev; /* prev process in residue chain */ struct tstat tstat; /* per-process statistics */ }; /* ** structure to maintains all deviation info related to one sample */ struct devtstat { struct tstat *taskall; struct tstat **procall; struct tstat **procactive; unsigned long ntaskall; unsigned long ntaskactive; unsigned long nprocall; unsigned long nprocactive; unsigned long totrun, totslpi, totslpu, totzombie; }; /* ** prototypes of process-database functions */ int pdb_gettask(int, char, time_t, struct pinfo **); void pdb_addtask(int, struct pinfo *); int pdb_deltask(int, char); int pdb_makeresidue(void); int pdb_cleanresidue(void); int pdb_srchresidue(struct tstat *, struct pinfo **); /* ** prototypes for raw process-statistics functions */ struct netpertask; void deviattask(struct tstat *, unsigned long, struct tstat *, unsigned long, struct devtstat *, struct sstat *); unsigned long photoproc(struct tstat *, int); unsigned long counttasks(void); atop-2.4.0/photosyst.c0000664000203100020310000015524413416466037014227 0ustar gerlofgerlof/* ** 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 functions to read all relevant system-level ** figures. ** ========================================================================== ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Date: November 1996 ** LINUX-port: June 2000 ** -------------------------------------------------------------------------- ** Copyright (C) 2000-2012 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 ** -------------------------------------------------------------------------- ** ** $Log: photosyst.c,v $ ** Revision 1.38 2010/11/19 07:40:40 gerlof ** Support of virtual disk vd... (kvm). ** ** Revision 1.37 2010/11/14 06:42:18 gerlof ** After opening /proc/cpuinfo, the file descriptor was not closed any more. ** ** Revision 1.36 2010/10/23 14:09:50 gerlof ** Add support for mmcblk disks (MMC/SD cardreaders) ** Credits: Anssi Hannula ** ** Revision 1.35 2010/05/18 19:20:30 gerlof ** Introduce CPU frequency and scaling (JC van Winkel). ** ** Revision 1.34 2010/04/23 12:19:35 gerlof ** Modified mail-address in header. ** ** Revision 1.33 2010/03/04 10:58:05 gerlof ** Added recognition of device-type /dev/fio... ** ** Revision 1.32 2010/03/04 10:52:47 gerlof ** Support I/O-statistics on logical volumes and MD devices. ** ** Revision 1.31 2009/12/17 11:59:16 gerlof ** Gather and display new counters: dirty cache and guest cpu usage. ** ** Revision 1.30 2008/02/25 13:47:00 gerlof ** Experimental code for HTTP statistics. ** ** Revision 1.29 2007/08/17 09:45:44 gerlof ** Experimental: gather info about HTTP statistics. ** ** Revision 1.28 2007/08/16 12:00:49 gerlof ** Add support for atopsar reporting. ** Gather more counters, mainly related to networking. ** ** Revision 1.27 2007/07/03 09:01:56 gerlof ** Support Apache-statistics. ** ** Revision 1.26 2007/02/13 10:32:28 gerlof ** Removal of external declarations. ** ** Revision 1.25 2007/02/13 09:29:57 gerlof ** Removal of external declarations. ** ** Revision 1.24 2007/01/22 14:57:12 gerlof ** Support of special disks used by virtual machines. ** ** Revision 1.23 2007/01/22 08:28:50 gerlof ** Support steal-time from /proc/stat. ** ** Revision 1.22 2006/11/13 13:48:20 gerlof ** Implement load-average counters, context-switches and interrupts. ** ** Revision 1.21 2006/01/30 09:14:16 gerlof ** Extend memory counters (a.o. page scans). ** ** Revision 1.20 2005/10/21 09:50:08 gerlof ** Per-user accumulation of resource consumption. ** ** Revision 1.19 2004/10/28 08:31:23 gerlof ** New counter: vm committed space ** ** Revision 1.18 2004/09/24 10:02:35 gerlof ** Wrong cpu-numbers for system level statistics. ** ** Revision 1.17 2004/05/07 05:27:37 gerlof ** Recognize new disk-names and support of diskname-modification. ** ** Revision 1.16 2004/05/06 09:53:31 gerlof ** Skip statistics of ram-disks. ** ** Revision 1.15 2004/05/06 09:46:14 gerlof ** Ported to kernel-version 2.6. ** ** Revision 1.14 2003/07/08 13:53:21 gerlof ** Cleanup code. ** ** Revision 1.13 2003/07/07 09:27:06 gerlof ** Cleanup code (-Wall proof). ** ** Revision 1.12 2003/06/30 11:30:37 gerlof ** Enlarge counters to 'long long'. ** ** Revision 1.11 2003/06/24 06:21:40 gerlof ** Limit number of system resource lines. ** ** Revision 1.10 2003/01/17 14:23:05 root ** Change-directory to /proc to optimize opening /proc-files ** via relative path-names i.s.o. absolute path-names. ** ** Revision 1.9 2003/01/14 07:50:26 gerlof ** Consider IPv6 counters on IP and UDP level (add them to the IPv4 counters). ** ** Revision 1.8 2002/07/24 11:13:38 gerlof ** Changed to ease porting to other UNIX-platforms. ** ** Revision 1.7 2002/07/11 09:12:41 root ** Parsing of /proc/meminfo made 2.5 proof. ** ** Revision 1.6 2002/07/10 05:00:21 root ** Counters pin/pout renamed to swin/swout (Linux conventions). ** ** Revision 1.5 2002/07/08 09:31:11 gerlof ** *** empty log message *** ** ** Revision 1.4 2002/07/02 07:36:45 gerlof ** *** empty log message *** ** ** Revision 1.3 2002/07/02 07:08:36 gerlof ** Recognize more disk driver types via regular expressions ** ** Revision 1.2 2002/01/22 13:40:11 gerlof ** Support for number of cpu's. ** ** Revision 1.1 2001/10/02 10:43:31 gerlof ** Initial revision ** */ static const char rcsid[] = "$Id: photosyst.c,v 1.38 2010/11/19 07:40:40 gerlof Exp $"; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SCALINGMAXCPU 8 // threshold for scaling info per CPU #ifndef NOPERFEVENT #include #include #endif #include #include #include // #define _GNU_SOURCE #include #include #include "atop.h" #include "photosyst.h" #define MAXCNT 64 /* return value of isdisk() */ #define NONTYPE 0 #define DSKTYPE 1 #define MDDTYPE 2 #define LVMTYPE 3 #ifndef NOPERFEVENT static void getperfevents(struct cpustat *); #endif static int get_infiniband(struct ifbstat *); static int isdisk(unsigned int, unsigned int, char *, struct perdsk *, int); static struct ipv6_stats ipv6_tmp; static struct icmpv6_stats icmpv6_tmp; static struct udpv6_stats udpv6_tmp; struct v6tab { char *nam; count_t *val; }; static struct v6tab v6tab[] = { {"Ip6InReceives", &ipv6_tmp.Ip6InReceives, }, {"Ip6InHdrErrors", &ipv6_tmp.Ip6InHdrErrors, }, {"Ip6InTooBigErrors", &ipv6_tmp.Ip6InTooBigErrors, }, {"Ip6InNoRoutes", &ipv6_tmp.Ip6InNoRoutes, }, {"Ip6InAddrErrors", &ipv6_tmp.Ip6InAddrErrors, }, {"Ip6InUnknownProtos", &ipv6_tmp.Ip6InUnknownProtos, }, {"Ip6InTruncatedPkts", &ipv6_tmp.Ip6InTruncatedPkts, }, {"Ip6InDiscards", &ipv6_tmp.Ip6InDiscards, }, {"Ip6InDelivers", &ipv6_tmp.Ip6InDelivers, }, {"Ip6OutForwDatagrams", &ipv6_tmp.Ip6OutForwDatagrams, }, {"Ip6OutRequests", &ipv6_tmp.Ip6OutRequests, }, {"Ip6OutDiscards", &ipv6_tmp.Ip6OutDiscards, }, {"Ip6OutNoRoutes", &ipv6_tmp.Ip6OutNoRoutes, }, {"Ip6ReasmTimeout", &ipv6_tmp.Ip6ReasmTimeout, }, {"Ip6ReasmReqds", &ipv6_tmp.Ip6ReasmReqds, }, {"Ip6ReasmOKs", &ipv6_tmp.Ip6ReasmOKs, }, {"Ip6ReasmFails", &ipv6_tmp.Ip6ReasmFails, }, {"Ip6FragOKs", &ipv6_tmp.Ip6FragOKs, }, {"Ip6FragFails", &ipv6_tmp.Ip6FragFails, }, {"Ip6FragCreates", &ipv6_tmp.Ip6FragCreates, }, {"Ip6InMcastPkts", &ipv6_tmp.Ip6InMcastPkts, }, {"Ip6OutMcastPkts", &ipv6_tmp.Ip6OutMcastPkts, }, {"Icmp6InMsgs", &icmpv6_tmp.Icmp6InMsgs, }, {"Icmp6InErrors", &icmpv6_tmp.Icmp6InErrors, }, {"Icmp6InDestUnreachs", &icmpv6_tmp.Icmp6InDestUnreachs, }, {"Icmp6InPktTooBigs", &icmpv6_tmp.Icmp6InPktTooBigs, }, {"Icmp6InTimeExcds", &icmpv6_tmp.Icmp6InTimeExcds, }, {"Icmp6InParmProblems", &icmpv6_tmp.Icmp6InParmProblems, }, {"Icmp6InEchos", &icmpv6_tmp.Icmp6InEchos, }, {"Icmp6InEchoReplies", &icmpv6_tmp.Icmp6InEchoReplies, }, {"Icmp6InGroupMembQueries", &icmpv6_tmp.Icmp6InGroupMembQueries, }, {"Icmp6InGroupMembResponses", &icmpv6_tmp.Icmp6InGroupMembResponses, }, {"Icmp6InGroupMembReductions", &icmpv6_tmp.Icmp6InGroupMembReductions, }, {"Icmp6InRouterSolicits", &icmpv6_tmp.Icmp6InRouterSolicits, }, {"Icmp6InRouterAdvertisements", &icmpv6_tmp.Icmp6InRouterAdvertisements, }, {"Icmp6InNeighborSolicits", &icmpv6_tmp.Icmp6InNeighborSolicits, }, {"Icmp6InNeighborAdvertisements", &icmpv6_tmp.Icmp6InNeighborAdvertisements, }, {"Icmp6InRedirects", &icmpv6_tmp.Icmp6InRedirects, }, {"Icmp6OutMsgs", &icmpv6_tmp.Icmp6OutMsgs, }, {"Icmp6OutDestUnreachs", &icmpv6_tmp.Icmp6OutDestUnreachs, }, {"Icmp6OutPktTooBigs", &icmpv6_tmp.Icmp6OutPktTooBigs, }, {"Icmp6OutTimeExcds", &icmpv6_tmp.Icmp6OutTimeExcds, }, {"Icmp6OutParmProblems", &icmpv6_tmp.Icmp6OutParmProblems, }, {"Icmp6OutEchoReplies", &icmpv6_tmp.Icmp6OutEchoReplies, }, {"Icmp6OutRouterSolicits", &icmpv6_tmp.Icmp6OutRouterSolicits, }, {"Icmp6OutNeighborSolicits",&icmpv6_tmp.Icmp6OutNeighborSolicits, }, {"Icmp6OutNeighborAdvertisements", &icmpv6_tmp.Icmp6OutNeighborAdvertisements, }, {"Icmp6OutRedirects", &icmpv6_tmp.Icmp6OutRedirects, }, {"Icmp6OutGroupMembResponses", &icmpv6_tmp.Icmp6OutGroupMembResponses, }, {"Icmp6OutGroupMembReductions", &icmpv6_tmp.Icmp6OutGroupMembReductions, }, {"Udp6InDatagrams", &udpv6_tmp.Udp6InDatagrams, }, {"Udp6NoPorts", &udpv6_tmp.Udp6NoPorts, }, {"Udp6InErrors", &udpv6_tmp.Udp6InErrors, }, {"Udp6OutDatagrams", &udpv6_tmp.Udp6OutDatagrams, }, }; static int v6tab_entries = sizeof(v6tab)/sizeof(struct v6tab); void photosyst(struct sstat *si) { static char part_stats = 1; /* per-partition statistics ? */ static char ib_stats = 1; /* InfiniBand statistics ? */ register int i, nr; count_t cnts[MAXCNT]; float lavg1, lavg5, lavg15; FILE *fp; char linebuf[1024], nam[64], origdir[1024]; unsigned int major, minor; struct shm_info shminfo; #if HTTPSTATS static int wwwvalid = 1; #endif memset(si, 0, sizeof(struct sstat)); if ( getcwd(origdir, sizeof origdir) == NULL) { perror("save current dir"); cleanstop(53); } if ( chdir("/proc") == -1) { perror("change to /proc"); cleanstop(54); } /* ** gather various general statistics from the file /proc/stat and ** store them in binary form */ if ( (fp = fopen("stat", "r")) != NULL) { while ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { nr = sscanf(linebuf, "%s %lld %lld %lld %lld %lld %lld %lld " "%lld %lld %lld %lld %lld %lld %lld %lld ", nam, &cnts[0], &cnts[1], &cnts[2], &cnts[3], &cnts[4], &cnts[5], &cnts[6], &cnts[7], &cnts[8], &cnts[9], &cnts[10], &cnts[11], &cnts[12], &cnts[13], &cnts[14]); if (nr < 2) /* headerline ? --> skip */ continue; if ( strcmp("cpu", nam) == EQ) { si->cpu.all.utime = cnts[0]; si->cpu.all.ntime = cnts[1]; si->cpu.all.stime = cnts[2]; si->cpu.all.itime = cnts[3]; if (nr > 5) /* 2.6 kernel? */ { si->cpu.all.wtime = cnts[4]; si->cpu.all.Itime = cnts[5]; si->cpu.all.Stime = cnts[6]; if (nr > 8) /* steal support */ si->cpu.all.steal = cnts[7]; if (nr > 9) /* guest support */ si->cpu.all.guest = cnts[8]; } continue; } if ( strncmp("cpu", nam, 3) == EQ) { i = atoi(&nam[3]); if (i >= MAXCPU) { fprintf(stderr, "cpu %s exceeds maximum of %d\n", nam, MAXCPU); continue; } si->cpu.cpu[i].cpunr = i; si->cpu.cpu[i].utime = cnts[0]; si->cpu.cpu[i].ntime = cnts[1]; si->cpu.cpu[i].stime = cnts[2]; si->cpu.cpu[i].itime = cnts[3]; if (nr > 5) /* 2.6 kernel? */ { si->cpu.cpu[i].wtime = cnts[4]; si->cpu.cpu[i].Itime = cnts[5]; si->cpu.cpu[i].Stime = cnts[6]; if (nr > 8) /* steal support */ si->cpu.cpu[i].steal = cnts[7]; if (nr > 9) /* guest support */ si->cpu.cpu[i].guest = cnts[8]; } si->cpu.nrcpu++; continue; } if ( strcmp("ctxt", nam) == EQ) { si->cpu.csw = cnts[0]; continue; } if ( strcmp("intr", nam) == EQ) { si->cpu.devint = cnts[0]; continue; } if ( strcmp("processes", nam) == EQ) { si->cpu.nprocs = cnts[0]; continue; } if ( strcmp("swap", nam) == EQ) /* < 2.6 */ { si->mem.swins = cnts[0]; si->mem.swouts = cnts[1]; continue; } } fclose(fp); if (si->cpu.nrcpu == 0) si->cpu.nrcpu = 1; } /* ** gather loadaverage values from the file /proc/loadavg and ** store them in binary form */ if ( (fp = fopen("loadavg", "r")) != NULL) { if ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { if ( sscanf(linebuf, "%f %f %f", &lavg1, &lavg5, &lavg15) == 3) { si->cpu.lavg1 = lavg1; si->cpu.lavg5 = lavg5; si->cpu.lavg15 = lavg15; } } fclose(fp); } /* ** gather frequency scaling info. ** sources (in order of preference): ** /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state ** or ** /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq ** /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq ** ** store them in binary form */ static char fn[256]; int didone=0; if (si->cpu.nrcpu <= SCALINGMAXCPU) { for (i = 0; i < si->cpu.nrcpu; ++i) { long long f=0; sprintf(fn, "/sys/devices/system/cpu/cpu%d/cpufreq/stats/time_in_state", i); if ((fp=fopen(fn, "r")) != 0) { long long hits=0; long long maxfreq=0; long long cnt=0; long long sum=0; while (fscanf(fp, "%lld %lld", &f, &cnt) == 2) { f /= 1000; sum += (f*cnt); hits += cnt; if (f > maxfreq) maxfreq=f; didone=1; } si->cpu.cpu[i].freqcnt.maxfreq = maxfreq; si->cpu.cpu[i].freqcnt.cnt = sum; si->cpu.cpu[i].freqcnt.ticks = hits; fclose(fp); } else { // governor statistics not available sprintf(fn, "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", i); if ((fp=fopen(fn, "r")) != 0) { if (fscanf(fp, "%lld", &f) == 1) { // convert KHz to MHz si->cpu.cpu[i].freqcnt.maxfreq =f/1000; } fclose(fp); } else { si->cpu.cpu[i].freqcnt.maxfreq=0; } sprintf(fn, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", i); if ((fp=fopen(fn, "r")) != 0) { if (fscanf(fp, "%lld", &f) == 1) { // convert KHz to MHz si->cpu.cpu[i].freqcnt.cnt = f/1000; si->cpu.cpu[i].freqcnt.ticks = 0; didone=1; } fclose(fp); } else { si->cpu.cpu[i].freqcnt.cnt = 0; si->cpu.cpu[i].freqcnt.ticks = 0; } } } // for all CPUs } if (!didone) // did not get processor freq statistics. // use /proc/cpuinfo { if ( (fp = fopen("cpuinfo", "r")) != NULL) { // get information from the lines // processor\t: 0 // cpu MHz\t\t: 800.000 int cpuno=-1; while ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { if (memcmp(linebuf, "processor", 9)== EQ) sscanf(linebuf, "%*s %*s %d", &cpuno); if (memcmp(linebuf, "cpu MHz", 7) == EQ) { if (cpuno >= 0 && cpuno < si->cpu.nrcpu) { sscanf(linebuf, "%*s %*s %*s %lld", &(si->cpu.cpu[cpuno].freqcnt.cnt)); } } } fclose(fp); } } /* ** gather virtual memory statistics from the file /proc/vmstat and ** store them in binary form (>= kernel 2.6) */ if ( (fp = fopen("vmstat", "r")) != NULL) { while ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { nr = sscanf(linebuf, "%s %lld", nam, &cnts[0]); if (nr < 2) /* headerline ? --> skip */ continue; if ( strcmp("pswpin", nam) == EQ) { si->mem.swins = cnts[0]; continue; } if ( strcmp("pswpout", nam) == EQ) { si->mem.swouts = cnts[0]; continue; } if ( strncmp("pgscan_", nam, 7) == EQ) { si->mem.pgscans += cnts[0]; continue; } if ( strncmp("pgsteal_", nam, 8) == EQ) { si->mem.pgsteal += cnts[0]; continue; } if ( strcmp("allocstall", nam) == EQ) { si->mem.allocstall = cnts[0]; continue; } } fclose(fp); } /* ** gather memory-related statistics from the file /proc/meminfo and ** store them in binary form ** ** in the file /proc/meminfo a 2.4 kernel starts with two lines ** headed by the strings "Mem:" and "Swap:" containing all required ** fields, except proper value for page cache ** if these lines are present we try to skip parsing the rest ** of the lines; if these lines are not present we should get the ** required field from other lines */ si->mem.physmem = (count_t)-1; si->mem.freemem = (count_t)-1; si->mem.buffermem = (count_t)-1; si->mem.cachemem = (count_t)-1; si->mem.slabmem = (count_t) 0; si->mem.slabreclaim = (count_t) 0; si->mem.shmem = (count_t) 0; si->mem.totswap = (count_t)-1; si->mem.freeswap = (count_t)-1; si->mem.committed = (count_t) 0; if ( (fp = fopen("meminfo", "r")) != NULL) { while ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { nr = sscanf(linebuf, "%s %lld %lld %lld %lld %lld %lld %lld " "%lld %lld %lld\n", nam, &cnts[0], &cnts[1], &cnts[2], &cnts[3], &cnts[4], &cnts[5], &cnts[6], &cnts[7], &cnts[8], &cnts[9]); if (nr < 2) /* headerline ? --> skip */ continue; if ( strcmp("Mem:", nam) == EQ) { si->mem.physmem = cnts[0] / pagesize; si->mem.freemem = cnts[2] / pagesize; si->mem.buffermem = cnts[4] / pagesize; } else if ( strcmp("Swap:", nam) == EQ) { si->mem.totswap = cnts[0] / pagesize; si->mem.freeswap = cnts[2] / pagesize; } else if (strcmp("Cached:", nam) == EQ) { if (si->mem.cachemem == (count_t)-1) { si->mem.cachemem = cnts[0]*1024/pagesize; } } else if (strcmp("Dirty:", nam) == EQ) { si->mem.cachedrt = cnts[0]*1024/pagesize; } else if (strcmp("MemTotal:", nam) == EQ) { if (si->mem.physmem == (count_t)-1) { si->mem.physmem = cnts[0]*1024/pagesize; } } else if (strcmp("MemFree:", nam) == EQ) { if (si->mem.freemem == (count_t)-1) { si->mem.freemem = cnts[0]*1024/pagesize; } } else if (strcmp("Buffers:", nam) == EQ) { if (si->mem.buffermem == (count_t)-1) { si->mem.buffermem = cnts[0]*1024/pagesize; } } else if (strcmp("Shmem:", nam) == EQ) { si->mem.shmem = cnts[0]*1024/pagesize; } else if (strcmp("SwapTotal:", nam) == EQ) { if (si->mem.totswap == (count_t)-1) { si->mem.totswap = cnts[0]*1024/pagesize; } } else if (strcmp("SwapFree:", nam) == EQ) { if (si->mem.freeswap == (count_t)-1) { si->mem.freeswap = cnts[0]*1024/pagesize; } } else if (strcmp("Slab:", nam) == EQ) { si->mem.slabmem = cnts[0]*1024/pagesize; } else if (strcmp("SReclaimable:", nam) == EQ) { si->mem.slabreclaim = cnts[0]*1024/ pagesize; } else if (strcmp("Committed_AS:", nam) == EQ) { si->mem.committed = cnts[0]*1024/ pagesize; } else if (strcmp("CommitLimit:", nam) == EQ) { si->mem.commitlim = cnts[0]*1024/ pagesize; } else if (strcmp("HugePages_Total:", nam) == EQ) { si->mem.tothugepage = cnts[0]; } else if (strcmp("HugePages_Free:", nam) == EQ) { si->mem.freehugepage = cnts[0]; } else if (strcmp("Hugepagesize:", nam) == EQ) { si->mem.hugepagesz = cnts[0]*1024; } } fclose(fp); } /* ** gather vmware-related statistics from /proc/vmmemctl ** (only present if balloon driver enabled) */ si->mem.vmwballoon = (count_t) 0; if ( (fp = fopen("vmmemctl", "r")) != NULL) { while ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { nr = sscanf(linebuf, "%s %lld ", nam, &cnts[0]); if ( strcmp("current:", nam) == EQ) { si->mem.vmwballoon = cnts[0]; break; } } fclose(fp); } /* ** gather network-related statistics ** - interface stats from the file /proc/net/dev ** - IPv4 stats from the file /proc/net/snmp ** - IPv6 stats from the file /proc/net/snmp6 */ /* ** interface statistics */ if ( (fp = fopen("net/dev", "r")) != NULL) { char *cp; i = 0; while ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { if ( (cp = strchr(linebuf, ':')) != NULL) *cp = ' '; /* substitute ':' by space */ nr = sscanf(linebuf, "%15s %lld %lld %lld %lld %lld %lld %lld " "%lld %lld %lld %lld %lld %lld %lld %lld " "%lld\n", si->intf.intf[i].name, &(si->intf.intf[i].rbyte), &(si->intf.intf[i].rpack), &(si->intf.intf[i].rerrs), &(si->intf.intf[i].rdrop), &(si->intf.intf[i].rfifo), &(si->intf.intf[i].rframe), &(si->intf.intf[i].rcompr), &(si->intf.intf[i].rmultic), &(si->intf.intf[i].sbyte), &(si->intf.intf[i].spack), &(si->intf.intf[i].serrs), &(si->intf.intf[i].sdrop), &(si->intf.intf[i].sfifo), &(si->intf.intf[i].scollis), &(si->intf.intf[i].scarrier), &(si->intf.intf[i].scompr)); if (nr == 17) /* skip header & lines without stats */ { if (++i >= MAXINTF-1) break; } } si->intf.intf[i].name[0] = '\0'; /* set terminator for table */ si->intf.nrintf = i; fclose(fp); } /* ** IP version 4 statistics */ if ( (fp = fopen("net/snmp", "r")) != NULL) { while ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { nr = sscanf(linebuf, "%s %lld %lld %lld %lld %lld %lld %lld %lld %lld " "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld " "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld " "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld " "%lld\n", nam, &cnts[0], &cnts[1], &cnts[2], &cnts[3], &cnts[4], &cnts[5], &cnts[6], &cnts[7], &cnts[8], &cnts[9], &cnts[10], &cnts[11], &cnts[12], &cnts[13], &cnts[14], &cnts[15], &cnts[16], &cnts[17], &cnts[18], &cnts[19], &cnts[20], &cnts[21], &cnts[22], &cnts[23], &cnts[24], &cnts[25], &cnts[26], &cnts[27], &cnts[28], &cnts[29], &cnts[30], &cnts[31], &cnts[32], &cnts[33], &cnts[34], &cnts[35], &cnts[36], &cnts[37], &cnts[38], &cnts[39]); if (nr < 2) /* headerline ? --> skip */ continue; if ( strcmp("Ip:", nam) == 0) { memcpy(&si->net.ipv4, cnts, sizeof si->net.ipv4); continue; } if ( strcmp("Icmp:", nam) == 0) { memcpy(&si->net.icmpv4, cnts, sizeof si->net.icmpv4); continue; } if ( strcmp("Tcp:", nam) == 0) { memcpy(&si->net.tcp, cnts, sizeof si->net.tcp); continue; } if ( strcmp("Udp:", nam) == 0) { memcpy(&si->net.udpv4, cnts, sizeof si->net.udpv4); continue; } } fclose(fp); } /* ** IP version 6 statistics */ memset(&ipv6_tmp, 0, sizeof ipv6_tmp); memset(&icmpv6_tmp, 0, sizeof icmpv6_tmp); memset(&udpv6_tmp, 0, sizeof udpv6_tmp); if ( (fp = fopen("net/snmp6", "r")) != NULL) { count_t countval; int cur = 0; /* ** one name-value pair per line */ while ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { nr = sscanf(linebuf, "%s %lld", nam, &countval); if (nr < 2) /* unexpected line ? --> skip */ continue; if (strcmp(v6tab[cur].nam, nam) == 0) { *(v6tab[cur].val) = countval; } else { for (cur=0; cur < v6tab_entries; cur++) if (strcmp(v6tab[cur].nam, nam) == 0) break; if (cur < v6tab_entries) /* found ? */ *(v6tab[cur].val) = countval; } if (++cur >= v6tab_entries) cur = 0; } memcpy(&si->net.ipv6, &ipv6_tmp, sizeof ipv6_tmp); memcpy(&si->net.icmpv6, &icmpv6_tmp, sizeof icmpv6_tmp); memcpy(&si->net.udpv6, &udpv6_tmp, sizeof udpv6_tmp); fclose(fp); } /* ** check if extended partition-statistics are provided < kernel 2.6 */ if ( part_stats && (fp = fopen("partitions", "r")) != NULL) { char diskname[256]; i = 0; while ( fgets(linebuf, sizeof(linebuf), fp) ) { nr = sscanf(linebuf, "%*d %*d %*d %255s %lld %*d %lld %*d " "%lld %*d %lld %*d %*d %lld %lld", diskname, &(si->dsk.dsk[i].nread), &(si->dsk.dsk[i].nrsect), &(si->dsk.dsk[i].nwrite), &(si->dsk.dsk[i].nwsect), &(si->dsk.dsk[i].io_ms), &(si->dsk.dsk[i].avque) ); /* ** check if this line concerns the entire disk ** or just one of the partitions of a disk (to be ** skipped) */ if (nr == 7) /* full stats-line ? */ { if ( isdisk(0, 0, diskname, &(si->dsk.dsk[i]), MAXDKNAM) != DSKTYPE) continue; if (++i >= MAXDSK-1) break; } } si->dsk.dsk[i].name[0] = '\0'; /* set terminator for table */ si->dsk.ndsk = i; fclose(fp); if (i == 0) part_stats = 0; /* do not try again for next cycles */ } /* ** check if disk-statistics are provided (kernel 2.6 onwards) */ if ( (fp = fopen("diskstats", "r")) != NULL) { char diskname[256]; struct perdsk tmpdsk; si->dsk.ndsk = 0; si->dsk.nmdd = 0; si->dsk.nlvm = 0; while ( fgets(linebuf, sizeof(linebuf), fp) ) { nr = sscanf(linebuf, "%d %d %255s %lld %*d %lld %*d " "%lld %*d %lld %*d %*d %lld %lld", &major, &minor, diskname, &tmpdsk.nread, &tmpdsk.nrsect, &tmpdsk.nwrite, &tmpdsk.nwsect, &tmpdsk.io_ms, &tmpdsk.avque ); /* ** check if this line concerns the entire disk ** or just one of the partitions of a disk (to be ** skipped) */ if (nr == 9) /* full stats-line ? */ { switch ( isdisk(major, minor, diskname, &tmpdsk, MAXDKNAM) ) { case NONTYPE: continue; case DSKTYPE: if (si->dsk.ndsk < MAXDSK-1) si->dsk.dsk[si->dsk.ndsk++] = tmpdsk; break; case MDDTYPE: if (si->dsk.nmdd < MAXMDD-1) si->dsk.mdd[si->dsk.nmdd++] = tmpdsk; break; case LVMTYPE: if (si->dsk.nlvm < MAXLVM-1) si->dsk.lvm[si->dsk.nlvm++] = tmpdsk; break; } } } /* ** set terminator for table */ si->dsk.dsk[si->dsk.ndsk].name[0] = '\0'; si->dsk.mdd[si->dsk.nmdd].name[0] = '\0'; si->dsk.lvm[si->dsk.nlvm].name[0] = '\0'; fclose(fp); } /* ** get information about the shared memory statistics */ if ( shmctl(0, SHM_INFO, (struct shmid_ds *)&shminfo) != -1) { si->mem.shmrss = shminfo.shm_rss; si->mem.shmswp = shminfo.shm_swp; } /* ** NFS server statistics */ if ( (fp = fopen("net/rpc/nfsd", "r")) != NULL) { char label[32]; count_t cnt[40]; /* ** every line starts with a small label, ** followed by upto 60 counters */ while ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { memset(cnt, 0, sizeof cnt); nr = sscanf(linebuf, "%31s %lld %lld %lld %lld %lld" "%lld %lld %lld %lld %lld" "%lld %lld %lld %lld %lld" "%lld %lld %lld %lld %lld" "%lld %lld %lld %lld %lld" "%lld %lld %lld %lld %lld" "%lld %lld %lld %lld %lld" "%lld %lld %lld %lld %lld", label, &cnt[0], &cnt[1], &cnt[2], &cnt[3], &cnt[4], &cnt[5], &cnt[6], &cnt[7], &cnt[8], &cnt[9], &cnt[10], &cnt[11], &cnt[12], &cnt[13], &cnt[14], &cnt[15], &cnt[16], &cnt[17], &cnt[18], &cnt[19], &cnt[20], &cnt[21], &cnt[22], &cnt[23], &cnt[24], &cnt[25], &cnt[26], &cnt[27], &cnt[28], &cnt[29], &cnt[30], &cnt[31], &cnt[32], &cnt[33], &cnt[34], &cnt[35], &cnt[36], &cnt[37], &cnt[38], &cnt[39]); if (nr < 2) // unexpected empty line ? continue; if (strcmp(label, "rc") == 0) { si->nfs.server.rchits = cnt[0]; si->nfs.server.rcmiss = cnt[1]; si->nfs.server.rcnoca = cnt[2]; continue; } if (strcmp(label, "io") == 0) { si->nfs.server.nrbytes = cnt[0]; si->nfs.server.nwbytes = cnt[1]; continue; } if (strcmp(label, "net") == 0) { si->nfs.server.netcnt = cnt[0]; si->nfs.server.netudpcnt = cnt[1]; si->nfs.server.nettcpcnt = cnt[2]; si->nfs.server.nettcpcon = cnt[3]; continue; } if (strcmp(label, "rpc") == 0) { si->nfs.server.rpccnt = cnt[0]; si->nfs.server.rpcbadfmt = cnt[1]; si->nfs.server.rpcbadaut = cnt[2]; si->nfs.server.rpcbadcln = cnt[3]; continue; } // // first counter behind 'proc..' is number of // counters that follow if (strcmp(label, "proc2") == 0) { si->nfs.server.rpcread += cnt[7]; // offset+1 si->nfs.server.rpcwrite += cnt[9]; // offset+1 continue; } if (strcmp(label, "proc3") == 0) { si->nfs.server.rpcread += cnt[7]; // offset+1 si->nfs.server.rpcwrite += cnt[8]; // offset+1 continue; } if (strcmp(label, "proc4ops") == 0) { si->nfs.server.rpcread += cnt[26]; // offset+1 si->nfs.server.rpcwrite += cnt[39]; // offset+1 continue; } } fclose(fp); } /* ** NFS client statistics */ if ( (fp = fopen("net/rpc/nfs", "r")) != NULL) { char label[32]; count_t cnt[10]; /* ** every line starts with a small label, ** followed by counters */ while ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { memset(cnt, 0, sizeof cnt); nr = sscanf(linebuf, "%31s %lld %lld %lld %lld %lld" "%lld %lld %lld %lld %lld", label, &cnt[0], &cnt[1], &cnt[2], &cnt[3], &cnt[4], &cnt[5], &cnt[6], &cnt[7], &cnt[8], &cnt[9]); if (nr < 2) // unexpected empty line ? continue; if (strcmp(label, "rpc") == 0) { si->nfs.client.rpccnt = cnt[0]; si->nfs.client.rpcretrans = cnt[1]; si->nfs.client.rpcautrefresh = cnt[2]; continue; } // first counter behind 'proc..' is number of // counters that follow if (strcmp(label, "proc2") == 0) { si->nfs.client.rpcread += cnt[7]; // offset+1 si->nfs.client.rpcwrite += cnt[9]; // offset+1 continue; } if (strcmp(label, "proc3") == 0) { si->nfs.client.rpcread += cnt[7]; // offset+1 si->nfs.client.rpcwrite += cnt[8]; // offset+1 continue; } if (strcmp(label, "proc4") == 0) { si->nfs.client.rpcread += cnt[2]; // offset+1 si->nfs.client.rpcwrite += cnt[3]; // offset+1 continue; } } fclose(fp); } /* ** NFS client: per-mount statistics */ regainrootprivs(); if ( (fp = fopen("self/mountstats", "r")) != NULL) { char mountdev[128], fstype[32], label[32]; count_t cnt[8]; i = 0; while ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { // if 'device' line, just remember the mounted device if (sscanf(linebuf, "device %127s mounted on %*s with fstype %31s", mountdev, fstype) == 2) { continue; } if (memcmp(fstype, "nfs", 3) != 0) continue; // this is line with NFS client stats nr = sscanf(linebuf, "%31s %lld %lld %lld %lld %lld %lld %lld %lld", label, &cnt[0], &cnt[1], &cnt[2], &cnt[3], &cnt[4], &cnt[5], &cnt[6], &cnt[7]); if (nr >= 2 ) { if (strcmp(label, "age:") == 0) { strcpy(si->nfs.nfsmounts.nfsmnt[i].mountdev, mountdev); si->nfs.nfsmounts.nfsmnt[i].age = cnt[0]; } if (strcmp(label, "bytes:") == 0) { si->nfs.nfsmounts.nfsmnt[i].bytesread = cnt[0]; si->nfs.nfsmounts.nfsmnt[i].byteswrite = cnt[1]; si->nfs.nfsmounts.nfsmnt[i].bytesdread = cnt[2]; si->nfs.nfsmounts.nfsmnt[i].bytesdwrite = cnt[3]; si->nfs.nfsmounts.nfsmnt[i].bytestotread = cnt[4]; si->nfs.nfsmounts.nfsmnt[i].bytestotwrite = cnt[5]; si->nfs.nfsmounts.nfsmnt[i].pagesmread = cnt[6]; si->nfs.nfsmounts.nfsmnt[i].pagesmwrite = cnt[7]; if (++i >= MAXNFSMOUNT-1) break; } } } si->nfs.nfsmounts.nrmounts = i; fclose(fp); } if (! droprootprivs()) cleanstop(42); /* ** pressure statistics in /proc/pressure (>= 4.20) ** ** cpu: some avg10=0.00 avg60=1.37 avg300=3.73 total=30995960 ** io: some avg10=0.00 avg60=8.83 avg300=22.86 total=141658568 ** io: full avg10=0.00 avg60=8.33 avg300=21.56 total=133129045 ** memory: some avg10=0.00 avg60=0.74 avg300=1.67 total=10663184 ** memory: full avg10=0.00 avg60=0.45 avg300=0.94 total=6461782 ** ** verify if pressure stats supported by this system */ if ( chdir("pressure") == 0) { struct psi psitemp; char psitype; char psiformat[] = "%c%*s avg10=%f avg60=%f avg300=%f total=%llu"; si->psi.present = 1; if ( (fp = fopen("cpu", "r")) != NULL) { if ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { nr = sscanf(linebuf, psiformat, &psitype, &psitemp.avg10, &psitemp.avg60, &psitemp.avg300, &psitemp.total); if (nr == 5) // complete line ? memmove(&(si->psi.cpusome), &psitemp, sizeof psitemp); } fclose(fp); } if ( (fp = fopen("memory", "r")) != NULL) { while ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { nr = sscanf(linebuf, psiformat, &psitype, &psitemp.avg10, &psitemp.avg60, &psitemp.avg300, &psitemp.total); if (nr == 5) { if (psitype == 's') memmove(&(si->psi.memsome), &psitemp, sizeof psitemp); else memmove(&(si->psi.memfull), &psitemp, sizeof psitemp); } } fclose(fp); } if ( (fp = fopen("io", "r")) != NULL) { while ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { nr = sscanf(linebuf, psiformat, &psitype, &psitemp.avg10, &psitemp.avg60, &psitemp.avg300, &psitemp.total); if (nr == 5) { if (psitype == 's') memmove(&(si->psi.iosome), &psitemp, sizeof psitemp); else memmove(&(si->psi.iofull), &psitemp, sizeof psitemp); } } fclose(fp); } if ( chdir("..") == -1) { perror("return to /proc"); cleanstop(54); } } else { si->psi.present = 0; } /* ** Container statistics (if any) */ if ( (fp = fopen("user_beancounters", "r")) != NULL) { unsigned long ctid; char label[32]; count_t cnt; i = -1; /* ** lines introducing a new container have an extra ** field with the container id at the beginning. */ while ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { nr = sscanf(linebuf, "%lu: %31s %lld", &ctid, label, &cnt); if (nr == 3) // new container ? { if (++i >= MAXCONTAINER) break; si->cfs.cont[i].ctid = ctid; } else { nr = sscanf(linebuf, "%31s %lld", label, &cnt); if (nr != 2) continue; } if (i == -1) // no container defined yet continue; if (strcmp(label, "numproc") == 0) { si->cfs.cont[i].numproc = cnt; continue; } if (strcmp(label, "physpages") == 0) { si->cfs.cont[i].physpages = cnt; continue; } } fclose(fp); si->cfs.nrcontainer = i+1; if ( (fp = fopen("vz/vestat", "r")) != NULL) { unsigned long ctid; count_t cnt[8]; /* ** relevant lines start with container id */ while ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { nr = sscanf(linebuf, "%lu %lld %lld %lld %lld" "%lld %lld %lld %lld %lld", &ctid, &cnt[0], &cnt[1], &cnt[2], &cnt[3], &cnt[4], &cnt[5], &cnt[6], &cnt[7], &cnt[8]); if (nr < 9) // irrelevant contents continue; // relevant stats: search for containerid for (i=0; i < si->cfs.nrcontainer; i++) { if (si->cfs.cont[i].ctid == ctid) break; } if (i >= si->cfs.nrcontainer) continue; // container not found si->cfs.cont[i].user = cnt[0]; si->cfs.cont[i].nice = cnt[1]; si->cfs.cont[i].system = cnt[2]; si->cfs.cont[i].uptime = cnt[3]; } fclose(fp); } } /* ** verify presence of InfiniBand controllers ** warning: possibly switches to other directory */ if (ib_stats) ib_stats = get_infiniband(&(si->ifb)); /* ** return to original directory */ if ( chdir(origdir) == -1) { perror(origdir); cleanstop(55); } #ifndef NOPERFEVENT /* ** get low-level CPU event counters */ getperfevents(&(si->cpu)); #endif /* ** fetch application-specific counters */ #if HTTPSTATS if ( wwwvalid) wwwvalid = getwwwstat(80, &(si->www)); #endif } /* ** set of subroutines to determine which disks should be monitored ** and to translate name strings into (shorter) name strings */ static void nullmodname(unsigned int major, unsigned int minor, char *curname, struct perdsk *px, int maxlen) { strncpy(px->name, curname, maxlen-1); *(px->name+maxlen-1) = 0; } static void abbrevname1(unsigned int major, unsigned int minor, char *curname, struct perdsk *px, int maxlen) { char cutype[128]; int hostnum, busnum, targetnum, lunnum; sscanf(curname, "%[^/]/host%d/bus%d/target%d/lun%d", cutype, &hostnum, &busnum, &targetnum, &lunnum); snprintf(px->name, maxlen, "%c-h%db%dt%d", cutype[0], hostnum, busnum, targetnum); } /* ** recognize LVM logical volumes */ #define NUMDMHASH 64 #define DMHASH(x,y) (((x)+(y))%NUMDMHASH) #define MAPDIR "/dev/mapper" struct devmap { unsigned int major; unsigned int minor; char name[MAXDKNAM]; struct devmap *next; }; static void lvmmapname(unsigned int major, unsigned int minor, char *curname, struct perdsk *px, int maxlen) { static int firstcall = 1; static struct devmap *devmaps[NUMDMHASH], *dmp; int hashix; /* ** setup a list of major-minor numbers of dm-devices with their ** corresponding name */ if (firstcall) { DIR *dirp; struct dirent *dentry; struct stat statbuf; char path[64]; if ( (dirp = opendir(MAPDIR)) ) { /* ** read every directory-entry and search for ** block devices */ while ( (dentry = readdir(dirp)) ) { snprintf(path, sizeof path, "%s/%s", MAPDIR, dentry->d_name); if ( stat(path, &statbuf) == -1 ) continue; if ( ! S_ISBLK(statbuf.st_mode) ) continue; /* ** allocate struct to store name */ if ( !(dmp = malloc(sizeof (struct devmap)))) continue; /* ** store info in hash list */ strncpy(dmp->name, dentry->d_name, MAXDKNAM); dmp->name[MAXDKNAM-1] = 0; dmp->major = major(statbuf.st_rdev); dmp->minor = minor(statbuf.st_rdev); hashix = DMHASH(dmp->major, dmp->minor); dmp->next = devmaps[hashix]; devmaps[hashix] = dmp; } closedir(dirp); } firstcall = 0; } /* ** find info in hash list */ hashix = DMHASH(major, minor); dmp = devmaps[hashix]; while (dmp) { if (dmp->major == major && dmp->minor == minor) { /* ** info found in hash list; fill proper name */ strncpy(px->name, dmp->name, maxlen-1); *(px->name+maxlen-1) = 0; return; } dmp = dmp->next; } /* ** info not found in hash list; fill original name */ strncpy(px->name, curname, maxlen-1); *(px->name+maxlen-1) = 0; } /* ** this table is used in the function isdisk() ** ** table contains the names (in regexp format) of disks ** to be recognized, together with a function to modify ** the name-strings (i.e. to abbreviate long strings); ** some frequently found names (like 'loop' and 'ram') ** are also recognized to skip them as fast as possible */ static struct { char *regexp; regex_t compreg; void (*modname)(unsigned int, unsigned int, char *, struct perdsk *, int); int retval; } validdisk[] = { { "^ram[0-9][0-9]*$", {0}, (void *)0, NONTYPE, }, { "^loop[0-9][0-9]*$", {0}, (void *)0, NONTYPE, }, { "^sd[a-z][a-z]*$", {0}, nullmodname, DSKTYPE, }, { "^dm-[0-9][0-9]*$", {0}, lvmmapname, LVMTYPE, }, { "^md[0-9][0-9]*$", {0}, nullmodname, MDDTYPE, }, { "^vd[a-z][a-z]*$", {0}, nullmodname, DSKTYPE, }, { "^nvme[0-9][0-9]*n[0-9][0-9]*$", {0}, nullmodname, DSKTYPE, }, { "^nbd[0-9][0-9]*$", {0}, nullmodname, DSKTYPE, }, { "^hd[a-z]$", {0}, nullmodname, DSKTYPE, }, { "^rd/c[0-9][0-9]*d[0-9][0-9]*$", {0}, nullmodname, DSKTYPE, }, { "^cciss/c[0-9][0-9]*d[0-9][0-9]*$", {0}, nullmodname, DSKTYPE, }, { "^fio[a-z][a-z]*$", {0}, nullmodname, DSKTYPE, }, { "/host.*/bus.*/target.*/lun.*/disc", {0}, abbrevname1, DSKTYPE, }, { "^xvd[a-z][a-z]*[0-9]*$", {0}, nullmodname, DSKTYPE, }, { "^dasd[a-z][a-z]*$", {0}, nullmodname, DSKTYPE, }, { "^mmcblk[0-9][0-9]*$", {0}, nullmodname, DSKTYPE, }, { "^emcpower[a-z][a-z]*$", {0}, nullmodname, DSKTYPE, }, }; static int isdisk(unsigned int major, unsigned int minor, char *curname, struct perdsk *px, int maxlen) { static int firstcall = 1; register int i; if (firstcall) /* compile the regular expressions */ { for (i=0; i < sizeof validdisk/sizeof validdisk[0]; i++) regcomp(&validdisk[i].compreg, validdisk[i].regexp, REG_NOSUB); firstcall = 0; } /* ** try to recognize one of the compiled regular expressions */ for (i=0; i < sizeof validdisk/sizeof validdisk[0]; i++) { if (regexec(&validdisk[i].compreg, curname, 0, NULL, 0) == 0) { /* ** name-string recognized; modify name-string */ if (validdisk[i].retval != NONTYPE) (*validdisk[i].modname)(major, minor, curname, px, maxlen); return validdisk[i].retval; } } 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 ** /sys/class/infiniband//ports//.... */ static struct ibcachent { char *ibha; // InfiniBand Host Adaptor unsigned short port; // port number unsigned short lanes; // number of lanes count_t rate; // transfer rate in bytes/sec char *pathrcvb; // path name for received bytes char *pathsndb; // path name for transmitted bytes char *pathrcvp; // path name for received packets char *pathsndp; // path name for transmitted packets } ibcache[MAXIBPORT]; static int nib; // number of IB ports in cache static void ibprep(struct ibcachent *); static int ibstat(struct ibcachent *, struct perifb *); static int get_infiniband(struct ifbstat *si) { static int firstcall = 1; int i; // verify if InfiniBand used in this system if ( chdir("/sys/class/infiniband") == -1) return 0; // no path, no IB, so don't try again if (firstcall) { char path[128], *p; struct stat statbuf; struct dirent *contdent, *portdent; DIR *contp, *portp; firstcall = 0; /* ** once setup a cache with all info that is needed ** to gather the necessary stats with every subsequent ** call, including path names, etcetera. */ if ( (contp = opendir(".")) ) { /* ** read every directory-entry and search for ** subdirectories (i.e. controllers) */ while ( (contdent = readdir(contp)) ) { // skip . and .. if (contdent->d_name[0] == '.') continue; if ( stat(contdent->d_name, &statbuf) == -1 ) continue; if ( ! S_ISDIR(statbuf.st_mode) ) continue; // controller found // store controller name for cache // p = malloc( strlen(contdent->d_name)+1 ); strcpy(p, contdent->d_name); if (strlen(contdent->d_name) > MAXIBNAME-1) p[MAXIBNAME-1] = '\0'; // discover all ports // snprintf(path, sizeof path, "%s/ports", contdent->d_name); if ( (portp = opendir(path)) ) { /* ** read every directory-entry and ** search for subdirectories (i.e. ** port numbers) */ while ( (portdent = readdir(portp)) ) { int port; // skip . and .. if (portdent->d_name[0] == '.') continue; port = atoi(portdent->d_name); if (!port) continue; // valid port // fill cache info // ibcache[nib].port = port; ibcache[nib].ibha = p; ibprep(&ibcache[nib]); if (++nib >= MAXIBPORT) break; } closedir(portp); if (nib >= MAXIBPORT) break; } } closedir(contp); } } /* ** get static and variable metrics */ for (i=0; i < nib; i++) { // static metrics from cache strcpy(si->ifb[i].ibname, ibcache[i].ibha); si->ifb[i].portnr = ibcache[i].port; si->ifb[i].lanes = ibcache[i].lanes; si->ifb[i].rate = ibcache[i].rate; // variable metrics from sysfs ibstat(&(ibcache[i]), &(si->ifb[i])); } si->nrports = nib; return 1; } /* ** determine rate and number of lanes ** from /ports//rate --> e.g. "100 Gb/sec (4X EDR)" ** and assemble path names to be used for counters later on */ static void ibprep(struct ibcachent *ibc) { FILE *fp; char path[128], linebuf[64], speedunit; // determine port rate and number of lanes snprintf(path, sizeof path, "%s/ports/%d/rate", ibc->ibha, ibc->port); if ( (fp = fopen(path, "r")) ) { if ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { (void) sscanf(linebuf, "%lld %c%*s (%hdX", &(ibc->rate), &speedunit, &(ibc->lanes)); } fclose(fp); } // calculate megabits/second switch (speedunit) { case 'M': case 'm': break; case 'G': case 'g': ibc->rate *= 1000; break; case 'T': case 't': ibc->rate *= 1000000; break; } // build all pathnames to obtain the counters // of this port later on snprintf(path, sizeof path, "%s/ports/%d/counters/port_rcv_data", ibc->ibha, ibc->port); ibc->pathrcvb = malloc( strlen(path)+1 ); strcpy(ibc->pathrcvb, path); snprintf(path, sizeof path, "%s/ports/%d/counters/port_xmit_data", ibc->ibha, ibc->port); ibc->pathsndb = malloc( strlen(path)+1 ); strcpy(ibc->pathsndb, path); snprintf(path, sizeof path, "%s/ports/%d/counters/port_rcv_packets", ibc->ibha, ibc->port); ibc->pathrcvp = malloc( strlen(path)+1 ); strcpy(ibc->pathrcvp, path); snprintf(path, sizeof path, "%s/ports/%d/counters/port_xmit_packets", ibc->ibha, ibc->port); ibc->pathsndp = malloc( strlen(path)+1 ); strcpy(ibc->pathsndp, path); } /* ** read necessary variable counters for this IB port */ static int ibstat(struct ibcachent *ibc, struct perifb *ifb) { FILE *fp; char linebuf[64]; if ( (fp = fopen(ibc->pathrcvb, "r")) ) { if ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { if (sscanf(linebuf, "%lld", &(ifb->rcvb)) == 0) ifb->rcvb = 0; } else { ifb->rcvb = 0; } fclose(fp); } if ( (fp = fopen(ibc->pathsndb, "r")) ) { if ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { if (sscanf(linebuf, "%lld", &(ifb->sndb)) == 0) ifb->sndb = 0; } else { ifb->sndb = 0; } fclose(fp); } if ( (fp = fopen(ibc->pathrcvp, "r")) ) { if ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { if (sscanf(linebuf, "%lld", &(ifb->rcvp)) == 0) ifb->rcvp = 0; } else { ifb->rcvp = 0; } fclose(fp); } if ( (fp = fopen(ibc->pathsndp, "r")) ) { if ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { if (sscanf(linebuf, "%lld", &(ifb->sndp)) == 0) ifb->sndp = 0; } else { ifb->sndp = 0; } fclose(fp); } return 1; } /* ** retrieve low-level CPU events: ** instructions and cycles per CPU */ #ifndef NOPERFEVENT long perf_event_open(struct perf_event_attr *hwevent, pid_t pid, int cpu, int groupfd, unsigned long flags) { return syscall(__NR_perf_event_open, hwevent, pid, cpu, groupfd, flags); } static void getperfevents(struct cpustat *cs) { static int firstcall = 1, cpualloced, *fdi, *fdc; int i; /* ** once initialize perf event counter retrieval */ if (firstcall) { struct perf_event_attr pea; int success = 0; firstcall = 0; /* ** allocate space for per-cpu file descriptors */ cpualloced = cs->nrcpu; fdi = malloc(sizeof(int) * cpualloced); fdc = malloc(sizeof(int) * cpualloced); /* ** fill perf_event_attr struct with appropriate values */ memset(&pea, 0, sizeof(struct perf_event_attr)); pea.type = PERF_TYPE_HARDWARE; pea.size = sizeof(struct perf_event_attr); pea.inherit = 1; pea.pinned = 1; regainrootprivs(); for (i=0; i < cpualloced; i++) { pea.config = PERF_COUNT_HW_INSTRUCTIONS; if ( (*(fdi+i) = perf_event_open(&pea, -1, i, -1, PERF_FLAG_FD_CLOEXEC)) >= 0) success++; pea.config = PERF_COUNT_HW_CPU_CYCLES; if ( (*(fdc+i) = perf_event_open(&pea, -1, i, -1, PERF_FLAG_FD_CLOEXEC)) >= 0) success++; } if (! droprootprivs()) cleanstop(42); /* ** all failed (probably no kernel support)? */ if (success == 0) { free(fdi); free(fdc); cpualloced = 0; } else { cs->all.instr = 1; cs->all.cycle = 1; } return; // initialization finished for first sample } /* ** every sample: check if counters available anyhow */ if (!cpualloced) return; /* ** retrieve counters per CPU and in total */ cs->all.instr = 0; cs->all.cycle = 0; for (i=0; i < cpualloced; i++) { if (*(fdi+i) != -1) { read(*(fdi+i), &(cs->cpu[i].instr), sizeof(count_t)); cs->all.instr += cs->cpu[i].instr; read(*(fdc+i), &(cs->cpu[i].cycle), sizeof(count_t)); cs->all.cycle += cs->cpu[i].cycle; } } } #endif #if HTTPSTATS /* ** retrieve statistics from local HTTP daemons ** via http://localhost/server-status?auto */ int getwwwstat(unsigned short port, struct wwwstat *wp) { int sockfd, tobefound; FILE *sockfp; struct sockaddr_in sockname; char linebuf[4096]; char label[512]; long long value; memset(wp, 0, sizeof *wp); /* ** allocate a socket and connect to the local HTTP daemon */ if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) return 0; sockname.sin_family = AF_INET; sockname.sin_addr.s_addr = htonl(INADDR_LOOPBACK); sockname.sin_port = htons(port); if ( connect(sockfd, (struct sockaddr *) &sockname, sizeof sockname) == -1) { close(sockfd); return 0; } /* ** write a GET-request for /server-status */ if ( write(sockfd, HTTPREQ, sizeof HTTPREQ) < sizeof HTTPREQ) { close(sockfd); return 0; } /* ** remap socket descriptor to a stream to allow stdio calls */ sockfp = fdopen(sockfd, "r+"); /* ** read response line by line */ tobefound = 5; /* number of values to be searched */ while ( fgets(linebuf, sizeof linebuf, sockfp) && tobefound) { /* ** handle line containing status code */ if ( strncmp(linebuf, "HTTP/", 5) == 0) { sscanf(linebuf, "%511s %lld %*s\n", label, &value); if (value != 200) /* HTTP-request okay? */ { fclose(sockfp); close(sockfd); return 0; } continue; } /* ** decode line and search for the required counters */ if (sscanf(linebuf, "%511[^:]: %lld\n", label, &value) == 2) { if ( strcmp(label, "Total Accesses") == 0) { wp->accesses = value; tobefound--; } if ( strcmp(label, "Total kBytes") == 0) { wp->totkbytes = value; tobefound--; } if ( strcmp(label, "Uptime") == 0) { wp->uptime = value; tobefound--; } if ( strcmp(label, "BusyWorkers") == 0) { wp->bworkers = value; tobefound--; } if ( strcmp(label, "IdleWorkers") == 0) { wp->iworkers = value; tobefound--; } } } fclose(sockfp); close(sockfd); return 1; } #endif atop-2.4.0/photosyst.h0000664000203100020310000002714713416466037014234 0ustar gerlofgerlof/* ** 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. ** ** Include-file describing system-level counters maintained. ** ================================================================ ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Date: November 1996 ** LINUX-port: June 2000 ** ** 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. */ #ifndef __PHOTOSYST__ #define __PHOTOSYST__ #include "netstats.h" #define MAXCPU 2048 #define MAXDSK 1024 #define MAXLVM 2048 #define MAXMDD 256 #define MAXINTF 128 #define MAXCONTAINER 128 #define MAXNFSMOUNT 64 #define MAXIBPORT 32 #define MAXGPU 32 #define MAXGPUBUS 12 #define MAXGPUTYPE 12 #define MAXDKNAM 32 #define MAXIBNAME 12 /************************************************************************/ struct memstat { 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 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 cfuture[8]; // reserved for future use }; /************************************************************************/ struct netstat { 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 { 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 actul freq */ }; struct percpu { 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 freqcnt;/* frequency scaling info */ count_t instr; /* CPU instructions */ count_t cycle; /* CPU cycles */ count_t cfuture[2]; /* reserved for future use */ }; struct cpustat { 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 all; struct percpu cpu[MAXCPU]; }; /************************************************************************/ struct perdsk { char name[MAXDKNAM]; /* 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 cfuture[4]; /* reserved for future use */ }; struct dskstat { int ndsk; /* number of physical disks */ int nmdd; /* number of md volumes */ int nlvm; /* number of logical volumes */ struct perdsk dsk[MAXDSK]; struct perdsk mdd[MAXMDD]; struct perdsk lvm[MAXLVM]; }; /************************************************************************/ struct perintf { 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'/'?') */ 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 { int nrintf; struct perintf intf[MAXINTF]; }; /************************************************************************/ struct pernfsmount { 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 { 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]; } nfsmounts; }; /************************************************************************/ struct psi { 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 { char present; /* pressure stats supported? */ char future[3]; struct psi cpusome; /* pressure stall info 'some' */ struct psi memsome; /* pressure stall info 'some' */ struct psi memfull; /* pressure stall info 'full' */ struct psi iosome; /* pressure stall info 'some' */ struct psi iofull; /* pressure stall info 'full' */ }; /************************************************************************/ struct percontainer { 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 { int nrcontainer; struct percontainer cont[MAXCONTAINER]; }; /************************************************************************/ /* ** experimental stuff for access to local HTTP daemons */ #define HTTPREQ "GET /server-status?auto HTTP/1.1\nHost: localhost\n\n" struct wwwstat { 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 */ }; #if HTTPSTATS int getwwwstat(unsigned short, struct wwwstat *); #endif /************************************************************************/ struct pergpu { char taskstats; // GPU task statistics supported? unsigned char nrprocs; // number of processes using GPU char type[MAXGPUTYPE+1]; // GPU type char busid[MAXGPUBUS+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 { int nrgpus; // total number of GPUs struct pergpu gpu[MAXGPU]; }; /************************************************************************/ struct perifb { char ibname[MAXIBNAME]; // 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 { int nrports; // total number of IB ports struct perifb ifb[MAXIBPORT]; }; /************************************************************************/ struct sstat { struct cpustat cpu; struct memstat mem; struct netstat net; struct intfstat intf; struct dskstat dsk; struct nfsstat nfs; struct contstat cfs; struct pressure psi; struct gpustat gpu; struct ifbstat ifb; struct wwwstat www; }; /* ** prototypes */ void photosyst (struct sstat *); void deviatsyst(struct sstat *, struct sstat *, struct sstat *, long); void totalsyst (char, struct sstat *, struct sstat *); #endif atop-2.4.0/procdbase.c0000664000203100020310000002010113416466037014074 0ustar gerlofgerlof/* ** 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 all functions required to manipulate the ** process-database. This database is implemented as a linked list of ** all running processes, needed to remember the process-counters from ** the previous sample. ** ========================================================================== ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Date: November 1996 ** LINUX-port: June 2000 ** -------------------------------------------------------------------------- ** Copyright (C) 2000-2012 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 ** -------------------------------------------------------------------------- ** ** $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 #include #include #include #include #include #include #include #include "atop.h" #include "photoproc.h" /*****************************************************************************/ #define NPHASH 256 /* number of hash queues for process dbase */ /* MUST be a power of 2 !!! */ /* hash buckets for getting process-info */ /* for a given PID */ static struct pinfo *phash[NPHASH]; /* cyclic list of all processes, to detect */ /* which processes were not referred */ static struct pinfo presidue; /*****************************************************************************/ /* ** search process database for the given PID */ int pdb_gettask(int pid, char isproc, time_t btime, struct pinfo **pinfopp) { register struct pinfo *pp; pp = phash[pid&(NPHASH-1)]; /* get proper hash bucket */ /* ** scan all entries in hash Q */ while (pp) { /* ** if this is required PID, unchain it from the RESIDUE-list ** and return info */ if (pp->tstat.gen.pid == pid && pp->tstat.gen.isproc == isproc ) { int diff = pp->tstat.gen.btime - btime; /* ** with longer intervals, the same PID might be ** found more than once, so also check the start ** time of the task */ if (diff > 1 || diff < -1) { pp = pp->phnext; continue; } if (pp->prnext) /* if part of RESIDUE-list */ { (pp->prnext)->prprev = pp->prprev; /* unchain */ (pp->prprev)->prnext = pp->prnext; } pp->prnext = NULL; pp->prprev = NULL; *pinfopp = pp; return 1; } pp = pp->phnext; } /* ** end of list; PID not found */ return 0; } /* ** add new process-info structure to the process database */ void pdb_addtask(int pid, struct pinfo *pinfop) { register int i = pid&(NPHASH-1); pinfop->phnext = phash[i]; phash[i] = pinfop; } /* ** delete a process from the process database */ int pdb_deltask(int pid, char isproc) { register struct pinfo *pp, *ppp; pp = phash[pid&(NPHASH-1)]; /* get proper hash bucket */ /* ** check first entry in hash Q */ if (pp->tstat.gen.pid == pid && pp->tstat.gen.isproc == isproc) { phash[pid&(NPHASH-1)] = pp->phnext; if ( pp->prnext ) /* still part of RESIDUE-list ? */ { (pp->prprev)->prnext = pp->prnext; (pp->prnext)->prprev = pp->prprev; /* unchain */ } /* ** remove process-info from process-database */ free(pp); return 1; } /* ** scan other entries of hash-list */ ppp = pp; pp = pp->phnext; while (pp) { /* ** if this is wanted PID, unchain it from the RESIDUE-list ** and return info */ if (pp->tstat.gen.pid == pid && pp->tstat.gen.isproc == isproc) { ppp->phnext = pp->phnext; if ( pp->prnext ) /* part of RESIDUE-list ? */ { (pp->prnext)->prprev = pp->prprev; (pp->prprev)->prnext = pp->prnext; } /* ** remove process-info from process-database */ free(pp); return 1; } ppp = pp; pp = pp->phnext; } return 0; /* PID not found */ } /* ** Chain all process-info structures into the RESIDUE-list; ** every process-info struct which is referenced later on by pdb_gettask(), ** will be removed from this list again. After that, the remaining ** (unreferred) process-info structs can be easily discovered and ** eventually removed. */ int pdb_makeresidue(void) { register struct pinfo *pp, *pr; register int i; /* ** prepare RESIDUE-list anchor */ pr = &presidue; pr->prnext = pr; pr->prprev = pr; /* ** check all entries in hash list */ for (i=0; i < NPHASH; i++) { if (!phash[i]) continue; /* empty hash bucket */ pp = phash[i]; /* get start of list */ while (pp) /* all entries in hash list */ { pp->prnext = pr->prnext; pr->prnext = pp; pp->prprev = (pp->prnext)->prprev; (pp->prnext)->prprev = pp; pp = pp->phnext; /* get next of hash list */ } } /* ** all entries chained in doubly-linked RESIDUE-list */ return 1; } /* ** remove all remaining entries in RESIDUE-list */ int pdb_cleanresidue(void) { register struct pinfo *pr; register int pid; char isproc; /* ** start at RESIDUE-list anchor and delete all entries */ pr = presidue.prnext; while (pr != &presidue) { pid = pr->tstat.gen.pid; isproc = pr->tstat.gen.isproc; pr = pr->prnext; /* MUST be done before deletion */ pdb_deltask(pid, isproc); } return 1; } /* ** search in the RESIDUE-list for process-info which may fit to the ** given process-info, for which the PID is not known */ int pdb_srchresidue(struct tstat *tstatp, struct pinfo **pinfopp) { register struct pinfo *pr, *prmin=NULL; register long btimediff; /* ** start at RESIDUE-list anchor and search through ** all remaining entries */ pr = presidue.prnext; while (pr != &presidue) /* still entries left ? */ { /* ** check if this entry matches searched info */ if ( pr->tstat.gen.ruid == tstatp->gen.ruid && pr->tstat.gen.rgid == tstatp->gen.rgid && strcmp(pr->tstat.gen.name, tstatp->gen.name) == EQ ) { /* ** check if the start-time of the process is exactly ** the same ----> then we have a match; ** however sometimes the start-time may deviate a ** second although it IS the process we are looking ** for (depending on the rounding of the boot-time), ** so if we don't find the exact match, we will check ** later on if we found an almost-exact match */ btimediff = pr->tstat.gen.btime - tstatp->gen.btime; if (btimediff == 0) /* gotcha !! */ { *pinfopp = pr; return 1; } if ((btimediff== -1 || btimediff== 1) && prmin== NULL) prmin = pr; /* remember this process */ } pr = pr->prnext; } /* ** nothing found that matched exactly; ** do we remember a process that matched almost exactly? */ if (prmin) { *pinfopp = prmin; return 1; } return 0; /* even not almost */ } atop-2.4.0/rawlog.c0000664000203100020310000005441313416466037013442 0ustar gerlofgerlof/* ** 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. ** ========================================================================== ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Date: September 2002 ** -------------------------------------------------------------------------- ** Copyright (C) 2000-2010 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 ** -------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "atop.h" #include "showgeneric.h" #include "photoproc.h" #include "photosyst.h" #define BASEPATH "/var/log/atop" /* ** structure which describes the raw file contents ** ** layout raw file: rawheader ** ** rawrecord \ ** compressed system-level statistics | sample 1 ** compressed process-level statistics / ** ** rawrecord \ ** compressed system-level statistics | sample 2 ** compressed process-level statistics / ** ** etcetera ..... */ #define MYMAGIC (unsigned int) 0xfeedbeef struct rawheader { unsigned int magic; unsigned short aversion; /* creator atop version with MSB */ unsigned short future1; /* can be reused */ unsigned short future2; /* can be reused */ unsigned short rawheadlen; /* length of struct rawheader */ unsigned short rawreclen; /* length of struct rawrecord */ unsigned short hertz; /* clock interrupts per second */ unsigned short sfuture[6]; /* future use */ unsigned int sstatlen; /* length of struct sstat */ unsigned int tstatlen; /* length of struct tstat */ struct utsname utsname; /* info about this system */ char cfuture[8]; /* future use */ unsigned int pagesize; /* size of memory page (bytes) */ int supportflags; /* used features */ int osrel; /* OS release number */ int osvers; /* OS version number */ int ossub; /* OS version subnumber */ int ifuture[6]; /* future use */ }; struct rawrecord { time_t curtime; /* current time (epoch) */ unsigned short flags; /* various flags */ unsigned short sfuture[3]; /* future use */ unsigned int scomplen; /* length of compressed sstat */ unsigned int pcomplen; /* length of compressed tstat's */ unsigned int interval; /* interval (number of seconds) */ unsigned int ndeviat; /* number of tasks in list */ unsigned int nactproc; /* number of processes in list */ unsigned int ntask; /* total number of tasks */ unsigned int totproc; /* total number of processes */ unsigned int totrun; /* number of running threads */ unsigned int totslpi; /* number of sleeping threads(S)*/ unsigned int totslpu; /* number of sleeping threads(D)*/ unsigned int totzomb; /* number of zombie processes */ unsigned int nexit; /* number of exited processes */ unsigned int noverflow; /* number of overflow processes */ unsigned int ifuture[6]; /* future use */ }; static int getrawrec (int, struct rawrecord *, int); static int getrawsstat(int, struct sstat *, int); static int getrawtstat(int, struct tstat *, int, int); static int rawwopen(void); static int lookslikedatetome(char *); static void testcompval(int, char *); static void try_other_version(int, int); /* ** write a raw record to file ** (file is opened/created during the first call) */ char rawwrite(time_t curtime, int numsecs, struct devtstat *devtstat, struct sstat *sstat, int nexit, unsigned int noverflow, char flag) { static int rawfd = -1; struct rawrecord rr; int rv; struct stat filestat; Byte scompbuf[sizeof(struct sstat)], *pcompbuf; unsigned long scomplen = sizeof scompbuf; unsigned long pcomplen = sizeof(struct tstat) * devtstat->ntaskall; /* ** first call: ** take care that the log file is opened */ if (rawfd == -1) rawfd = rawwopen(); /* ** register current size of file in order to "roll back" ** writes that have been done while not *all* writes could ** succeed, e.g. when file system full */ (void) fstat(rawfd, &filestat); /* ** compress system- and process-level statistics */ rv = compress(scompbuf, &scomplen, (Byte *)sstat, (unsigned long)sizeof *sstat); testcompval(rv, "compress"); pcompbuf = malloc(pcomplen); ptrverify(pcompbuf, "Malloc failed for compression buffer\n"); rv = compress(pcompbuf, &pcomplen, (Byte *)devtstat->taskall, (unsigned long)pcomplen); testcompval(rv, "compress"); /* ** fill record header and write to file */ memset(&rr, 0, sizeof rr); rr.curtime = curtime; rr.interval = numsecs; rr.flags = 0; rr.ndeviat = devtstat->ntaskall; rr.nactproc = devtstat->nprocactive; rr.ntask = devtstat->ntaskall; rr.nexit = nexit; rr.noverflow = noverflow; rr.totproc = devtstat->nprocall; rr.totrun = devtstat->totrun; rr.totslpi = devtstat->totslpi; rr.totslpu = devtstat->totslpu; rr.totzomb = devtstat->totzombie; rr.scomplen = scomplen; rr.pcomplen = pcomplen; if (flag&RRBOOT) rr.flags |= RRBOOT; if (supportflags & ACCTACTIVE) rr.flags |= RRACCTACTIVE; if (supportflags & IOSTAT) rr.flags |= RRIOSTAT; if (supportflags & NETATOP) rr.flags |= RRNETATOP; if (supportflags & NETATOPD) rr.flags |= RRNETATOPD; if (supportflags & DOCKSTAT) rr.flags |= RRDOCKSTAT; if (supportflags & GPUSTAT) rr.flags |= RRGPUSTAT; if ( write(rawfd, &rr, sizeof rr) == -1) { fprintf(stderr, "%s - ", rawname); perror("write raw record"); if ( ftruncate(rawfd, filestat.st_size) == -1) cleanstop(8); cleanstop(7); } /* ** write compressed system status structure to file */ if ( write(rawfd, scompbuf, scomplen) == -1) { fprintf(stderr, "%s - ", rawname); perror("write raw status record"); if ( ftruncate(rawfd, filestat.st_size) == -1) cleanstop(8); cleanstop(7); } /* ** write compressed list of process status structures to file */ if ( write(rawfd, pcompbuf, pcomplen) == -1) { fprintf(stderr, "%s - ", rawname); perror("write raw process record"); if ( ftruncate(rawfd, filestat.st_size) == -1) cleanstop(8); cleanstop(7); } free(pcompbuf); return '\0'; } /* ** open a raw file for writing ** ** if the raw file exists already: ** - read and validate the header record (be sure it is an atop-file) ** - seek to the end of the file ** ** if the raw file does not yet exist: ** - create the raw file ** - write a header record ** ** return the filedescriptor of the raw file */ static int rawwopen() { struct rawheader rh; int fd; /* ** check if the file exists already */ if ( (fd = open(rawname, O_RDWR)) >= 0) { /* ** read and verify header record */ if ( read(fd, &rh, sizeof rh) < sizeof rh) { fprintf(stderr, "%s - cannot read header\n", rawname); cleanstop(7); } if (rh.magic != MYMAGIC) { fprintf(stderr, "file %s exists but does not contain raw " "atop output (wrong magic number)\n", rawname); cleanstop(7); } if ( rh.sstatlen != sizeof(struct sstat) || rh.tstatlen != sizeof(struct tstat) || rh.rawheadlen != sizeof(struct rawheader) || rh.rawreclen != sizeof(struct rawrecord) ) { fprintf(stderr, "existing file %s has incompatible header\n", rawname); if (rh.aversion & 0x8000 && (rh.aversion & 0x7fff) != getnumvers()) { fprintf(stderr, "(created by version %d.%d - " "current version %d.%d)\n", (rh.aversion >> 8) & 0x7f, rh.aversion & 0xff, getnumvers() >> 8, getnumvers() & 0x7f); } cleanstop(7); } (void) lseek(fd, (off_t) 0, SEEK_END); return fd; } /* ** file does not exist (or can not be opened) */ if ( (fd = creat(rawname, 0666)) == -1) { fprintf(stderr, "%s - ", rawname); perror("create raw file"); cleanstop(7); } memset(&rh, 0, sizeof rh); rh.magic = MYMAGIC; rh.aversion = getnumvers() | 0x8000; rh.sstatlen = sizeof(struct sstat); rh.tstatlen = sizeof(struct tstat); rh.rawheadlen = sizeof(struct rawheader); rh.rawreclen = sizeof(struct rawrecord); rh.supportflags = supportflags | RAWLOGNG; rh.osrel = osrel; rh.osvers = osvers; rh.ossub = ossub; rh.hertz = hertz; rh.pagesize = pagesize; memcpy(&rh.utsname, &utsname, sizeof rh.utsname); if ( write(fd, &rh, sizeof rh) == -1) { fprintf(stderr, "%s - ", rawname); perror("write raw header"); cleanstop(7); } return fd; } /* ** read the contents of a raw file */ #define OFFCHUNK 256 void rawread(void) { int i, j, rawfd, len; char *py; struct rawheader rh; struct rawrecord rr; struct sstat sstat; static struct devtstat devtstat; struct stat filestat; /* ** variables to maintain the offsets of the raw records ** to be able to see previous samples again */ off_t *offlist; unsigned int offsize = 0; unsigned int offcur = 0; char lastcmd = 'X', flags; time_t timenow; struct tm *tp; switch ( len = strlen(rawname) ) { /* ** if no filename is specified, assemble the name of the raw file */ case 0: timenow = time(0); tp = localtime(&timenow); snprintf(rawname, RAWNAMESZ, "%s/atop_%04d%02d%02d", BASEPATH, tp->tm_year+1900, tp->tm_mon+1, tp->tm_mday); break; /* ** if date specified as filename in format YYYYMMDD, assemble ** the full pathname of the raw file */ case 8: if ( access(rawname, F_OK) == 0) break; /* existing file */ if (lookslikedatetome(rawname)) { char savedname[RAWNAMESZ]; strncpy(savedname, rawname, RAWNAMESZ-1); snprintf(rawname, RAWNAMESZ, "%s/atop_%s", BASEPATH, savedname); break; } /* ** if one or more 'y' (yesterday) characters are used and that ** string is not known as an existing file, the standard logfile ** is shown from N days ago (N is determined by the number ** of y's). */ default: if ( access(rawname, F_OK) == 0) break; /* existing file */ /* ** make a string existing of y's to compare with */ py = malloc(len+1); ptrverify(py, "Malloc failed for 'yes' sequence\n"); memset(py, 'y', len); *(py+len) = '\0'; if ( strcmp(rawname, py) == 0 ) { timenow = time(0); timenow -= len*3600*24; tp = localtime(&timenow); snprintf(rawname, RAWNAMESZ, "%s/atop_%04d%02d%02d", BASEPATH, tp->tm_year+1900, tp->tm_mon+1, tp->tm_mday); } free(py); } /* ** open raw file */ if ( (rawfd = open(rawname, O_RDONLY)) == -1) { char command[512], tmpname1[RAWNAMESZ], tmpname2[RAWNAMESZ]; /* ** check if a compressed raw file is present */ snprintf(tmpname1, sizeof tmpname1, "%s.gz", rawname); if ( access(tmpname1, F_OK|R_OK) == -1) { fprintf(stderr, "%s - ", rawname); perror("open raw file"); cleanstop(7); } /* ** compressed raw file to be decompressed via gunzip */ fprintf(stderr, "Decompressing logfile ....\n"); snprintf(tmpname2, sizeof tmpname2, "/tmp/atopwrkXXXXXX"); rawfd = mkstemp(tmpname2); if (rawfd == -1) { fprintf(stderr, "%s - ", rawname); perror("creating decompression temp file"); cleanstop(7); } snprintf(command, sizeof command, "gunzip -c %s > %s", tmpname1, tmpname2); const int system_res = system (command); unlink(tmpname2); if (system_res) { fprintf(stderr, "%s - gunzip failed", rawname); cleanstop(7); } } /* ** read the raw header and verify the magic */ if ( read(rawfd, &rh, sizeof rh) < sizeof rh) { fprintf(stderr, "can not read raw file header\n"); cleanstop(7); } if (rh.magic != MYMAGIC) { fprintf(stderr, "file %s does not contain raw atop/atopsar " "output (wrong magic number)\n", rawname); cleanstop(7); } /* ** magic okay, but file-layout might have been modified */ if (rh.sstatlen != sizeof(struct sstat) || rh.tstatlen != sizeof(struct tstat) || rh.rawheadlen != sizeof(struct rawheader) || rh.rawreclen != sizeof(struct rawrecord) ) { fprintf(stderr, "raw file %s has incompatible format\n", rawname); if (rh.aversion & 0x8000 && (rh.aversion & 0x7fff) != getnumvers()) { fprintf(stderr, "(created by version %d.%d - " "current version %d.%d)\n", (rh.aversion >> 8) & 0x7f, rh.aversion & 0xff, getnumvers() >> 8, getnumvers() & 0x7f); } else { fprintf(stderr, "(files from other system architectures might" " be binary incompatible)\n"); } close(rawfd); if (((rh.aversion >> 8) & 0x7f) != (getnumvers() >> 8) || (rh.aversion & 0xff) != (getnumvers() & 0x7f) ) { try_other_version((rh.aversion >> 8) & 0x7f, rh.aversion & 0xff); } cleanstop(7); } memcpy(&utsname, &rh.utsname, sizeof utsname); utsnodenamelen = strlen(utsname.nodename); supportflags = rh.supportflags; osrel = rh.osrel; osvers = rh.osvers; ossub = rh.ossub; interval = 0; if (rh.hertz) hertz = rh.hertz; if (rh.pagesize) pagesize = rh.pagesize; /* ** allocate a list for backtracking of rawrecord-offsets */ offlist = malloc(sizeof(off_t) * OFFCHUNK); ptrverify(offlist, "Malloc failed for backtrack list\n"); offsize = OFFCHUNK; *offlist = lseek(rawfd, 0, SEEK_CUR); offcur = 1; /* ** read a raw record header until end-of-file */ sampcnt = 0; while (lastcmd && lastcmd != 'q') { while ( getrawrec(rawfd, &rr, rh.rawreclen) == rh.rawreclen) { unsigned int secsinday = daysecs(rr.curtime); unsigned int k, l; /* ** store the offset of the raw record in the offset list ** in case of offset list overflow, extend the list */ *(offlist+offcur) = lseek(rawfd, 0, SEEK_CUR) - rh.rawreclen; if ( ++offcur >= offsize ) { offlist = realloc(offlist, (offsize+OFFCHUNK)*sizeof(off_t)); ptrverify(offlist, "Realloc failed for backtrack list\n"); offsize+= OFFCHUNK; } /* ** check if this sample is within the time-range ** specified with the -b and -e flags (if any) */ if ( (begintime && begintime > secsinday) ) { lastcmd = 1; lseek(rawfd, rr.scomplen+rr.pcomplen, SEEK_CUR); continue; } begintime = 0; // allow earlier times from now on if ( (endtime && endtime < secsinday) ) { free(offlist); close(rawfd); return; } /* ** allocate space, read compressed system-level ** statistics and decompress */ if ( !getrawsstat(rawfd, &sstat, rr.scomplen) ) cleanstop(7); /* ** allocate space, read compressed process-level ** statistics and decompress */ devtstat.taskall = malloc(sizeof(struct tstat ) * rr.ndeviat); if (rr.totproc < rr.nactproc) // compat old raw files devtstat.procall = malloc(sizeof(struct tstat *) * rr.nactproc); else devtstat.procall = malloc(sizeof(struct tstat *) * rr.totproc); devtstat.procactive = malloc(sizeof(struct tstat *) * rr.nactproc); ptrverify(devtstat.taskall, "Malloc failed for %d stored tasks\n", rr.ndeviat); ptrverify(devtstat.procall, "Malloc failed for total %d processes\n", rr.totproc); ptrverify(devtstat.procactive, "Malloc failed for %d active processes\n", rr.nactproc); if ( !getrawtstat(rawfd, devtstat.taskall, rr.pcomplen, rr.ndeviat) ) cleanstop(7); for (i=j=k=l=0; i < rr.ndeviat; i++) { if ( (devtstat.taskall+i)->gen.isproc) { devtstat.procall[j++] = devtstat.taskall+i; if (! (devtstat.taskall+i)->gen.wasinactive) devtstat.procactive[k++] = devtstat.taskall+i; } if (! (devtstat.taskall+i)->gen.wasinactive) l++; } devtstat.ntaskall = i; devtstat.nprocall = j; devtstat.nprocactive = k; devtstat.ntaskactive = l; devtstat.totrun = rr.totrun; devtstat.totslpi = rr.totslpi; devtstat.totslpu = rr.totslpu; devtstat.totzombie = rr.totzomb; /* ** activate the installed print-function to visualize ** the system- and process-level statistics */ sampcnt++; if ( (rh.supportflags & RAWLOGNG) == RAWLOGNG) { if (rr.flags & RRACCTACTIVE) supportflags |= ACCTACTIVE; else supportflags &= ~ACCTACTIVE; if (rr.flags & RRIOSTAT) supportflags |= IOSTAT; else supportflags &= ~IOSTAT; } if (rr.flags & RRNETATOP) supportflags |= NETATOP; else supportflags &= ~NETATOP; if (rr.flags & RRNETATOPD) supportflags |= NETATOPD; else supportflags &= ~NETATOPD; if (rr.flags & RRDOCKSTAT) supportflags |= DOCKSTAT; else supportflags &= ~DOCKSTAT; if (rr.flags & RRGPUSTAT) supportflags |= GPUSTAT; else supportflags &= ~GPUSTAT; flags = rr.flags & RRBOOT; nrgpus = sstat.gpu.nrgpus; (void) fstat(rawfd, &filestat); if ( filestat.st_size - lseek(rawfd, (off_t)0, SEEK_CUR) <= rh.rawreclen) flags |= RRLAST; lastcmd = (vis.show_samp)(rr.curtime, rr.interval, &devtstat, &sstat, rr.nexit, rr.noverflow, flags); free(devtstat.taskall); free(devtstat.procall); free(devtstat.procactive); switch (lastcmd) { case MSAMPPREV: if (offcur >= 2) offcur-= 2; else offcur = 0; lseek(rawfd, *(offlist+offcur), SEEK_SET); break; case MRESET: lseek(rawfd, *offlist, SEEK_SET); offcur = 1; break; case MSAMPBRANCH: if (begintime && begintime < secsinday) { lseek(rawfd, *offlist, SEEK_SET); offcur = 1; } } } begintime = 0; // allow earlier times from now on if (offcur >= 1) offcur--; lseek(rawfd, *(offlist+offcur), SEEK_SET); } free(offlist); close(rawfd); } /* ** read the next raw record from the raw logfile */ static int getrawrec(int rawfd, struct rawrecord *prr, int rrlen) { return read(rawfd, prr, rrlen); } /* ** read the system-level statistics from the current offset */ static int getrawsstat(int rawfd, struct sstat *sp, int complen) { Byte *compbuf; unsigned long uncomplen = sizeof(struct sstat); int rv; if ( (compbuf = malloc(complen)) == NULL) ptrverify(compbuf, "Malloc failed for reading compressed sysstats\n"); if ( read(rawfd, compbuf, complen) < complen) { free(compbuf); return 0; } rv = uncompress((Byte *)sp, &uncomplen, compbuf, complen); testcompval(rv, "uncompress"); free(compbuf); return 1; } /* ** read the process-level statistics from the current offset */ static int getrawtstat(int rawfd, struct tstat *pp, int complen, int ndeviat) { Byte *compbuf; unsigned long uncomplen = sizeof(struct tstat) * ndeviat; int rv; compbuf = malloc(complen); ptrverify(compbuf, "Malloc failed for reading compressed procstats\n"); if ( read(rawfd, compbuf, complen) < complen) { free(compbuf); return 0; } rv = uncompress((Byte *)pp, &uncomplen, compbuf, complen); testcompval(rv, "uncompress"); free(compbuf); return 1; } /* ** verify if a particular ascii-string is in the format yyyymmdd */ static int lookslikedatetome(char *p) { register int i; for (i=0; i < 8; i++) if ( !isdigit(*(p+i)) ) return 0; if (*p != '2') return 0; /* adapt this in the year 3000 */ if ( *(p+4) > '1') return 0; if ( *(p+6) > '3') return 0; return 1; /* yes, looks like a date to me */ } static void testcompval(int rv, char *func) { switch (rv) { case Z_OK: case Z_STREAM_END: case Z_NEED_DICT: break; case Z_MEM_ERROR: fprintf(stderr, "atop/atopsar - " "%s: failed due to lack of memory\n", func); cleanstop(7); case Z_BUF_ERROR: fprintf(stderr, "atop/atopsar - " "%s: failed due to lack of room in buffer\n", func); cleanstop(7); case Z_DATA_ERROR: fprintf(stderr, "atop/atopsar - " "%s: failed due to corrupted/incomplete data\n", func); cleanstop(7); default: fprintf(stderr, "atop/atopsar - " "%s: unexpected error %d\n", func, rv); cleanstop(7); } } /* ** try to activate another atop- or atopsar-version ** to read this logfile */ static void try_other_version(int majorversion, int minorversion) { char tmpbuf[1024], *p; extern char **argvp; int fds; struct rlimit rlimit; int setresuid(uid_t, uid_t, uid_t); /* ** prepare name of executable file ** the current pathname (if any) is stripped off */ snprintf(tmpbuf, sizeof tmpbuf, "%s-%d.%d", (p = strrchr(*argvp, '/')) ? p+1 : *argvp, majorversion, minorversion); fprintf(stderr, "trying to activate %s....\n", tmpbuf); /* ** be sure no open file descriptors are passed ** except stdin, stdout en stderr */ (void) getrlimit(RLIMIT_NOFILE, &rlimit); for (fds=3; fds < rlimit.rlim_cur; fds++) close(fds); /* ** be absolutely sure not to pass setuid-root privileges ** to the loaded program; errno EAGAIN and ENOMEM are not ** acceptable! */ if ( setresuid(getuid(), getuid(), getuid()) == -1 && errno != EPERM) { fprintf(stderr, "not possible to drop root-privileges!\n"); exit(1); } /* ** load alternative executable image ** at this moment the saved-uid might still be set ** to 'root' but this is reset at the moment of exec */ (void) execvp(tmpbuf, argvp); /* ** point of no return, except when exec failed */ fprintf(stderr, "activation of %s failed!\n", tmpbuf); } atop-2.4.0/showgeneric.c0000664000203100020310000022564513416466037014473 0ustar gerlofgerlof/* ** 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 the print-functions to visualize the calculated ** figures. ** ========================================================================== ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Date: November 1996 ** LINUX-port: June 2000 ** -------------------------------------------------------------------------- ** Copyright (C) 2000-2010 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 ** -------------------------------------------------------------------------- ** ** $Log: showgeneric.c,v $ ** Revision 1.71 2010/10/25 19:08:32 gerlof ** When the number of lines is too small for the system-level ** lines, limit the number of variable resources automatically ** to a minimum. ** ** Revision 1.70 2010/10/23 14:04:05 gerlof ** Counters for total number of running and sleep threads (JC van Winkel). ** ** Revision 1.69 2010/04/23 12:19:35 gerlof ** Modified mail-address in header. ** ** Revision 1.68 2010/04/23 09:58:11 gerlof ** Version (flag -V) handled earlier after startup. ** ** Revision 1.67 2010/04/23 07:57:32 gerlof ** Proper sorting of processes when switching from single process view ** to cumulative view (key 'u' or 'p') and vice versa. ** ** Revision 1.66 2010/04/17 17:20:26 gerlof ** Allow modifying the layout of the columns in the system lines. ** ** Revision 1.65 2010/03/16 21:13:38 gerlof ** Program and user selection can be combined with program and user ** accumulation. ** ** Revision 1.64 2010/03/16 20:18:46 gerlof ** Show in header-line if user selections and program selection are active. ** ** Revision 1.63 2010/03/16 20:08:51 gerlof ** Performance improvement: only sort system-resources once per interval. ** ** Revision 1.62 2010/03/04 10:53:01 gerlof ** Support I/O-statistics on logical volumes and MD devices. ** ** Revision 1.61 2009/12/17 10:55:07 gerlof ** *** empty log message *** ** ** Revision 1.60 2009/12/17 10:50:30 gerlof ** Allow own defined process line with key 'o' and a definition ** in the atoprc file. ** ** Revision 1.59 2009/12/17 09:03:26 gerlof ** Center message "....since boot" in status line on first screen. ** ** Revision 1.58 2009/12/17 08:55:15 gerlof ** Show messages on status line in color to draw attention. ** ** Revision 1.57 2009/12/17 08:16:14 gerlof ** Introduce branch-key to go to specific time in raw file. ** ** Revision 1.56 2009/12/12 09:06:39 gerlof ** Corrected cumulated disk I/O per user/program (JC van Winkel). ** ** Revision 1.55 2009/12/10 13:34:44 gerlof ** Show which toggle-keys are active in the header line. ** ** Revision 1.54 2009/12/10 11:55:03 gerlof ** Introduce system-wide /etc/atoprc ** ** Revision 1.53 2009/12/10 09:53:08 gerlof ** Improved display of header-line (JC van Winkel). ** ** Revision 1.52 2008/03/06 10:14:01 gerlof ** Modified help-messages. ** ** Revision 1.51 2008/02/25 13:47:21 gerlof ** Bug-solution: segmentation-fault in case of invalid regular expression. ** ** Revision 1.50 2008/01/07 11:33:58 gerlof ** Cosmetic changes. ** ** Revision 1.49 2008/01/07 10:18:24 gerlof ** Implement possibility to make summaries with atopsar. ** ** Revision 1.48 2007/03/22 10:12:17 gerlof ** Support for io counters (>= kernel 2.6.20). ** ** Revision 1.47 2007/03/21 14:22:34 gerlof ** Handle io counters maintained from 2.6.20 ** ** Revision 1.46 2007/03/20 11:13:15 gerlof ** Cosmetic changes. ** ** Revision 1.45 2007/03/09 12:39:59 gerlof ** Do not allow 'N' and 'D' when kernel-patch is not installed. ** ** Revision 1.44 2007/02/13 10:31:53 gerlof ** Removal of external declarations. ** ** Revision 1.43 2007/01/18 10:41:45 gerlof ** Add support for colors. ** Add support for automatic determination of most critical resource. ** ** Revision 1.42 2006/11/13 13:48:36 gerlof ** Implement load-average counters, context-switches and interrupts. ** ** Revision 1.41 2006/04/03 05:42:35 gerlof ** *** empty log message *** ** ** Revision 1.40 2006/02/07 08:28:26 gerlof ** Improve screen-handling (less flashing) by exchanging clear() ** by werase() (contribution Folkert van Heusden). ** ** Revision 1.39 2005/11/04 14:16:16 gerlof ** Minor bug-solutions. ** ** Revision 1.38 2005/10/28 09:52:03 gerlof ** All flags/subcommands are defined as macro's. ** Subcommand 'p' has been changed to 'z' (pause). ** ** Revision 1.37 2005/10/24 06:12:17 gerlof ** Flag -L modified into -l. ** ** Revision 1.36 2005/10/21 09:50:46 gerlof ** Per-user accumulation of resource consumption. ** Possibility to send signal to process. ** ** Revision 1.35 2004/12/14 15:06:41 gerlof ** Implementation of patch-recognition for disk and network-statistics. ** ** Revision 1.34 2004/09/27 11:01:13 gerlof ** Corrected usage-info as suggested by Edelhard Becker. ** ** Revision 1.33 2004/09/13 09:19:14 gerlof ** Modify subcommands (former 's' -> 'v', 'v' -> 'V', new 's'). ** ** Revision 1.32 2004/08/31 09:52:47 root ** information about underlying threads. ** ** Revision 1.31 2004/06/01 11:57:58 gerlof ** Regular expressions for selections on process-name and user-name. ** ** Revision 1.30 2003/07/07 09:27:24 gerlof ** Cleanup code (-Wall proof). ** ** Revision 1.29 2003/07/03 11:16:42 gerlof ** Implemented subcommand `r' (reset). ** ** Revision 1.28 2003/06/30 11:29:49 gerlof ** Handle configuration file ~/.atoprc ** ** Revision 1.27 2003/06/24 06:21:57 gerlof ** Limit number of system resource lines. ** ** Revision 1.26 2003/02/07 10:19:18 gerlof ** Possibility to show the version number and date. ** ** Revision 1.25 2003/01/17 07:32:16 gerlof ** Show the full command-line per process (option 'c'). ** ** Revision 1.24 2002/10/30 13:47:20 gerlof ** Generate notification for statistics since boot. ** ** Revision 1.23 2002/10/08 12:00:30 gerlof ** *** empty log message *** ** ** Revision 1.22 2002/09/26 14:17:39 gerlof ** No beep when resizing the window. ** ** Revision 1.21 2002/09/26 13:52:26 gerlof ** Limit header lines by not showing disks. ** ** Revision 1.20 2002/09/18 07:15:59 gerlof ** Modified viewflag to rawreadflag. ** ** Revision 1.19 2002/09/17 13:17:39 gerlof ** Allow key 'T' to be pressed to view previous sample in raw file. ** ** Revision 1.18 2002/08/30 07:11:50 gerlof ** Minor changes to support viewing of raw atop data. ** ** Revision 1.17 2002/08/27 12:10:12 gerlof ** Allow raw data file to be written and to be read (with compression). ** ** Revision 1.16 2002/07/24 11:12:46 gerlof ** Changed to ease porting to other UNIX-platforms. ** ** Revision 1.15 2002/07/11 09:12:05 root ** Some minor updates. ** ** Revision 1.14 2002/07/10 05:00:37 root ** Counters pin/pout renamed to swin/swout (Linux conventions). ** ** Revision 1.13 2002/07/08 09:29:49 root ** Limitation for username and groupname (8 characters truncate). ** ** Revision 1.12 2002/07/02 07:14:02 gerlof ** More positions for the name of the disk-unit in the DSK-line. ** ** Revision 1.11 2002/01/22 13:40:42 gerlof ** Support for number of cpu's. ** Check if the window is large enough for the system-statistics. ** ** Revision 1.10 2001/11/30 09:09:36 gerlof ** Cosmetic chnage. ** ** Revision 1.9 2001/11/29 10:41:44 gerlof ** *** empty log message *** ** ** Revision 1.8 2001/11/29 10:38:16 gerlof ** Exit-code correctly printed. ** ** Revision 1.7 2001/11/26 11:18:45 gerlof ** Modified generic output in case that the kernel-patch is not installed. ** ** Revision 1.6 2001/11/13 08:24:50 gerlof ** Show blank columns for sockets and disk I/O when no kernel-patch installed. ** ** Revision 1.5 2001/11/07 09:19:28 gerlof ** Use /proc instead of /dev/kmem for process-level statistics. ** ** Revision 1.4 2001/10/05 13:46:32 gerlof ** Implemented paging through the process-list ** ** Revision 1.3 2001/10/04 08:47:27 gerlof ** Improved handling of error-messages ** ** Revision 1.2 2001/10/03 08:57:53 gerlof ** Improved help-screen shown in scrollable window ** ** Revision 1.1 2001/10/02 10:43:34 gerlof ** Initial revision ** */ static const char rcsid[] = "$Id: showgeneric.c,v 1.71 2010/10/25 19:08:32 gerlof Exp $"; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "atop.h" #include "photoproc.h" #include "photosyst.h" #include "showgeneric.h" #include "showlinux.h" static struct pselection procsel = {"", {USERSTUB, }, {0,}, "", 0, { 0, }, "", 0, { 0, } }; 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 avgval; /* boolean: average values i.s.o. total */ static int suppressexit; /* boolean: suppress exited processes */ static char showtype = MPROCGEN; static char showorder = MSORTCPU; static int maxcpulines = 999; /* maximum cpu lines */ static int maxgpulines = 999; /* maximum gpu lines */ static int maxdsklines = 999; /* maximum disk lines */ static int maxmddlines = 999; /* maximum MDD lines */ static int maxlvmlines = 999; /* maximum LVM lines */ static int maxintlines = 999; /* maximum interface lines */ static int maxifblines = 999; /* maximum infinibnd lines */ static int maxnfslines = 999; /* maximum nfs mount lines */ static int maxcontlines = 999; /* maximum container lines */ static short colorinfo = COLOR_GREEN; static short coloralmost = COLOR_CYAN; static short colorcrit = COLOR_RED; static short colorthread = COLOR_YELLOW; static int cumusers(struct tstat **, struct tstat *, int); static int cumprogs(struct tstat **, struct tstat *, int); static int cumconts(struct tstat **, struct tstat *, int); static void accumulate(struct tstat *, struct tstat *); static int procsuppress(struct tstat *, struct pselection *); static void limitedlines(void); static long getnumval(char *, long, int); static void generic_init(void); static int (*procsort[])(const void *, const void *) = { [MSORTCPU&0x1f]=compcpu, [MSORTMEM&0x1f]=compmem, [MSORTDSK&0x1f]=compdsk, [MSORTNET&0x1f]=compnet, [MSORTGPU&0x1f]=compgpu, }; extern proc_printpair ownprocs[]; /* ** global: incremented by -> key and decremented by <- key */ int startoffset; /* ** print the deviation-counters on process- and system-level */ 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; register int i, curline, statline, nproc; int firstproc = 0, plistsz, alistsz, killpid, killsig; int lastchar; char format1[16], format2[16], hhmm[16]; char *statmsg = NULL, statbuf[80], genline[80]; char *lastsortp, curorder, autoorder; char buf[33]; struct passwd *pwd; struct syscap syscap; /* ** curlist points to the active list of tstat-pointers that ** should be displayed; ncurlist indicates the number of entries in ** this list */ struct tstat **curlist; int ncurlist; /* ** tXcumlist is a list of tstat-structs holding one entry ** per accumulated (per user or per program) group of processes ** ** Xcumlist contains the pointers to all structs in tXcumlist ** ** these lists will only be allocated 'lazy' ** only when accumulation is requested */ struct tstat *tpcumlist = 0; // per program accumulation struct tstat **pcumlist = 0; int npcum = 0; char plastorder = 0; struct tstat *tucumlist = 0; // per user accumulation struct tstat **ucumlist = 0; int nucum = 0; char ulastorder = 0; struct tstat *tccumlist = 0; // per container accumulation struct tstat **ccumlist = 0; int nccum = 0; char clastorder = 0; /* ** tsklist contains the pointers to all structs in tstat ** sorted on process with the related threads immediately ** following the process ** ** this list will be allocated 'lazy' */ struct tstat **tsklist = 0; int ntsk = 0; char tlastorder = 0; char zipagain = 0; char tdeviate = 0; /* ** sellist contains the pointers to the structs in tstat ** that are currently selected on basis of a particular ** username (regexp), program name (regexp), container name ** or suppressed exited procs ** ** this list will be allocated 'lazy' */ struct tstat **sellist = 0; int nsel = 0; char slastorder = 0; char threadallowed = 0; if (callnr == 0) /* first call? */ generic_init(); callnr++; startoffset = 0; /* ** compute the total capacity of this system for the ** four main resources */ totalcap(&syscap, sstat, devtstat->procactive, devtstat->nprocactive); /* ** sort per-cpu statistics on busy percentage ** sort per-logical-volume statistics on busy percentage ** sort per-multiple-device statistics on busy percentage ** sort per-disk statistics on busy percentage ** sort per-interface statistics on busy percentage (if known) */ if (!sysnosort) { if (sstat->cpu.nrcpu > 1 && maxcpulines > 0) qsort(sstat->cpu.cpu, sstat->cpu.nrcpu, sizeof sstat->cpu.cpu[0], cpucompar); if (sstat->gpu.nrgpus > 1 && maxgpulines > 0) qsort(sstat->gpu.gpu, sstat->gpu.nrgpus, sizeof sstat->gpu.gpu[0], gpucompar); if (sstat->dsk.nlvm > 1 && maxlvmlines > 0) qsort(sstat->dsk.lvm, sstat->dsk.nlvm, sizeof sstat->dsk.lvm[0], diskcompar); if (sstat->dsk.nmdd > 1 && maxmddlines > 0) qsort(sstat->dsk.mdd, sstat->dsk.nmdd, sizeof sstat->dsk.mdd[0], diskcompar); if (sstat->dsk.ndsk > 1 && maxdsklines > 0) qsort(sstat->dsk.dsk, sstat->dsk.ndsk, sizeof sstat->dsk.dsk[0], diskcompar); if (sstat->intf.nrintf > 1 && maxintlines > 0) qsort(sstat->intf.intf, sstat->intf.nrintf, sizeof sstat->intf.intf[0], intfcompar); if (sstat->ifb.nrports > 1 && maxifblines > 0) qsort(sstat->ifb.ifb, sstat->ifb.nrports, sizeof sstat->ifb.ifb[0], ifbcompar); if (sstat->nfs.nfsmounts.nrmounts > 1 && maxnfslines > 0) qsort(sstat->nfs.nfsmounts.nfsmnt, sstat->nfs.nfsmounts.nrmounts, sizeof sstat->nfs.nfsmounts.nfsmnt[0], nfsmcompar); if (sstat->cfs.nrcontainer > 1 && maxcontlines > 0) qsort(sstat->cfs.cont, sstat->cfs.nrcontainer, sizeof sstat->cfs.cont[0], contcompar); } /* ** loop in which the system resources and the list of active ** processes are shown; the loop will be preempted by receiving ** a timer-signal or when the trigger-button is pressed. */ while (1) { curline = 1; /* ** prepare screen or file output for new sample */ if (screen) werase(stdscr); else printf("\n\n"); /* ** print general headerlines */ convdate(curtime, format1); /* date to ascii string */ convtime(curtime, format2); /* time to ascii string */ if (screen) attron(A_REVERSE); int seclen = val2elapstr(nsecs, buf); int lenavail = (screen ? COLS : linelen) - 49 - seclen - utsnodenamelen; int len1 = lenavail / 3; int len2 = lenavail - len1 - len1; printg("ATOP - %s%*s%s %s%*s%c%c%c%c%c%c%c%c%c%c%c%c%c%c%*s%s" " elapsed", utsname.nodename, len1, "", format1, format2, len1, "", threadview ? MTHREAD : '-', fixedhead ? MSYSFIXED : '-', sysnosort ? MSYSNOSORT : '-', deviatonly ? '-' : MALLPROC, usecolors ? '-' : MCOLORS, avgval ? MAVGVAL : '-', calcpss ? MCALCPSS : '-', suppressexit ? MSUPEXITS : '-', procsel.userid[0] != USERSTUB ? MSELUSER : '-', procsel.prognamesz ? MSELPROC : '-', procsel.container[0] ? MSELCONT : '-', procsel.pid[0] != 0 ? MSELPID : '-', procsel.argnamesz ? MSELARG : '-', syssel.lvmnamesz + syssel.dsknamesz + syssel.itfnamesz ? MSELSYS : '-', len2, "", buf); if (screen) attroff(A_REVERSE); else printg("\n"); /* ** print cumulative system- and user-time for all processes */ pricumproc(sstat, devtstat, nexit, noverflow, avgval, nsecs); if (noverflow) { snprintf(statbuf, sizeof statbuf, "Only %d exited processes handled " "-- %u skipped!", nexit, noverflow); statmsg = statbuf; } curline=2; /* ** print other lines of system-wide statistics */ if (showorder == MSORTAUTO) autoorder = MSORTCPU; else autoorder = showorder; curline = prisyst(sstat, curline, nsecs, avgval, fixedhead, &syssel, &autoorder, maxcpulines, maxgpulines, maxdsklines, maxmddlines, maxlvmlines, maxintlines, maxifblines, maxnfslines, maxcontlines); /* ** if system-wide statistics do not fit, ** limit the number of variable resource lines ** and try again */ if (screen && curline+2 > LINES) { curline = 2; move(curline, 0); clrtobot(); move(curline, 0); limitedlines(); curline = prisyst(sstat, curline, nsecs, avgval, fixedhead, &syssel, &autoorder, maxcpulines, maxgpulines, maxdsklines, maxmddlines, maxlvmlines, maxintlines, maxifblines, maxnfslines, maxcontlines); /* ** if system-wide statistics still do not fit, ** the window is really to small */ if (curline+2 > LINES) { endwin(); // finish curses interface fprintf(stderr, "Not enough screen-lines available " "(need at least %d lines)\n", curline+2); fprintf(stderr, "Please resize window....\n"); cleanstop(1); } else { statmsg = "Number of variable resources" " limited to fit in this window"; } } statline = curline; if (screen) move(curline, 0); if (statmsg) { if (screen) { clrtoeol(); if (usecolors) attron(COLOR_PAIR(COLORINFO)); } printg(statmsg); if (screen) { if (usecolors) attroff(COLOR_PAIR(COLORINFO)); } statmsg = NULL; } else { if (flag&RRBOOT) { if (screen) { if (usecolors) attron(COLOR_PAIR(COLORINFO)); attron(A_BLINK); printg("%*s", (COLS-45)/2, " "); } else { printg(" "); } printg("*** system and process activity " "since boot ***"); if (screen) { if (usecolors) attroff(COLOR_PAIR(COLORINFO)); attroff(A_BLINK); } } } /* ** select the required list with tasks to be shown ** ** if cumulative figures required, accumulate resource ** consumption of all processes in the current list */ switch (showtype) { case MCUMUSER: threadallowed = 0; if (ucumlist) /* previous list still available? */ { free(ucumlist); free(tucumlist); ulastorder = 0; } if (deviatonly) nproc = devtstat->nprocactive; else nproc = devtstat->nprocall; /* ** allocate space for new (temporary) list with ** one entry per user (list has worst-case size) */ tucumlist = calloc(sizeof(struct tstat), nproc); ucumlist = malloc(sizeof(struct tstat *) * nproc); ptrverify(tucumlist, "Malloc failed for %d ucum procs\n", nproc); ptrverify(ucumlist, "Malloc failed for %d ucum ptrs\n", nproc); for (i=0; i < nproc; i++) { /* fill pointers */ ucumlist[i] = tucumlist+i; } nucum = cumusers(deviatonly ? devtstat->procactive : devtstat->procall, tucumlist, nproc); curlist = ucumlist; ncurlist = nucum; lastsortp = &ulastorder; break; case MCUMPROC: threadallowed = 0; if (pcumlist) /* previous list still available? */ { free(pcumlist); free(tpcumlist); plastorder = 0; } if (deviatonly) nproc = devtstat->nprocactive; else nproc = devtstat->nprocall; /* ** allocate space for new (temporary) list with ** one entry per program (list has worst-case size) */ tpcumlist = calloc(sizeof(struct tstat), nproc); pcumlist = malloc(sizeof(struct tstat *) * nproc); ptrverify(tpcumlist, "Malloc failed for %d pcum procs\n", nproc); ptrverify(pcumlist, "Malloc failed for %d pcum ptrs\n", nproc); for (i=0; i < nproc; i++) { /* fill pointers */ pcumlist[i] = tpcumlist+i; } npcum = cumprogs(deviatonly ? devtstat->procactive : devtstat->procall, tpcumlist, nproc); curlist = pcumlist; ncurlist = npcum; lastsortp = &plastorder; break; case MCUMCONT: threadallowed = 0; if (ccumlist) /* previous list still available? */ { free(ccumlist); free(tccumlist); clastorder = 0; } if (deviatonly) nproc = devtstat->nprocactive; else nproc = devtstat->nprocall; /* ** allocate space for new (temporary) list with ** one entry per user (list has worst-case size) */ tccumlist = calloc(sizeof(struct tstat), nproc); ccumlist = malloc(sizeof(struct tstat *) * nproc); ptrverify(tccumlist, "Malloc failed for %d ccum procs\n", nproc); ptrverify(ccumlist, "Malloc failed for %d ccum ptrs\n", nproc); for (i=0; i < nproc; i++) { /* fill pointers */ ccumlist[i] = tccumlist+i; } nccum = cumconts(deviatonly ? devtstat->procactive : devtstat->procall, tccumlist, nproc); curlist = ccumlist; ncurlist = nccum; lastsortp = &clastorder; break; default: threadallowed = 1; if (deviatonly && showtype != MPROCMEM && showorder != MSORTMEM ) { curlist = devtstat->procactive; ncurlist = devtstat->nprocactive; } else { curlist = devtstat->procall; ncurlist = devtstat->nprocall; } lastsortp = &tlastorder; if ( procsel.userid[0] == USERSTUB && !procsel.prognamesz && !procsel.container[0] && !procsel.argnamesz && !procsel.pid[0] && !suppressexit ) /* no selection wanted */ break; /* ** selection specified for tasks: ** create new (worst case) pointer list if needed */ if (sellist) // remove previous list if needed free(sellist); sellist = malloc(sizeof(struct tstat *) * ncurlist); ptrverify(sellist, "Malloc failed for %d select ptrs\n", ncurlist); for (i=nsel=0; i < ncurlist; i++) { if (procsuppress(*(curlist+i), &procsel)) continue; if (curlist[i]->gen.state == 'E' && suppressexit ) continue; sellist[nsel++] = curlist[i]; } curlist = sellist; ncurlist = nsel; tlastorder = 0; /* new sort and zip normal view */ slastorder = 0; /* new sort and zip now */ lastsortp = &slastorder; } /* ** sort the list in required order ** (default CPU-consumption) and print the list */ if (showorder == MSORTAUTO) curorder = autoorder; else curorder = showorder; /* ** determine size of list to be displayed */ if (screen) plistsz = LINES-curline-2; else if (threadview && threadallowed) plistsz = devtstat->ntaskactive; else plistsz = ncurlist; if (ncurlist > 0 && plistsz > 0) { /* ** if sorting order is changed, sort again */ if (*lastsortp != curorder) { qsort(curlist, ncurlist, sizeof(struct tstat *), procsort[(int)curorder&0x1f]); *lastsortp = curorder; zipagain = 1; } if (threadview && threadallowed) { int ntotal, j, t; if (deviatonly && showtype != MPROCMEM && showorder != MSORTMEM ) ntotal = devtstat->ntaskactive; else ntotal = devtstat->ntaskall; /* ** check if existing pointer list still usable ** if not, allocate new pointer list to be able ** to zip process list with references to threads */ if (!tsklist || ntsk != ntotal || tdeviate != deviatonly) { if (tsklist) free(tsklist); // remove current tsklist = malloc(sizeof(struct tstat *) * ntotal); ptrverify(tsklist, "Malloc failed for %d taskptrs\n", ntotal); ntsk = ntotal; tdeviate = deviatonly; zipagain = 1; } else j = ntotal; if (zipagain) { struct tstat *tall = devtstat->taskall; struct tstat *pcur; for (i=j=0; i < ncurlist; i++) { pcur = curlist[i]; tsklist[j++] = pcur; for (t = pcur - tall + 1; t < devtstat->ntaskall && pcur->gen.tgid && pcur->gen.tgid == (tall+t)->gen.tgid; t++) { if (deviatonly && showtype != MPROCMEM && showorder != MSORTMEM ) { if (!(tall+t)->gen.wasinactive) { tsklist[j++] = tall+t; } } else tsklist[j++] = tall+t; } } zipagain = 0; } curlist = tsklist; ncurlist = j; } /* ** print the header ** first determine the column-header for the current ** sorting order of processes */ if (screen) { attron(A_REVERSE); move(curline+1, 0); } priphead(firstproc/plistsz+1, (ncurlist-1)/plistsz+1, &showtype, &curorder, showorder == MSORTAUTO ? 1 : 0); if (screen) { attroff(A_REVERSE); clrtobot(); } /* ** print the list */ priproc(curlist, firstproc, ncurlist, curline+2, firstproc/plistsz+1, (ncurlist-1)/plistsz+1, showtype, curorder, &syscap, nsecs, avgval); } alistsz = ncurlist; /* preserve size of active list */ /* ** in case of writing to a terminal, the user can also enter ** a character to switch options, etc */ if (screen) { /* ** show blinking pause-indication if necessary */ if (paused) { move(statline, COLS-6); attron(A_BLINK); attron(A_REVERSE); printw("PAUSED"); attroff(A_REVERSE); attroff(A_BLINK); } /* ** await input-character or interval-timer expiration */ switch ( (lastchar = mvgetch(statline, 0)) ) { /* ** timer expired */ case ERR: case 0: timeout(0); (void) getch(); timeout(-1); if (tpcumlist) free(tpcumlist); if (pcumlist) free(pcumlist); if (tucumlist) free(tucumlist); if (ucumlist) free(ucumlist); if (tccumlist) free(tccumlist); if (ccumlist) free(ccumlist); if (tsklist) free(tsklist); if (sellist) free(sellist); return lastchar; /* ** stop it */ case MQUIT: move(LINES-1, 0); clrtoeol(); refresh(); cleanstop(0); /* ** manual trigger for next sample */ case MSAMPNEXT: if (paused) break; getalarm(0); if (tpcumlist) free(tpcumlist); if (pcumlist) free(pcumlist); if (tucumlist) free(tucumlist); if (ucumlist) free(ucumlist); if (tccumlist) free(tccumlist); if (ccumlist) free(ccumlist); if (tsklist) free(tsklist); if (sellist) free(sellist); return lastchar; /* ** manual trigger for previous sample */ case MSAMPPREV: if (!rawreadflag) { statmsg = "Only allowed when viewing " "raw file!"; beep(); break; } if (paused) break; if (tpcumlist) free(tpcumlist); if (pcumlist) free(pcumlist); if (tucumlist) free(tucumlist); if (ucumlist) free(ucumlist); if (tccumlist) free(tccumlist); if (ccumlist) free(ccumlist); if (tsklist) free(tsklist); if (sellist) free(sellist); return lastchar; /* ** branch to certain time stamp */ case MSAMPBRANCH: if (!rawreadflag) { statmsg = "Only allowed when viewing " "raw file!"; beep(); break; } if (paused) break; echo(); move(statline, 0); clrtoeol(); printw("Enter new time (format hh:mm): "); hhmm[0] = '\0'; scanw("%15s\n", hhmm); noecho(); if ( !hhmm2secs(hhmm, &begintime) ) { move(statline, 0); clrtoeol(); statmsg = "Wrong time format!"; beep(); begintime = 0; break; } if (tpcumlist) free(tpcumlist); if (pcumlist) free(pcumlist); if (tucumlist) free(tucumlist); if (ucumlist) free(ucumlist); if (tccumlist) free(tccumlist); if (ccumlist) free(ccumlist); if (tsklist) free(tsklist); if (sellist) free(sellist); return lastchar; /* ** sort order automatically depending on ** most busy resource */ case MSORTAUTO: showorder = MSORTAUTO; firstproc = 0; break; /* ** sort in cpu-activity order */ case MSORTCPU: showorder = MSORTCPU; firstproc = 0; break; /* ** sort in memory-consumption order */ case MSORTMEM: showorder = MSORTMEM; firstproc = 0; break; /* ** sort in disk-activity order */ case MSORTDSK: if ( !(supportflags & IOSTAT) ) { statmsg = "No disk-activity figures " "available; request ignored!"; break; } showorder = MSORTDSK; firstproc = 0; break; /* ** sort in network-activity order */ case MSORTNET: if ( !(supportflags & NETATOP) ) { statmsg = "Kernel module 'netatop' not " "active or no root privs; " "request ignored!"; break; } showorder = MSORTNET; firstproc = 0; break; /* ** sort in gpu-activity order */ case MSORTGPU: if ( !(supportflags & GPUSTAT) ) { statmsg = "No GPU activity figures " "available; request ignored!"; break; } showorder = MSORTGPU; firstproc = 0; break; /* ** general figures per process */ case MPROCGEN: showtype = MPROCGEN; if (showorder != MSORTAUTO) showorder = MSORTCPU; firstproc = 0; break; /* ** memory-specific figures per process */ case MPROCMEM: showtype = MPROCMEM; if (showorder != MSORTAUTO) showorder = MSORTMEM; firstproc = 0; break; /* ** disk-specific figures per process */ case MPROCDSK: if ( !(supportflags & IOSTAT) ) { statmsg = "No disk-activity figures " "available; request ignored!"; break; } showtype = MPROCDSK; if (showorder != MSORTAUTO) showorder = MSORTDSK; firstproc = 0; break; /* ** network-specific figures per process */ case MPROCNET: if ( !(supportflags & NETATOP) ) { statmsg = "Kernel module 'netatop' not " "active or no root privs; " "request ignored!"; break; } showtype = MPROCNET; if (showorder != MSORTAUTO) showorder = MSORTNET; firstproc = 0; break; /* ** GPU-specific figures per process */ case MPROCGPU: if ( !(supportflags & GPUSTAT) ) { statmsg = "No GPU activity figures " "available (atopgpud might " "not be running); " "request ignored!"; break; } showtype = MPROCGPU; if (showorder != MSORTAUTO) showorder = MSORTGPU; firstproc = 0; break; /* ** various info per process */ case MPROCVAR: showtype = MPROCVAR; firstproc = 0; break; /* ** command line per process */ case MPROCARG: showtype = MPROCARG; firstproc = 0; break; /* ** own defined output per process */ case MPROCOWN: if (! ownprocs[0].f) { statmsg = "Own process line is not " "configured in rc-file; " "request ignored"; break; } showtype = MPROCOWN; firstproc = 0; break; /* ** scheduling-values per process */ case MPROCSCH: showtype = MPROCSCH; if (showorder != MSORTAUTO) showorder = MSORTCPU; firstproc = 0; break; /* ** accumulated resource consumption per user */ case MCUMUSER: statmsg = "Consumption per user; use 'a' to " "toggle between all/active processes"; showtype = MCUMUSER; firstproc = 0; break; /* ** accumulated resource consumption per program */ case MCUMPROC: statmsg = "Consumption per program; use 'a' to " "toggle between all/active processes"; showtype = MCUMPROC; firstproc = 0; break; /* ** accumulated resource consumption per container */ case MCUMCONT: statmsg = "Consumption per container; use 'a' to " "toggle between all/active processes"; showtype = MCUMCONT; firstproc = 0; break; /* ** help wanted? */ case MHELP1: case MHELP2: alarm(0); /* stop the clock */ move(1, 0); clrtobot(); /* blank the screen */ refresh(); showhelp(2); move(statline, 0); if (interval && !paused && !rawreadflag) alarm(3); /* force new sample */ firstproc = 0; break; /* ** send signal to process */ case MKILLPROC: if (rawreadflag) { statmsg = "Not possible when viewing " "raw file!"; beep(); break; } alarm(0); /* stop the clock */ killpid = getnumval("Pid of process: ", 0, statline); switch (killpid) { case 0: case -1: break; case 1: statmsg = "Sending signal to pid 1 not " "allowed!"; beep(); break; default: clrtoeol(); killsig = getnumval("Signal [%d]: ", 15, statline); if ( kill(killpid, killsig) == -1) { statmsg = "Not possible to " "send signal to this pid!"; beep(); } } if (!paused) alarm(3); /* set short timer */ firstproc = 0; break; /* ** change interval timeout */ case MINTERVAL: if (rawreadflag) { statmsg = "Not possible when viewing " "raw file!"; beep(); break; } alarm(0); /* stop the clock */ interval = getnumval("New interval in seconds " "(now %d): ", interval, statline); if (interval) { if (!paused) alarm(3); /* set short timer */ } else { statmsg = "No timer set; waiting for " "manual trigger ('t')....."; } firstproc = 0; break; /* ** focus on specific user */ case MSELUSER: alarm(0); /* stop the clock */ echo(); move(statline, 0); clrtoeol(); printw("Username as regular expression " "(enter=all users): "); procsel.username[0] = '\0'; scanw("%255s\n", procsel.username); noecho(); if (procsel.username[0]) /* data entered ? */ { regex_t userregex; int u = 0; if ( regcomp(&userregex, procsel.username, REG_NOSUB)) { statmsg = "Invalid regular " "expression!"; beep(); procsel.username[0] = '\0'; } else { while ( (pwd = getpwent())) { if (regexec(&userregex, pwd->pw_name, 0, NULL, 0)) continue; if (u < MAXUSERSEL-1) { procsel.userid[u] = pwd->pw_uid; u++; } } endpwent(); procsel.userid[u] = USERSTUB; if (u == 0) { /* ** possibly a numerical ** value specified? */ if (numeric( procsel.username)) { procsel.userid[0] = atoi(procsel.username); procsel.userid[1] = USERSTUB; } else { statmsg = "No user-names " "match this " "pattern!"; beep(); } } } } else { procsel.userid[0] = USERSTUB; } if (interval && !paused && !rawreadflag) alarm(3); /* set short timer */ firstproc = 0; break; /* ** focus on specific process-name */ case MSELPROC: alarm(0); /* stop the clock */ echo(); move(statline, 0); clrtoeol(); printw("Process-name as regular " "expression (enter=no regex): "); procsel.prognamesz = 0; procsel.progname[0] = '\0'; scanw("%63s\n", procsel.progname); procsel.prognamesz = strlen(procsel.progname); if (procsel.prognamesz) { if (regcomp(&procsel.progregex, procsel.progname, REG_NOSUB)) { statmsg = "Invalid regular " "expression!"; beep(); procsel.prognamesz = 0; procsel.progname[0] = '\0'; } } noecho(); move(statline, 0); if (interval && !paused && !rawreadflag) alarm(3); /* set short timer */ firstproc = 0; break; /* ** focus on specific container id */ case MSELCONT: alarm(0); /* stop the clock */ echo(); move(statline, 0); clrtoeol(); printw("Containerid 12 postitions " "(enter=all, " "'host'=host processes): "); procsel.container[0] = '\0'; scanw("%15s", procsel.container); procsel.container[12] = '\0'; switch (strlen(procsel.container)) { case 0: break; // enter key pressed case 4: // host? if (strcmp(procsel.container, "host")) { statmsg="Invalid containerid!"; beep(); procsel.container[0] = '\0'; } else { procsel.container[0] = 'H'; procsel.container[1] = '\0'; } break; case 12: // container id (void)strtol(procsel.container, &p, 16); if (*p) { statmsg ="Containerid not hex!"; beep(); procsel.container[0] = '\0'; } break; default: statmsg = "Invalid containerid!"; beep(); procsel.container[0] = '\0'; } noecho(); move(statline, 0); if (interval && !paused && !rawreadflag) alarm(3); /* set short timer */ firstproc = 0; break; /* ** focus on specific PIDs */ case MSELPID: alarm(0); /* stop the clock */ echo(); move(statline, 0); clrtoeol(); printw("Comma-separated PIDs of processes " "(enter=no selection): "); scanw("%79s\n", genline); int id = 0; char *pidp = strtok(genline, ","); while (pidp) { char *ep; if (id >= MAXPID-1) { procsel.pid[id] = 0; // stub statmsg = "Maximum number of" "PIDs reached!"; beep(); break; } procsel.pid[id] = strtol(pidp, &ep, 10); if (*ep) { statmsg = "Non-numerical PID!"; beep(); procsel.pid[0] = 0; // stub break; } id++; pidp = strtok(NULL, ","); } procsel.pid[id] = 0; // stub noecho(); move(statline, 0); if (interval && !paused && !rawreadflag) alarm(3); /* set short timer */ firstproc = 0; break; /* ** focus on specific command line arguments */ case MSELARG: alarm(0); /* stop the clock */ echo(); move(statline, 0); clrtoeol(); printw("Command line string as regular " "expression (enter=no regex): "); procsel.argnamesz = 0; procsel.argname[0] = '\0'; scanw("%63s\n", procsel.argname); procsel.argnamesz = strlen(procsel.argname); if (procsel.argnamesz) { if (regcomp(&procsel.argregex, procsel.argname, REG_NOSUB)) { statmsg = "Invalid regular " "expression!"; beep(); procsel.argnamesz = 0; procsel.argname[0] = '\0'; } } noecho(); move(statline, 0); if (interval && !paused && !rawreadflag) alarm(3); /* set short timer */ firstproc = 0; break; /* ** focus on specific system resource */ case MSELSYS: alarm(0); /* stop the clock */ echo(); move(statline, 0); clrtoeol(); printw("Logical volume name as regular " "expression (enter=no specific name): "); syssel.lvmnamesz = 0; syssel.lvmname[0] = '\0'; scanw("%63s\n", syssel.lvmname); syssel.lvmnamesz = strlen(syssel.lvmname); if (syssel.lvmnamesz) { if (regcomp(&syssel.lvmregex, syssel.lvmname, REG_NOSUB)) { statmsg = "Invalid regular " "expression!"; beep(); syssel.lvmnamesz = 0; syssel.lvmname[0] = '\0'; } } move(statline, 0); clrtoeol(); printw("Disk name as regular " "expression (enter=no specific name): "); syssel.dsknamesz = 0; syssel.dskname[0] = '\0'; scanw("%63s\n", syssel.dskname); syssel.dsknamesz = strlen(syssel.dskname); if (syssel.dsknamesz) { if (regcomp(&syssel.dskregex, syssel.dskname, REG_NOSUB)) { statmsg = "Invalid regular " "expression!"; beep(); syssel.dsknamesz = 0; syssel.dskname[0] = '\0'; } } move(statline, 0); clrtoeol(); printw("Interface name as regular " "expression (enter=no specific name): "); syssel.itfnamesz = 0; syssel.itfname[0] = '\0'; scanw("%63s\n", syssel.itfname); syssel.itfnamesz = strlen(syssel.itfname); if (syssel.itfnamesz) { if (regcomp(&syssel.itfregex, syssel.itfname, REG_NOSUB)) { statmsg = "Invalid regular " "expression!"; beep(); syssel.itfnamesz = 0; syssel.itfname[0] = '\0'; } } noecho(); move(statline, 0); if (interval && !paused && !rawreadflag) alarm(3); /* set short timer */ firstproc = 0; break; /* ** toggle pause-state */ case MPAUSE: if (paused) { paused=0; clrtoeol(); refresh(); if (!rawreadflag) alarm(1); } else { paused=1; clrtoeol(); refresh(); alarm(0); /* stop the clock */ } break; /* ** toggle between modified processes and ** all processes */ case MALLPROC: if (deviatonly) { deviatonly=0; statmsg = "All processes/threads will be " "shown/accumulated..."; } else { deviatonly=1; statmsg = "Only active processes/threads " "will be shown/accumulated..."; } tlastorder = 0; firstproc = 0; break; /* ** toggle average or total values */ case MAVGVAL: if (avgval) avgval=0; else avgval=1; break; /* ** system-statistics lines: ** toggle fixed or variable */ case MSYSFIXED: if (fixedhead) { fixedhead=0; statmsg = "Only active system-resources" " will be shown ......"; } else { fixedhead=1; statmsg = "Also inactive " "system-resources will be shown....."; } firstproc = 0; break; /* ** system-statistics lines: ** toggle fixed or variable */ case MSYSNOSORT: if (sysnosort) { sysnosort=0; statmsg = "System resources will be " "sorted on utilization..."; } else { sysnosort=1; statmsg = "System resources will not " "be sorted on utilization..."; } firstproc = 0; break; /* ** per-thread view wanted with sorting on ** process level or thread level */ case MTHREAD: if (threadview) { threadview = 0; statmsg = "Thread view disabled"; firstproc = 0; } else { threadview = 1; statmsg = "Thread view enabled"; firstproc = 0; } break; /* ** per-process PSS calculation wanted */ case MCALCPSS: if (calcpss) { calcpss = 0; statmsg = "PSIZE gathering disabled"; } else { calcpss = 1; statmsg = "PSIZE gathering enabled"; } break; /* ** suppression of exited processes in output */ case MSUPEXITS: if (suppressexit) { suppressexit = 0; statmsg = "Exited processes will " "be shown/accumulated"; firstproc = 0; } else { suppressexit = 1; statmsg = "Exited processes will " "not be shown/accumulated"; firstproc = 0; } break; /* ** screen lines: ** toggle for colors */ case MCOLORS: if (usecolors) { usecolors=0; statmsg = "No colors will be used..."; } else { if (screen && has_colors()) { usecolors=1; statmsg = "Colors will be used..."; } else { statmsg="No colors supported!"; } } firstproc = 0; break; /* ** system-statistics lines: ** toggle no or all active disk */ case MSYSLIMIT: alarm(0); /* stop the clock */ maxcpulines = getnumval("Maximum lines for per-cpu " "statistics (now %d): ", maxcpulines, statline); maxgpulines = getnumval("Maximum lines for per-gpu " "statistics (now %d): ", maxgpulines, statline); if (sstat->dsk.nlvm > 0) { maxlvmlines = getnumval("Maximum lines for LVM " "statistics (now %d): ", maxlvmlines, statline); } if (sstat->dsk.nmdd > 0) { maxmddlines = getnumval("Maximum lines for MD " "device statistics (now %d): ", maxmddlines, statline); } maxdsklines = getnumval("Maximum lines for disk " "statistics (now %d): ", maxdsklines, statline); maxintlines = getnumval("Maximum lines for interface " "statistics (now %d): ", maxintlines, statline); maxifblines = getnumval("Maximum lines for infiniband " "port statistics (now %d): ", maxifblines, statline); maxnfslines = getnumval("Maximum lines for NFS mount " "statistics (now %d): ", maxnfslines, statline); maxcontlines = getnumval("Maximum lines for container " "statistics (now %d): ", maxcontlines, statline); if (interval && !paused && !rawreadflag) alarm(3); /* set short timer */ firstproc = 0; break; /* ** reset statistics */ case MRESET: getalarm(0); /* restart the clock */ paused = 0; if (tpcumlist) free(tpcumlist); if (pcumlist) free(pcumlist); if (tucumlist) free(tucumlist); if (ucumlist) free(ucumlist); if (tccumlist) free(tccumlist); if (ccumlist) free(ccumlist); if (tsklist) free(tsklist); if (sellist) free(sellist); return lastchar; /* ** show version info */ case MVERSION: statmsg = getstrvers(); break; /* ** handle redraw request */ case MREDRAW: wclear(stdscr); break; /* ** handle arrow right for command line */ case KEY_RIGHT: startoffset++; break; /* ** handle arrow left for command line */ case KEY_LEFT: if (startoffset > 0) startoffset--; break; /* ** handle arrow down to go one line down */ case KEY_DOWN: if (firstproc < alistsz-1) firstproc += 1; break; /* ** handle arrow up to go one line up */ case KEY_UP: if (firstproc > 0) firstproc -= 1; break; /* ** handle forward */ case KEY_NPAGE: case MLISTFW: if (alistsz-firstproc > plistsz) firstproc += plistsz; break; /* ** handle backward */ case KEY_PPAGE: case MLISTBW: if (firstproc >= plistsz) firstproc -= plistsz; else firstproc = 0; break; /* ** handle screen resize */ case KEY_RESIZE: snprintf(statbuf, sizeof statbuf, "Window resized to %dx%d...", COLS, LINES); statmsg = statbuf; timeout(0); (void) getch(); timeout(-1); break; /* ** unknown key-stroke */ default: beep(); } } else /* no screen */ { if (tpcumlist) free(tpcumlist); if (pcumlist) free(pcumlist); if (tucumlist) free(tucumlist); if (ucumlist) free(ucumlist); if (tccumlist) free(tccumlist); if (ccumlist) free(ccumlist); if (tsklist) free(tsklist); if (sellist) free(sellist); return '\0'; } } } /* ** accumulate all processes per user in new list */ static int cumusers(struct tstat **curprocs, struct tstat *curusers, int numprocs) { register int i, numusers; /* ** sort list of active processes in order of uid (increasing) */ qsort(curprocs, numprocs, sizeof(struct tstat *), compusr); /* ** accumulate all processes per user in the new list */ for (numusers=i=0; i < numprocs; i++, curprocs++) { if (procsuppress(*curprocs, &procsel)) continue; if ((*curprocs)->gen.state == 'E' && suppressexit) continue; if ( curusers->gen.ruid != (*curprocs)->gen.ruid ) { if (curusers->gen.pid) { numusers++; curusers++; } curusers->gen.ruid = (*curprocs)->gen.ruid; } accumulate(*curprocs, curusers); } if (curusers->gen.pid) numusers++; return numusers; } /* ** accumulate all processes with the same name (i.e. same program) ** into a new list */ static int cumprogs(struct tstat **curprocs, struct tstat *curprogs, int numprocs) { register int i, numprogs; /* ** sort list of active processes in order of process-name */ qsort(curprocs, numprocs, sizeof(struct tstat *), compnam); /* ** accumulate all processes with same name in the new list */ for (numprogs=i=0; i < numprocs; i++, curprocs++) { if (procsuppress(*curprocs, &procsel)) continue; if ((*curprocs)->gen.state == 'E' && suppressexit) continue; if ( strcmp(curprogs->gen.name, (*curprocs)->gen.name) != 0) { if (curprogs->gen.pid) { numprogs++; curprogs++; } strcpy(curprogs->gen.name, (*curprocs)->gen.name); } accumulate(*curprocs, curprogs); } if (curprogs->gen.pid) numprogs++; return numprogs; } /* ** accumulate all processes per container in new list */ static int cumconts(struct tstat **curprocs, struct tstat *curconts, int numprocs) { register int i, numconts; /* ** sort list of active processes in order of container (increasing) */ qsort(curprocs, numprocs, sizeof(struct tstat *), compcon); /* ** accumulate all processes per container in the new list */ for (numconts=i=0; i < numprocs; i++, curprocs++) { if (procsuppress(*curprocs, &procsel)) continue; if ((*curprocs)->gen.state == 'E' && suppressexit) continue; if ( strcmp(curconts->gen.container, (*curprocs)->gen.container) != 0) { if (curconts->gen.pid) { numconts++; curconts++; } strcpy(curconts->gen.container, (*curprocs)->gen.container); } accumulate(*curprocs, curconts); } if (curconts->gen.pid) numconts++; return numconts; } /* ** accumulate relevant counters from individual task to ** combined task */ static void accumulate(struct tstat *curproc, struct tstat *curstat) { count_t nett_wsz; curstat->gen.pid++; /* misuse as counter */ curstat->gen.isproc = 1; curstat->gen.nthr += curproc->gen.nthr; curstat->cpu.utime += curproc->cpu.utime; curstat->cpu.stime += curproc->cpu.stime; if (curproc->dsk.wsz > curproc->dsk.cwsz) nett_wsz = curproc->dsk.wsz -curproc->dsk.cwsz; else nett_wsz = 0; curstat->dsk.rio += curproc->dsk.rsz; curstat->dsk.wio += nett_wsz; curstat->dsk.rsz = curstat->dsk.rio; curstat->dsk.wsz = curstat->dsk.wio; curstat->net.tcpsnd += curproc->net.tcpsnd; curstat->net.tcprcv += curproc->net.tcprcv; curstat->net.udpsnd += curproc->net.udpsnd; curstat->net.udprcv += curproc->net.udprcv; curstat->net.tcpssz += curproc->net.tcpssz; curstat->net.tcprsz += curproc->net.tcprsz; curstat->net.udpssz += curproc->net.udpssz; curstat->net.udprsz += curproc->net.udprsz; if (curproc->gen.state != 'E') { if (curstat->mem.pmem != -1) { if (curproc->mem.pmem != -1) // no errors? curstat->mem.pmem += curproc->mem.pmem; else curstat->mem.pmem = -1; } curstat->mem.vmem += curproc->mem.vmem; curstat->mem.rmem += curproc->mem.rmem; curstat->mem.vlibs += curproc->mem.vlibs; curstat->mem.vdata += curproc->mem.vdata; curstat->mem.vstack += curproc->mem.vstack; curstat->mem.vswap += curproc->mem.vswap; curstat->mem.rgrow += curproc->mem.rgrow; curstat->mem.vgrow += curproc->mem.vgrow; if (curproc->gpu.state) // GPU is use? { int i; curstat->gpu.state = 'A'; if (curproc->gpu.gpubusy == -1) curstat->gpu.gpubusy = -1; else curstat->gpu.gpubusy += curproc->gpu.gpubusy; if (curproc->gpu.membusy == -1) curstat->gpu.membusy = -1; else curstat->gpu.membusy += curproc->gpu.membusy; curstat->gpu.memnow += curproc->gpu.memnow; curstat->gpu.gpulist |= curproc->gpu.gpulist; curstat->gpu.nrgpus = 0; for (i=0; i < MAXGPU; i++) { if (curstat->gpu.gpulist & 1<gpu.nrgpus++; } } } } /* ** function that checks if the current process is selected or suppressed; ** returns 1 (suppress) or 0 (do not suppress) */ static int procsuppress(struct tstat *curstat, struct pselection *sel) { /* ** check if only processes of a particular user ** should be shown */ if (sel->userid[0] != USERSTUB) { int u = 0; while (sel->userid[u] != USERSTUB) { if (sel->userid[u] == curstat->gen.ruid) break; u++; } if (sel->userid[u] != curstat->gen.ruid) return 1; } /* ** check if only processes with particular PIDs ** should be shown */ if (sel->pid[0]) { int i = 0; while (sel->pid[i]) { if (sel->pid[i] == curstat->gen.pid) break; i++; } if (sel->pid[i] != curstat->gen.pid) return 1; } /* ** check if only processes with a particular name ** should be shown */ if (sel->prognamesz && regexec(&(sel->progregex), curstat->gen.name, 0, NULL, 0)) return 1; /* ** check if only processes with a particular command line string ** should be shown */ if (sel->argnamesz) { if (curstat->gen.cmdline[0]) { if (regexec(&(sel->argregex), curstat->gen.cmdline, 0, NULL, 0)) return 1; } else { if (regexec(&(sel->argregex), curstat->gen.name, 0, NULL, 0)) return 1; } } /* ** check if only processes related to a particular container ** should be shown (container 'H' stands for native host processes) */ if (sel->container[0]) { if (sel->container[0] == 'H') // only host processes { if (curstat->gen.container[0]) return 1; } else { if (memcmp(sel->container, curstat->gen.container, 12)) return 1; } } return 0; } static void limitedlines(void) { if (maxcpulines == 999) // default? maxcpulines = 0; if (maxgpulines == 999) // default? maxgpulines = 2; if (maxdsklines == 999) // default? maxdsklines = 3; if (maxmddlines == 999) // default? maxmddlines = 3; if (maxlvmlines == 999) // default? maxlvmlines = 4; if (maxintlines == 999) // default? maxintlines = 2; if (maxifblines == 999) // default? maxifblines = 2; if (maxnfslines == 999) // default? maxnfslines = 2; if (maxcontlines == 999) // default? maxcontlines = 1; } /* ** get a numerical value from the user and verify */ static long getnumval(char *ask, long valuenow, int statline) { char numval[16]; long retval; echo(); move(statline, 0); clrtoeol(); printw(ask, valuenow); numval[0] = 0; scanw("%15s", numval); move(statline, 0); noecho(); if (numval[0]) /* data entered ? */ { if ( numeric(numval) ) { retval = atol(numval); } else { beep(); clrtoeol(); printw("Value not numeric (current value kept)!"); refresh(); sleep(2); retval = valuenow; } } else { retval = valuenow; } return retval; } /* ** generic print-function which checks if printf should be used ** (to file or pipe) or curses (to screen) */ void printg(const char *format, ...) { va_list args; va_start(args, format); if (screen) vwprintw(stdscr, (char *) format, args); else vprintf(format, args); va_end (args); } /* ** initialize generic sample output functions */ static void generic_init(void) { int i; /* ** check if default sort order and/or showtype are overruled ** by command-line flags */ for (i=0; flaglist[i]; i++) { switch (flaglist[i]) { case MSORTAUTO: showorder = MSORTAUTO; break; case MSORTCPU: showorder = MSORTCPU; break; case MSORTGPU: showorder = MSORTGPU; break; case MSORTMEM: showorder = MSORTMEM; break; case MSORTDSK: showorder = MSORTDSK; break; case MSORTNET: showorder = MSORTNET; break; case MPROCGEN: showtype = MPROCGEN; showorder = MSORTCPU; break; case MPROCGPU: showtype = MPROCGPU; showorder = MSORTGPU; break; case MPROCMEM: showtype = MPROCMEM; showorder = MSORTMEM; break; case MPROCSCH: showtype = MPROCSCH; showorder = MSORTCPU; break; case MPROCDSK: if ( !(supportflags & IOSTAT) ) { fprintf(stderr, "No disk-activity figures " "available; request ignored\n"); sleep(3); break; } showtype = MPROCDSK; showorder = MSORTDSK; break; case MPROCNET: if ( !(supportflags & NETATOP) ) { fprintf(stderr, "Kernel module 'netatop' not " "active; request ignored!"); sleep(3); break; } showtype = MPROCNET; showorder = MSORTNET; break; case MPROCVAR: showtype = MPROCVAR; break; case MPROCARG: showtype = MPROCARG; break; case MPROCOWN: showtype = MPROCOWN; break; case MAVGVAL: if (avgval) avgval=0; else avgval=1; break; case MCUMUSER: showtype = MCUMUSER; break; case MCUMPROC: showtype = MCUMPROC; break; case MCUMCONT: showtype = MCUMCONT; break; case MSYSFIXED: if (fixedhead) fixedhead=0; else fixedhead=1; break; case MSYSNOSORT: if (sysnosort) sysnosort=0; else sysnosort=1; break; case MTHREAD: if (threadview) threadview = 0; else threadview = 1; break; case MCALCPSS: if (calcpss) calcpss = 0; else calcpss = 1; break; case MSUPEXITS: if (suppressexit) suppressexit = 0; else suppressexit = 1; break; case MCOLORS: if (usecolors) usecolors=0; else usecolors=1; break; case MSYSLIMIT: limitedlines(); break; default: prusage("atop"); } } /* ** set stdout output on line-basis */ setvbuf(stdout, (char *)0, _IOLBF, BUFSIZ); /* ** check if STDOUT is related to a tty or ** something else (file, pipe) */ if ( isatty(1) ) screen = 1; else screen = 0; /* ** install catch-routine to finish in a controlled way ** and activate cbreak-mode */ if (screen) { /* ** initialize screen-handling via curses */ initscr(); cbreak(); noecho(); keypad(stdscr, TRUE); if (COLS < 30) { endwin(); // finish curses interface fprintf(stderr, "Not enough columns available\n" "(need at least %d columns)\n", 30); fprintf(stderr, "Please resize window....\n"); cleanstop(1); } if (has_colors()) { 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); } else { usecolors = 0; } } signal(SIGINT, cleanstop); signal(SIGTERM, cleanstop); } /* ** show help information in interactive mode */ static struct helptext { char *helpline; char helparg; } helptext[] = { {"Figures shown for active processes:\n", ' '}, {"\t'%c' - generic info (default)\n", MPROCGEN}, {"\t'%c' - memory details\n", MPROCMEM}, {"\t'%c' - disk details\n", MPROCDSK}, {"\t'%c' - network details\n", MPROCNET}, {"\t'%c' - GPU details\n", MPROCGPU}, {"\t'%c' - scheduling and thread-group info\n", MPROCSCH}, {"\t'%c' - various info (ppid, user/group, date/time, status, " "exitcode)\n", MPROCVAR}, {"\t'%c' - full command line per process\n", MPROCARG}, {"\t'%c' - use own output line definition\n", MPROCOWN}, {"\n", ' '}, {"Sort list of processes in order of:\n", ' '}, {"\t'%c' - cpu activity\n", MSORTCPU}, {"\t'%c' - memory consumption\n", MSORTMEM}, {"\t'%c' - disk activity\n", MSORTDSK}, {"\t'%c' - network activity\n", MSORTNET}, {"\t'%c' - GPU activity\n", MSORTGPU}, {"\t'%c' - most active system resource (auto mode)\n", MSORTAUTO}, {"\n", ' '}, {"Accumulated figures:\n", ' '}, {"\t'%c' - total resource consumption per user\n", MCUMUSER}, {"\t'%c' - total resource consumption per program (i.e. same " "process name)\n", MCUMPROC}, {"\t'%c' - total resource consumption per container\n",MCUMCONT}, {"\n", ' '}, {"Process selections (keys shown in header line):\n", ' '}, {"\t'%c' - focus on specific user name " "(regular expression)\n", MSELUSER}, {"\t'%c' - focus on specific program name " "(regular expression)\n", MSELPROC}, {"\t'%c' - focus on specific contained id (CID)\n", MSELCONT}, {"\t'%c' - focus on specific command line string " "(regular expression)\n", MSELARG}, {"\t'%c' - focus on specific process id (PID)\n", MSELPID}, {"\n", ' '}, {"System resource selections (keys shown in header line):\n",' '}, {"\t'%c' - focus on specific system resources " "(regular expression)\n", MSELSYS}, {"\n", ' '}, {"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", ' '}, {"\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", ' '}, {"\n", ' '}, {"Presentation (keys shown in header line):\n", ' '}, {"\t'%c' - show individual threads (toggle)\n", MTHREAD}, {"\t'%c' - show all processes (default: active processes) (toggle)\n", MALLPROC}, {"\t'%c' - show fixed number of header lines (toggle)\n", MSYSFIXED}, {"\t'%c' - suppress sorting system resources (toggle)\n", MSYSNOSORT}, {"\t'%c' - suppress exited processes in output (toggle)\n", MSUPEXITS}, {"\t'%c' - no colors to indicate high occupation (toggle)\n", MCOLORS}, {"\t'%c' - show average-per-second i.s.o. total values (toggle)\n", MAVGVAL}, {"\t'%c' - calculate proportional set size (PSIZE) (toggle)\n", MCALCPSS}, {"\n", ' '}, {"Raw file viewing:\n", ' '}, {"\t'%c' - show next sample in raw file\n", MSAMPNEXT}, {"\t'%c' - show previous sample in raw file\n", MSAMPPREV}, {"\t'%c' - branch to certain time in raw file\n", MSAMPBRANCH}, {"\t'%c' - rewind to begin of raw file\n", MRESET}, {"\n", ' '}, {"Miscellaneous commands:\n", ' '}, {"\t'%c' - change interval timer (0 = only manual trigger)\n", MINTERVAL}, {"\t'%c' - manual trigger to force next sample\n", MSAMPNEXT}, {"\t'%c' - reset counters to boot time values\n", MRESET}, {"\t'%c' - pause button to freeze current sample (toggle)\n", MPAUSE}, {"\n", ' '}, {"\t'%c' - limited lines for per-cpu, disk and interface resources\n", MSYSLIMIT}, {"\t'%c' - kill a process (i.e. send a signal)\n", MKILLPROC}, {"\n", ' '}, {"\t'%c' - version information\n", MVERSION}, {"\t'%c' - help information\n", MHELP1}, {"\t'%c' - help information\n", MHELP2}, {"\t'%c' - quit this program\n", MQUIT}, }; static int helplines = sizeof(helptext)/sizeof(struct helptext); static void showhelp(int helpline) { int winlines = LINES-helpline, shown, tobeshown=1, i; WINDOW *helpwin; /* ** create a new window for the help-info in which scrolling is ** allowed */ helpwin = newwin(winlines, COLS, helpline, 0); scrollok(helpwin, 1); /* ** show help-lines */ for (i=0, shown=0; i < helplines; i++, shown++) { wprintw(helpwin, helptext[i].helpline, helptext[i].helparg); /* ** when the window is full, start paging interactively */ if (i >= winlines-2 && shown >= tobeshown) { wmove (helpwin, winlines-1, 0); wclrtoeol(helpwin); wprintw (helpwin, "Press 'q' to leave help, " "space for next page or " "other key for next line... "); switch (wgetch(helpwin)) { case 'q': delwin(helpwin); return; case ' ': shown = 0; tobeshown = winlines-1; break; default: shown = 0; tobeshown = 1; } 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); } /* ** function to be called to print error-messages */ void generic_error(const char *format, ...) { va_list args; va_start(args, format); vfprintf(stderr, format, args); va_end (args); } /* ** function to be called when the program stops */ void generic_end(void) { endwin(); } /* ** function to be called when usage-info is required */ void generic_usage(void) { printf("\t -%c show fixed number of lines with system statistics\n", MSYSFIXED); printf("\t -%c suppress sorting of system resources\n", MSYSNOSORT); printf("\t -%c suppress exited processes in output\n", MSUPEXITS); printf("\t -%c show limited number of lines for certain resources\n", MSYSLIMIT); printf("\t -%c show individual threads\n", MTHREAD); printf("\t -%c show average-per-second i.s.o. total values\n\n", MAVGVAL); printf("\t -%c no colors in case of high occupation\n", MCOLORS); printf("\t -%c show general process-info (default)\n", MPROCGEN); printf("\t -%c show memory-related process-info\n", MPROCMEM); printf("\t -%c show disk-related process-info\n", MPROCDSK); printf("\t -%c show network-related process-info\n", MPROCNET); printf("\t -%c show scheduling-related process-info\n", MPROCSCH); printf("\t -%c show various process-info (ppid, user/group, " "date/time)\n", MPROCVAR); printf("\t -%c show command line per process\n", MPROCARG); printf("\t -%c show own defined process-info\n", MPROCOWN); printf("\t -%c show cumulated process-info per user\n", MCUMUSER); printf("\t -%c show cumulated process-info per program " "(i.e. same name)\n", MCUMPROC); printf("\t -%c show cumulated process-info per container\n\n", MCUMCONT); printf("\t -%c sort processes in order of cpu consumption " "(default)\n", MSORTCPU); printf("\t -%c sort processes in order of memory consumption\n", MSORTMEM); printf("\t -%c sort processes in order of disk activity\n", MSORTDSK); printf("\t -%c sort processes in order of network activity\n", MSORTNET); printf("\t -%c sort processes in order of GPU activity\n", MSORTGPU); printf("\t -%c sort processes in order of most active resource " "(auto mode)\n", MSORTAUTO); } /* ** functions to handle a particular tag in the /etc/atoprc and .atoprc file */ void do_username(char *name, char *val) { struct passwd *pwd; strncpy(procsel.username, val, sizeof procsel.username -1); procsel.username[sizeof procsel.username -1] = 0; if (procsel.username[0]) { regex_t userregex; int u = 0; if (regcomp(&userregex, procsel.username, REG_NOSUB)) { fprintf(stderr, "atoprc - %s: invalid regular expression %s\n", name, val); exit(1); } while ( (pwd = getpwent())) { if (regexec(&userregex, pwd->pw_name, 0, NULL, 0)) continue; if (u < MAXUSERSEL-1) { procsel.userid[u] = pwd->pw_uid; u++; } } endpwent(); procsel.userid[u] = USERSTUB; if (u == 0) { /* ** possibly a numerical value has been specified */ if (numeric(procsel.username)) { procsel.userid[0] = atoi(procsel.username); procsel.userid[1] = USERSTUB; } else { fprintf(stderr, "atoprc - %s: user-names matching %s " "do not exist\n", name, val); exit(1); } } } else { procsel.userid[0] = USERSTUB; } } void do_procname(char *name, char *val) { strncpy(procsel.progname, val, sizeof procsel.progname -1); procsel.prognamesz = strlen(procsel.progname); if (procsel.prognamesz) { if (regcomp(&procsel.progregex, procsel.progname, REG_NOSUB)) { fprintf(stderr, "atoprc - %s: invalid regular expression %s\n", name, val); exit(1); } } } extern int get_posval(char *name, char *val); void do_maxcpu(char *name, char *val) { maxcpulines = get_posval(name, val); } void do_maxgpu(char *name, char *val) { maxgpulines = get_posval(name, val); } void do_maxdisk(char *name, char *val) { maxdsklines = get_posval(name, val); } void do_maxmdd(char *name, char *val) { maxmddlines = get_posval(name, val); } void do_maxlvm(char *name, char *val) { maxlvmlines = get_posval(name, val); } void do_maxintf(char *name, char *val) { maxintlines = get_posval(name, val); } void do_maxifb(char *name, char *val) { maxifblines = get_posval(name, val); } void do_maxnfsm(char *name, char *val) { maxnfslines = get_posval(name, val); } void do_maxcont(char *name, char *val) { maxcontlines = get_posval(name, val); } struct colmap { char *colname; short colval; } colormap[] = { { "red", COLOR_RED, }, { "green", COLOR_GREEN, }, { "yellow", COLOR_YELLOW, }, { "blue", COLOR_BLUE, }, { "magenta", COLOR_MAGENTA, }, { "cyan", COLOR_CYAN, }, { "black", COLOR_BLACK, }, { "white", COLOR_WHITE, }, }; static short modify_color(char *colorname) { int i; for (i=0; i < sizeof colormap/sizeof colormap[0]; i++) { if ( strcmp(colorname, colormap[i].colname) == 0) return colormap[i].colval; } // required color not found fprintf(stderr, "atoprc - invalid color used: %s\n", colorname); fprintf(stderr, "supported colors:"); for (i=0; i < sizeof colormap/sizeof colormap[0]; i++) fprintf(stderr, " %s", colormap[i].colname); fprintf(stderr, "\n"); exit(1); } void do_colinfo(char *name, char *val) { colorinfo = modify_color(val); } void do_colalmost(char *name, char *val) { coloralmost = modify_color(val); } void do_colcrit(char *name, char *val) { colorcrit = modify_color(val); } void do_colthread(char *name, char *val) { colorthread = modify_color(val); } void do_flags(char *name, char *val) { int i; for (i=0; val[i]; i++) { switch (val[i]) { case '-': break; case MSORTCPU: showorder = MSORTCPU; break; case MSORTGPU: showorder = MSORTGPU; break; case MSORTMEM: showorder = MSORTMEM; break; case MSORTDSK: showorder = MSORTDSK; break; case MSORTNET: showorder = MSORTNET; break; case MSORTAUTO: showorder = MSORTAUTO; break; case MPROCGEN: showtype = MPROCGEN; showorder = MSORTCPU; break; case MPROCGPU: showtype = MPROCGPU; showorder = MSORTGPU; break; case MPROCMEM: showtype = MPROCMEM; showorder = MSORTMEM; break; case MPROCDSK: showtype = MPROCDSK; showorder = MSORTDSK; break; case MPROCNET: showtype = MPROCNET; showorder = MSORTNET; break; case MPROCVAR: showtype = MPROCVAR; break; case MPROCSCH: showtype = MPROCSCH; showorder = MSORTCPU; break; case MPROCARG: showtype = MPROCARG; break; case MPROCOWN: showtype = MPROCOWN; break; case MCUMUSER: showtype = MCUMUSER; break; case MCUMPROC: showtype = MCUMPROC; break; case MCUMCONT: showtype = MCUMCONT; break; case MALLPROC: deviatonly = 0; break; case MAVGVAL: avgval=1; break; case MSYSFIXED: fixedhead = 1; break; case MSYSNOSORT: sysnosort = 1; break; case MTHREAD: threadview = 1; break; case MCOLORS: usecolors = 0; break; case MCALCPSS: calcpss = 1; break; case MSUPEXITS: suppressexit = 1; break; } } } atop-2.4.0/showgeneric.h0000664000203100020310000000721313416466037014465 0ustar gerlofgerlof/* ** 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. ** ** Include-file describing prototypes and structures for visualization ** of counters. ** ================================================================ ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Date: July 2002 ** ** 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. */ #define USERSTUB 9999999 #define MAXUSERSEL 64 #define MAXPID 32 struct syscap { int nrcpu; count_t availcpu; count_t availmem; count_t availdsk; count_t availnet; int nrgpu; count_t availgpumem; // GPU memory in Kb! }; struct pselection { char username[256]; uid_t userid[MAXUSERSEL]; pid_t pid[MAXPID]; char progname[64]; int prognamesz; regex_t progregex; char argname[64]; int argnamesz; regex_t argregex; char container[16]; }; struct sselection { char lvmname[64]; // logical volume selection int lvmnamesz; regex_t lvmregex; char dskname[64]; // disk selection int dsknamesz; regex_t dskregex; char itfname[64]; // network interface selection int itfnamesz; regex_t itfregex; }; /* ** color names */ #define COLORINFO 2 #define COLORALMOST 3 #define COLORCRIT 4 #define COLORTHR 5 /* ** list with keystrokes/flags */ #define MPROCGEN 'g' #define MPROCMEM 'm' #define MPROCDSK 'd' #define MPROCNET 'n' #define MPROCGPU 'e' #define MPROCSCH 's' #define MPROCVAR 'v' #define MPROCARG 'c' #define MPROCOWN 'o' #define MCUMUSER 'u' #define MCUMPROC 'p' #define MCUMCONT 'j' #define MSORTCPU 'C' #define MSORTDSK 'D' #define MSORTMEM 'M' #define MSORTNET 'N' #define MSORTGPU 'E' #define MSORTAUTO 'A' #define MTHREAD 'y' #define MCALCPSS 'R' #define MSUPEXITS 'G' #define MCOLORS 'x' #define MSYSFIXED 'f' #define MSYSNOSORT 'F' #define MSYSLIMIT 'l' #define MSELUSER 'U' #define MSELPROC 'P' #define MSELCONT 'J' #define MSELPID 'I' #define MSELARG '/' #define MSELSYS 'S' #define MALLPROC 'a' #define MKILLPROC 'k' #define MLISTFW 0x06 #define MLISTBW 0x02 #define MREDRAW 0x0c #define MINTERVAL 'i' #define MPAUSE 'z' #define MQUIT 'q' #define MRESET 'r' #define MSAMPNEXT 't' #define MSAMPPREV 'T' #define MSAMPBRANCH 'b' #define MVERSION 'V' #define MAVGVAL '1' #define MHELP1 '?' #define MHELP2 'h' /* ** general function prototypes */ void totalcap (struct syscap *, struct sstat *, struct tstat **, int); void pricumproc (struct sstat *, struct devtstat *, int, unsigned int, int, int); void showgenproc(struct tstat *, double, int, int); void showmemproc(struct tstat *, double, int, int); void showdskproc(struct tstat *, double, int, int); void shownetproc(struct tstat *, double, int, int); void showvarproc(struct tstat *, double, int, int); void showschproc(struct tstat *, double, int, int); void showtotproc(struct tstat *, double, int, int); void showcmdproc(struct tstat *, double, int, int); void printg (const char *, ...); int prisyst(struct sstat *, int, int, int, int, struct sselection *, char *, int, int, int, int, int, int, int, int, int); int priproc(struct tstat **, int, int, int, int, int, char, char, struct syscap *, int, int); void priphead(int, int, char *, char *, char); atop-2.4.0/showlinux.c0000664000203100020310000023203313416466037014203 0ustar gerlofgerlof/* ** 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 the Linux-specific functions to calculate ** figures to be visualized. ** ========================================================================== ** Author: Gerlof Langeveld ** Original version. ** E-mail: gerlof.langeveld@atoptool.nl ** Date: July 2002 ** ** Author: JC van Winkel - AT Computing, Nijmegen, Holland ** Complete redesign. ** Date: November 2009 ** -------------------------------------------------------------------------- ** Copyright (C) 2009-2010 JC van Winkel ** ** 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 ** -------------------------------------------------------------------------- ** ** $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 ** */ static const char rcsid[] = "$Id: showlinux.c,v 1.70 2010/10/23 14:04:12 gerlof Exp $"; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "atop.h" #include "photoproc.h" #include "photosyst.h" #include "showgeneric.h" #include "showlinux.h" static void make_proc_dynamicgen(void); /* ** critical percentages for occupation-percentage; ** these defaults can be overruled via the config-file */ int cpubadness = 90; /* percentage */ int gpubadness = 100; /* percentage */ int membadness = 90; /* percentage */ int swpbadness = 80; /* percentage */ int dskbadness = 70; /* percentage */ int netbadness = 90; /* percentage */ int pagbadness = 10; /* number per second */ int almostcrit = 80; /* percentage */ /* * tables with all sys_printdefs */ sys_printdef *prcsyspdefs[] = { &syspdef_PRCSYS, &syspdef_PRCUSER, &syspdef_PRCNPROC, &syspdef_PRCNRUNNING, &syspdef_PRCNSLEEPING, &syspdef_PRCNDSLEEPING, &syspdef_PRCNZOMBIE, &syspdef_PRCCLONES, &syspdef_PRCNNEXIT, &syspdef_BLANKBOX, 0 }; sys_printdef *cpusyspdefs[] = { &syspdef_CPUSYS, &syspdef_CPUUSER, &syspdef_CPUIRQ, &syspdef_CPUIDLE, &syspdef_CPUWAIT, &syspdef_BLANKBOX, &syspdef_CPUIPC, &syspdef_CPUCYCLE, &syspdef_CPUFREQ, &syspdef_CPUSCALE, &syspdef_CPUSTEAL, &syspdef_CPUGUEST, &syspdef_BLANKBOX, 0 }; sys_printdef *cpisyspdefs[] = { &syspdef_CPUISYS, &syspdef_CPUIUSER, &syspdef_CPUIIRQ, &syspdef_CPUIIDLE, &syspdef_CPUIWAIT, &syspdef_BLANKBOX, &syspdef_CPUIIPC, &syspdef_CPUICYCLE, &syspdef_CPUIFREQ, &syspdef_CPUISCALE, &syspdef_CPUISTEAL, &syspdef_CPUIGUEST, &syspdef_BLANKBOX, 0 }; sys_printdef *cplsyspdefs[] = { &syspdef_CPLAVG1, &syspdef_CPLAVG5, &syspdef_CPLAVG15, &syspdef_CPLCSW, &syspdef_CPLNUMCPU, &syspdef_CPLINTR, &syspdef_BLANKBOX, 0 }; sys_printdef *gpusyspdefs[] = { &syspdef_GPUBUS, &syspdef_GPUGPUPERC, &syspdef_GPUMEMPERC, &syspdef_GPUMEMOCC, &syspdef_GPUMEMTOT, &syspdef_GPUMEMUSE, &syspdef_GPUMEMAVG, &syspdef_GPUTYPE, &syspdef_GPUNRPROC, &syspdef_BLANKBOX, 0 }; sys_printdef *memsyspdefs[] = { &syspdef_MEMTOT, &syspdef_MEMFREE, &syspdef_MEMCACHE, &syspdef_MEMDIRTY, &syspdef_MEMBUFFER, &syspdef_MEMSLAB, &syspdef_RECSLAB, &syspdef_BLANKBOX, &syspdef_SHMEM, &syspdef_SHMRSS, &syspdef_SHMSWP, &syspdef_BLANKBOX, &syspdef_VMWBAL, &syspdef_BLANKBOX, &syspdef_HUPTOT, &syspdef_HUPUSE, 0 }; sys_printdef *swpsyspdefs[] = { &syspdef_SWPTOT, &syspdef_SWPFREE, &syspdef_SWPCOMMITTED, &syspdef_SWPCOMMITLIM, &syspdef_BLANKBOX, 0 }; sys_printdef *pagsyspdefs[] = { &syspdef_PAGSCAN, &syspdef_PAGSTEAL, &syspdef_PAGSTALL, &syspdef_PAGSWIN, &syspdef_PAGSWOUT, &syspdef_BLANKBOX, 0 }; sys_printdef *psisyspdefs[] = { &syspdef_PSICPUS, &syspdef_PSIMEMS, &syspdef_PSIMEMF, &syspdef_PSIIOS, &syspdef_PSIIOF, &syspdef_BLANKBOX, 0 }; sys_printdef *contsyspdefs[] = { &syspdef_CONTNAME, &syspdef_CONTNPROC, &syspdef_CONTCPU, &syspdef_CONTMEM, &syspdef_BLANKBOX, 0 }; sys_printdef *dsksyspdefs[] = { &syspdef_DSKNAME, &syspdef_DSKBUSY, &syspdef_DSKNREAD, &syspdef_DSKNWRITE, &syspdef_DSKMBPERSECWR, &syspdef_DSKMBPERSECRD, &syspdef_DSKKBPERWR, &syspdef_DSKKBPERRD, &syspdef_DSKAVQUEUE, &syspdef_DSKAVIO, &syspdef_BLANKBOX, 0 }; sys_printdef *nfsmntsyspdefs[] = { &syspdef_NFMPATH, &syspdef_NFMSERVER, &syspdef_NFMTOTREAD, &syspdef_NFMTOTWRITE, &syspdef_NFMNREAD, &syspdef_NFMNWRITE, &syspdef_NFMDREAD, &syspdef_NFMDWRITE, &syspdef_NFMMREAD, &syspdef_NFMMWRITE, &syspdef_BLANKBOX, 0 }; sys_printdef *nfcsyspdefs[] = { &syspdef_NFCRPCCNT, &syspdef_NFCRPCREAD, &syspdef_NFCRPCWRITE, &syspdef_NFCRPCRET, &syspdef_NFCRPCARF, &syspdef_BLANKBOX, 0 }; sys_printdef *nfssyspdefs[] = { &syspdef_NFSRPCCNT, &syspdef_NFSRPCREAD, &syspdef_NFSRPCWRITE, &syspdef_NFSNRBYTES, &syspdef_NFSNWBYTES, &syspdef_NFSNETTCP, &syspdef_NFSNETUDP, &syspdef_NFSBADFMT, &syspdef_NFSBADAUT, &syspdef_NFSBADCLN, &syspdef_NFSRCHITS, &syspdef_NFSRCMISS, &syspdef_NFSRCNOCA, &syspdef_BLANKBOX, 0 }; sys_printdef *nettranssyspdefs[] = { &syspdef_NETTRANSPORT, &syspdef_NETTCPI, &syspdef_NETTCPO, &syspdef_NETUDPI, &syspdef_NETUDPO, &syspdef_NETTCPACTOPEN, &syspdef_NETTCPPASVOPEN, &syspdef_NETTCPRETRANS, &syspdef_NETTCPINERR, &syspdef_NETTCPORESET, &syspdef_NETUDPNOPORT, &syspdef_NETUDPINERR, &syspdef_BLANKBOX, 0 }; sys_printdef *netnetsyspdefs[] = { &syspdef_NETNETWORK, &syspdef_NETIPI, &syspdef_NETIPO, &syspdef_NETIPFRW, &syspdef_NETIPDELIV, &syspdef_NETICMPIN, &syspdef_NETICMPOUT, &syspdef_BLANKBOX, 0 }; sys_printdef *netintfsyspdefs[] = { &syspdef_NETNAME, &syspdef_NETPCKI, &syspdef_NETPCKO, &syspdef_NETSPEEDMAX, &syspdef_NETSPEEDIN, &syspdef_NETSPEEDOUT, &syspdef_NETCOLLIS, &syspdef_NETMULTICASTIN, &syspdef_NETRCVERR, &syspdef_NETSNDERR, &syspdef_NETRCVDROP, &syspdef_NETSNDDROP, &syspdef_BLANKBOX, 0 }; sys_printdef *infinisyspdefs[] = { &syspdef_IFBNAME, &syspdef_IFBPCKI, &syspdef_IFBPCKO, &syspdef_IFBSPEEDMAX, &syspdef_IFBSPEEDIN, &syspdef_IFBSPEEDOUT, &syspdef_IFBLANES, &syspdef_BLANKBOX, 0 }; /* * table with all proc_printdefs */ proc_printdef *allprocpdefs[]= { &procprt_PID, &procprt_TID, &procprt_PPID, &procprt_SYSCPU, &procprt_USRCPU, &procprt_VGROW, &procprt_RGROW, &procprt_MINFLT, &procprt_MAJFLT, &procprt_VSTEXT, &procprt_VSIZE, &procprt_RSIZE, &procprt_PSIZE, &procprt_VSLIBS, &procprt_VDATA, &procprt_VSTACK, &procprt_SWAPSZ, &procprt_CMD, &procprt_RUID, &procprt_EUID, &procprt_SUID, &procprt_FSUID, &procprt_RGID, &procprt_EGID, &procprt_SGID, &procprt_FSGID, &procprt_CTID, &procprt_VPID, &procprt_CID, &procprt_STDATE, &procprt_STTIME, &procprt_ENDATE, &procprt_ENTIME, &procprt_THR, &procprt_TRUN, &procprt_TSLPI, &procprt_TSLPU, &procprt_POLI, &procprt_NICE, &procprt_PRI, &procprt_RTPR, &procprt_CURCPU, &procprt_ST, &procprt_EXC, &procprt_S, &procprt_COMMAND_LINE, &procprt_NPROCS, &procprt_RDDSK, &procprt_WRDSK, &procprt_CWRDSK, &procprt_WCANCEL, &procprt_TCPRCV, &procprt_TCPRASZ, &procprt_TCPSND, &procprt_TCPSASZ, &procprt_UDPRCV, &procprt_UDPRASZ, &procprt_UDPSND, &procprt_UDPSASZ, &procprt_RNET, &procprt_SNET, &procprt_BANDWI, &procprt_BANDWO, &procprt_GPULIST, &procprt_GPUMEMNOW, &procprt_GPUMEMAVG, &procprt_GPUGPUBUSY, &procprt_GPUMEMBUSY, &procprt_SORTITEM, 0 }; /* * table with all proc_printdefs with PID/TID width to be initialized */ proc_printdef *idprocpdefs[]= { &procprt_PID, &procprt_TID, &procprt_PPID, &procprt_VPID, 0 }; /***************************************************************/ /* * output definitions for process data * these should be user configurable */ proc_printpair userprocs[MAXITEMS]; proc_printpair memprocs[MAXITEMS]; proc_printpair schedprocs[MAXITEMS]; proc_printpair genprocs[MAXITEMS]; proc_printpair dskprocs[MAXITEMS]; proc_printpair netprocs[MAXITEMS]; proc_printpair gpuprocs[MAXITEMS]; proc_printpair varprocs[MAXITEMS]; proc_printpair cmdprocs[MAXITEMS]; proc_printpair ownprocs[MAXITEMS]; proc_printpair totusers[MAXITEMS]; proc_printpair totprocs[MAXITEMS]; proc_printpair totconts[MAXITEMS]; /*****************************************************************/ /* * output definitions for system data * these should be user configurable */ sys_printpair sysprcline[MAXITEMS]; sys_printpair allcpuline[MAXITEMS]; sys_printpair indivcpuline[MAXITEMS]; sys_printpair cplline[MAXITEMS]; sys_printpair gpuline[MAXITEMS]; sys_printpair memline[MAXITEMS]; sys_printpair swpline[MAXITEMS]; sys_printpair pagline[MAXITEMS]; sys_printpair psiline[MAXITEMS]; sys_printpair contline[MAXITEMS]; sys_printpair dskline[MAXITEMS]; sys_printpair nettransportline[MAXITEMS]; sys_printpair netnetline[MAXITEMS]; sys_printpair netinterfaceline[MAXITEMS]; sys_printpair infinibandline[MAXITEMS]; sys_printpair nfsmountline[MAXITEMS]; sys_printpair nfcline[MAXITEMS]; sys_printpair nfsline[MAXITEMS]; typedef struct { const char *name; int prio; } name_prio; /* ** make an string,int pair array from a string. chop based on spaces/tabs ** example: input: "ABCD:3 EFG:1 QWE:16" ** output: { { "ABCD", 3 }, {"EFG", 1}, { "QWE", 16}, { 0, 0 } } */ static void makeargv(char *line, const char *linename, name_prio *vec) { int i=0; char *p=line; char *name=0; char *prio=0; // find pair and scan it while (*p && i= INT_MAX || lprio <0) { fprintf(stderr, "atoprc - %s: item `%s` has " "invalid priority `", linename, name); while (*prio && *prio !=' ') { fputc(*prio, stderr); prio++; } fprintf(stderr, "'\n"); cleanstop(1); } vec[i].name=name; vec[i].prio=lprio; ++i; } vec[i].name=0; } /* * make_sys_prints: make array of sys_printpairs * input: string, sys_printpair array, maxentries */ void make_sys_prints(sys_printpair *ar, int maxn, const char *pairs, sys_printdef *permissables[], const char *linename) { name_prio items[MAXITEMS]; int n=strlen(pairs); char str[n+1]; strcpy(str, pairs); makeargv(str, linename, items); int i; for(i=0; items[i].name && iconfigname, name)==0) { ar[i].f=permissables[j]; ar[i].prio=items[i].prio; break; } } if (permissables[j]==0) { fprintf(stderr, "atoprc - own system line: item %s invalid in %s line!\n", name, linename); cleanstop(1); } } ar[i].f=0; ar[i].prio=0; } /* * init_proc_prints: determine width of columns that are * dependent of dynamic values */ void init_proc_prints() { int i, numdigits = 5; char linebuf[64]; FILE *fp; /* ** determine maximum number of digits for PID/TID */ if ( (fp = fopen("/proc/sys/kernel/pid_max", "r")) != NULL) { if ( fgets(linebuf, sizeof(linebuf), fp) != NULL) { numdigits = strlen(linebuf) - 1; } fclose(fp); } /* ** fill number of digits for various PID/TID columns ** and reformat header to new width */ for (i=0; idprocpdefs[i] != 0; i++) { idprocpdefs[i]->width = numdigits; if ( strlen(idprocpdefs[i]->head) < numdigits) { char *p = malloc(numdigits+1); ptrverify(p, "Malloc failed for formatted header\n"); sprintf(p, "%*s", numdigits, idprocpdefs[i]->head); idprocpdefs[i]->head = p; } } } /* * make_proc_prints: make array of proc_printpairs * input: string, proc_printpair array, maxentries */ void make_proc_prints(proc_printpair *ar, int maxn, const char *pairs, const char *linename) { name_prio items[MAXITEMS]; int n=strlen(pairs); char str[n+1]; strcpy(str, pairs); makeargv(str, linename, items); int i; for(i=0; items[i].name && iconfigname, name)==0) { ar[i].f=allprocpdefs[j]; ar[i].prio=items[i].prio; break; } } if (allprocpdefs[j]==0) { fprintf(stderr, "atoprc - ownprocline: item %s invalid!\n", name); cleanstop(1); } } ar[i].f=0; ar[i].prio=0; } /* ** calculate the total consumption on system-level for the ** four main resources */ void totalcap(struct syscap *psc, struct sstat *sstat, struct tstat **proclist, int nactproc) { register int i; psc->nrcpu = sstat->cpu.nrcpu; psc->availcpu = 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; psc->availmem = sstat->mem.physmem * pagesize/1024; /* ** calculate total transfer issued by the active processes ** for disk and for network */ for (psc->availnet=psc->availdsk=0, i=0; i < nactproc; i++) { struct tstat *curstat = *(proclist+i); count_t nett_wsz; psc->availnet += curstat->net.tcpssz; psc->availnet += curstat->net.tcprsz; psc->availnet += curstat->net.udpssz; psc->availnet += curstat->net.udprsz; if (curstat->dsk.wsz > curstat->dsk.cwsz) nett_wsz = curstat->dsk.wsz - curstat->dsk.cwsz; else nett_wsz = 0; psc->availdsk += curstat->dsk.rsz; psc->availdsk += nett_wsz; } for (psc->availgpumem=i=0; i < sstat->gpu.nrgpus; i++) psc->availgpumem += sstat->gpu.gpu[i].memtotnow; psc->nrgpu = sstat->gpu.nrgpus; } /* ** calculate cumulative system- and user-time for all active processes */ void pricumproc(struct sstat *sstat, struct devtstat *devtstat, int nexit, unsigned int noverflow, int avgval, int nsecs) { static int firsttime=1; if (firsttime) { firsttime=0; if (sysprcline[0].f == 0) { make_sys_prints(sysprcline, MAXITEMS, "PRCSYS:8 " "PRCUSER:8 " "BLANKBOX:0 " "PRCNPROC:7 " "PRCNRUNNING:5 " "PRCNSLEEPING:5 " "PRCNDSLEEPING:5 " "PRCNZOMBIE:5 " "PRCCLONES:4 " "BLANKBOX:0 " "PRCNNEXIT:6", prcsyspdefs, "builtin sysprcline"); } if (allcpuline[0].f == 0) { make_sys_prints(allcpuline, MAXITEMS, "CPUSYS:9 " "CPUUSER:8 " "CPUIRQ:6 " "BLANKBOX:0 " "CPUIDLE:7 " "CPUWAIT:7 " "CPUSTEAL:2 " "CPUGUEST:3 " "BLANKBOX:0 " "CPUIPC:5 " "CPUCYCLE:4 " "CPUFREQ:4 " "CPUSCALE:4 ", cpusyspdefs, "builtin allcpuline"); } if (indivcpuline[0].f == 0) { make_sys_prints(indivcpuline, MAXITEMS, "CPUISYS:9 " "CPUIUSER:8 " "CPUIIRQ:6 " "BLANKBOX:0 " "CPUIIDLE:7 " "CPUIWAIT:7 " "CPUISTEAL:2 " "CPUIGUEST:3 " "BLANKBOX:0 " "CPUIIPC:5 " "CPUICYCLE:4 " "CPUIFREQ:4 " "CPUISCALE:4 ", cpisyspdefs, "builtin indivcpuline"); } if (cplline[0].f == 0) { make_sys_prints(cplline, MAXITEMS, "CPLAVG1:4 " "CPLAVG5:3 " "CPLAVG15:2 " "BLANKBOX:0 " "CPLCSW:6 " "CPLINTR:5 " "BLANKBOX:0 " "CPLNUMCPU:1", cplsyspdefs, "builtin cplline"); } if (gpuline[0].f == 0) { make_sys_prints(gpuline, MAXITEMS, "GPUBUS:8 " "GPUGPUPERC:7 " "GPUMEMPERC:6 " "GPUMEMOCC:5 " "GPUMEMTOT:3 " "GPUMEMUSE:4 " "GPUMEMAVG:2 " "GPUNRPROC:2 " "BLANKBOX:0 " "GPUTYPE:1 ", gpusyspdefs, "builtin gpuline"); } if (memline[0].f == 0) { make_sys_prints(memline, MAXITEMS, "MEMTOT:6 " "MEMFREE:7 " "MEMCACHE:5 " "MEMDIRTY:3 " "MEMBUFFER:5 " "MEMSLAB:5 " "RECSLAB:2 " "BLANKBOX:0 " "SHMEM:4 " "SHMRSS:3 " "SHMSWP:1 " "BLANKBOX:0 " "VMWBAL:4 " "BLANKBOX:0 " "HUPTOT:4 " "HUPUSE:3 ", memsyspdefs, "builtin memline"); } if (swpline[0].f == 0) { make_sys_prints(swpline, MAXITEMS, "SWPTOT:3 " "SWPFREE:4 " "BLANKBOX:0 " "BLANKBOX:0 " "BLANKBOX:0 " "BLANKBOX:0 " "BLANKBOX:0 " "BLANKBOX:0 " "SWPCOMMITTED:5 " "SWPCOMMITLIM:6", swpsyspdefs, "builtin swpline"); } if (pagline[0].f == 0) { make_sys_prints(pagline, MAXITEMS, "PAGSCAN:3 " "PAGSTEAL:3 " "PAGSTALL:1 " "BLANKBOX:0 " "BLANKBOX:0 " "BLANKBOX:0 " "BLANKBOX:0 " "BLANKBOX:0 " "PAGSWIN:3 " "PAGSWOUT:4", pagsyspdefs, "builtin pagline"); } if (psiline[0].f == 0) { make_sys_prints(psiline, MAXITEMS, "PSICPUS:3 " "PSIMEMS:3 " "PSIMEMF:3 " "PSIIOS:3 " "PSIIOF:3 " "BLANKBOX:0 " "BLANKBOX:0 " "BLANKBOX:0 ", psisyspdefs, "builtin psiline"); } if (contline[0].f == 0) { make_sys_prints(contline, MAXITEMS, "CONTNAME:8 " "CONTNPROC:7 " "CONTCPU:6 " "CONTMEM:6 " "BLANKBOX:0 " "BLANKBOX:0 ", contsyspdefs, "builtin contline"); } if (dskline[0].f == 0) { make_sys_prints(dskline, MAXITEMS, "DSKNAME:8 " "DSKBUSY:7 " "DSKNREAD:6 " "DSKNWRITE:6 " "DSKKBPERRD:4 " "DSKKBPERWR:4 " "DSKMBPERSECRD:5 " "DSKMBPERSECWR:5 " "DSKAVQUEUE:1 " "DSKAVIO:5", dsksyspdefs, "builtin dskline"); } if (nfsmountline[0].f == 0) { make_sys_prints(nfsmountline, MAXITEMS, "NFMPATH:8 " "NFMSERVER:8 " "NFMTOTREAD:8 " "NFMTOTWRITE:8 " "BLANKBOX:0 " "NFMNREAD:7 " "NFMNWRITE:6 " "BLANKBOX:0 " "NFMDREAD:5 " "NFMDWRITE:4 " "BLANKBOX:0 " "NFMMREAD:3 " "NFMMWRITE:2 " "BLANKBOX:0 " "BLANKBOX:0", nfsmntsyspdefs, "builtin nfsmountline"); } if (nfcline[0].f == 0) { make_sys_prints(nfcline, MAXITEMS, "NFCRPCCNT:8 " "NFCRPCREAD:7 " "NFCRPCWRITE:7 " "NFCRPCRET:5 " "NFCRPCARF:5 " "BLANKBOX:0 " "BLANKBOX:0 " "BLANKBOX:0 " "BLANKBOX:0 " "BLANKBOX:0 ", nfcsyspdefs, "builtin nfcline"); } if (nfsline[0].f == 0) { make_sys_prints(nfsline, MAXITEMS, "NFSRPCCNT:8 " "NFSRPCREAD:6 " "NFSRPCWRITE:6 " "BLANKBOX:0 " "NFSNRBYTES:7 " "NFSNWBYTES:7 " "BLANKBOX:0 " "NFSNETTCP:5 " "NFSNETUDP:5 " "BLANKBOX:0 " "NFSRCHITS:3 " "NFSRCMISS:2 " "NFSRCNOCA:1 " "BLANKBOX:0 " "NFSBADFMT:4 " "NFSBADAUT:4 " "NFSBADCLN:4 ", nfssyspdefs, "builtin nfsline"); } if (nettransportline[0].f == 0) { make_sys_prints(nettransportline, MAXITEMS, "NETTRANSPORT:9 " "NETTCPI:8 " "NETTCPO:8 " "NETUDPI:8 " "NETUDPO:8 " "NETTCPACTOPEN:6 " "NETTCPPASVOPEN:5 " "NETTCPRETRANS:4 " "NETTCPINERR:3 " "NETTCPORESET:2 " "NETUDPNOPORT:1 " "NETUDPINERR:3", nettranssyspdefs, "builtin nettransportline"); } if (netnetline[0].f == 0) { make_sys_prints(netnetline, MAXITEMS, "NETNETWORK:5 " "NETIPI:4 " "NETIPO:4 " "NETIPFRW:4 " "NETIPDELIV:4 " "BLANKBOX:0 " "BLANKBOX:0 " "BLANKBOX:0 " "NETICMPIN:1 " "NETICMPOUT:1 ", netnetsyspdefs, "builtin netnetline"); } if (netinterfaceline[0].f == 0) { make_sys_prints(netinterfaceline, MAXITEMS, "NETNAME:8 " "BLANKBOX:0 " "NETPCKI:7 " "NETPCKO:7 " "BLANKBOX:0 " "NETSPEEDMAX:5 " "NETSPEEDIN:6 " "NETSPEEDOUT:6 " "BLANKBOX:0 " "NETCOLLIS:2 " "NETMULTICASTIN:2 " "NETRCVERR:4 " "NETSNDERR:4 " "NETRCVDROP:3 " "NETSNDDROP:3", netintfsyspdefs, "builtin netinterfaceline"); } if (infinibandline[0].f == 0) { make_sys_prints(infinibandline, MAXITEMS, "IFBNAME:8 " "BLANKBOX:0 " "IFBPCKI:7 " "IFBPCKO:7 " "BLANKBOX:0 " "IFBSPEEDMAX:5 " "IFBSPEEDIN:6 " "IFBSPEEDOUT:6 " "IFBLANES:4 " "BLANKBOX:0 " "BLANKBOX:0 " "BLANKBOX:0 " "BLANKBOX:0 " "BLANKBOX:0 " "BLANKBOX:0 ", infinisyspdefs, "builtin infinibandline"); } } // firsttime int i; extraparam extra; for (i=0, extra.totut=extra.totst=0; i < devtstat->nprocactive; i++) { struct tstat *curstat = *(devtstat->procactive+i); extra.totut += curstat->cpu.utime; extra.totst += curstat->cpu.stime; } extra.nproc = devtstat->nprocall; extra.ntrun = devtstat->totrun; extra.ntslpi = devtstat->totslpi; extra.ntslpu = devtstat->totslpu; extra.nzomb = devtstat->totzombie; extra.nexit = nexit; extra.noverflow = noverflow; extra.avgval = avgval; extra.nsecs = nsecs; move(1, 0); showsysline(sysprcline, sstat, &extra, "PRC", 0); } /* ** print the header for the process list */ void priphead(int curlist, int totlist, char *showtype, char *showorder, char autosort) { static int firsttime=1; static int prev_supportflags = -1, prev_threadview = -1; /* ** determine once the layout of all per-process reports ** except for the generic report (might change dynamically) */ if (firsttime) { init_proc_prints(); make_proc_prints(memprocs, MAXITEMS, "PID:10 TID:3 MINFLT:2 MAJFLT:2 VSTEXT:4 VSLIBS:4 " "VDATA:4 VSTACK:4 VSIZE:6 RSIZE:7 PSIZE:5 " "VGROW:7 RGROW:8 SWAPSZ:5 RUID:1 EUID:0 " "SORTITEM:9 CMD:10", "built-in memprocs"); make_proc_prints(schedprocs, MAXITEMS, "PID:10 TID:6 CID:5 VPID:4 CTID:4 TRUN:7 TSLPI:7 " "TSLPU:7 POLI:8 NICE:9 PRI:9 RTPR:9 CPUNR:8 ST:8 " "EXC:8 S:8 SORTITEM:10 CMD:10", "built-in schedprocs"); make_proc_prints(dskprocs, MAXITEMS, "PID:10 TID:4 RDDSK:9 " "WRDSK:9 WCANCL:8 " "SORTITEM:10 CMD:10", "built-in dskprocs"); make_proc_prints(netprocs, MAXITEMS, "PID:10 TID:6 " "TCPRCV:9 TCPRASZ:4 TCPSND:9 TCPSASZ:4 " "UDPRCV:8 UDPRASZ:3 UDPSND:8 UDPSASZ:3 " "BANDWI:10 BANDWO:10 " "SORTITEM:10 CMD:10", "built-in netprocs"); make_proc_prints(gpuprocs, MAXITEMS, "PID:10 TID:5 CID:4 GPULIST:8 GPUGPUBUSY:8 GPUMEMBUSY:8 " "GPUMEM:7 GPUMEMAVG:6 S:8 SORTITEM:10 CMD:10", "built-in gpuprocs"); make_proc_prints(varprocs, MAXITEMS, "PID:10 TID:4 PPID:9 CID:2 VPID:1 CTID:1 " "RUID:8 RGID:8 EUID:5 EGID:4 " "SUID:3 SGID:2 FSUID:3 FSGID:2 " "STDATE:7 STTIME:7 ENDATE:5 ENTIME:5 " "ST:6 EXC:6 S:6 SORTITEM:10 CMD:10", "built-in varprocs"); make_proc_prints(cmdprocs, MAXITEMS, "PID:10 TID:4 S:8 SORTITEM:10 COMMAND-LINE:10", "built-in cmdprocs"); make_proc_prints(totusers, MAXITEMS, "NPROCS:10 SYSCPU:9 USRCPU:9 VSIZE:6 " "RSIZE:8 PSIZE:8 SWAPSZ:5 RDDSK:7 CWRDSK:7 " "RNET:6 SNET:6 SORTITEM:10 RUID:10", "built-in totusers"); make_proc_prints(totprocs, MAXITEMS, "NPROCS:10 SYSCPU:9 USRCPU:9 VSIZE:6 " "RSIZE:8 PSIZE:8 SWAPSZ:5 RDDSK:7 CWRDSK:7 " "RNET:6 SNET:6 SORTITEM:10 CMD:10", "built-in totprocs"); make_proc_prints(totconts, MAXITEMS, "NPROCS:10 SYSCPU:9 USRCPU:9 VSIZE:6 " "RSIZE:8 PSIZE:8 SWAPSZ:5 RDDSK:7 CWRDSK:7 " "RNET:6 SNET:6 SORTITEM:10 CID:10", "built-in totconts"); } /* ** update the generic report if needed */ if (prev_supportflags != supportflags || prev_threadview != threadview) { make_proc_dynamicgen(); prev_supportflags = supportflags; prev_threadview = threadview; if (*showtype == MPROCNET && !(supportflags&NETATOP) ) { *showtype = MPROCGEN; *showorder = MSORTCPU; } } /* ** print the header line */ switch (*showtype) { case MPROCGEN: showhdrline(genprocs, curlist, totlist, *showorder, autosort); break; case MPROCMEM: showhdrline(memprocs, curlist, totlist, *showorder, autosort); break; case MPROCDSK: showhdrline(dskprocs, curlist, totlist, *showorder, autosort); break; case MPROCNET: showhdrline(netprocs, curlist, totlist, *showorder, autosort); break; case MPROCGPU: showhdrline(gpuprocs, curlist, totlist, *showorder, autosort); break; case MPROCVAR: showhdrline(varprocs, curlist, totlist, *showorder, autosort); break; case MPROCARG: showhdrline(cmdprocs, curlist, totlist, *showorder, autosort); break; case MPROCOWN: showhdrline(ownprocs, curlist, totlist, *showorder, autosort); break; case MPROCSCH: showhdrline(schedprocs, curlist, totlist, *showorder, autosort); break; case MCUMUSER: showhdrline(totusers, curlist, totlist, *showorder, autosort); break; case MCUMPROC: showhdrline(totprocs, curlist, totlist, *showorder, autosort); break; case MCUMCONT: showhdrline(totconts, curlist, totlist, *showorder, autosort); break; } } /* ** assemble the layout of the generic line, ** depending on the supported features (like ** I/O stats, network stats) and current view */ #define FORMPID "PID:10 " #define FORMTID "TID:6 " #define FORMCID "CID:5 " #define FORMCPU "SYSCPU:9 USRCPU:9 " #define FORMMEM "VGROW:8 RGROW:8 " #define FORMDSK "RDDSK:7 CWRDSK:7 " #define FORMNET "RNET:6 SNET:6 " #define FORMMSC "RUID:3 EUID:2 ST:4 EXC:4 THR:4 S:4 CPUNR:4 " #define FORMEND "SORTITEM:10 CMD:10" static void make_proc_dynamicgen() { char format[300], *p = format; memcpy(p, FORMPID, sizeof FORMPID -1); p += sizeof FORMPID -1; if (threadview) { memcpy(p, FORMTID, sizeof FORMTID -1); p += sizeof FORMTID -1; } if (supportflags & DOCKSTAT) { memcpy(p, FORMCID, sizeof FORMCID -1); p += sizeof FORMCID -1; } memcpy(p, FORMCPU, sizeof FORMCPU -1); p += sizeof FORMCPU -1; memcpy(p, FORMMEM, sizeof FORMMEM -1); p += sizeof FORMMEM -1; if (supportflags & IOSTAT) { memcpy(p, FORMDSK, sizeof FORMDSK -1); p += sizeof FORMDSK -1; } if (supportflags & NETATOP) { memcpy(p, FORMNET, sizeof FORMNET -1); p += sizeof FORMNET -1; } memcpy(p, FORMMSC, sizeof FORMMSC -1); p += sizeof FORMMSC -1; memcpy(p, FORMEND, sizeof FORMEND); p += sizeof FORMEND; make_proc_prints(genprocs, MAXITEMS, format, "built-in genprocs"); } /* ** print the list of processes from the deviation-list */ int priproc(struct tstat **proclist, int firstproc, int lastproc, int curline, int curlist, int totlist, char showtype, char showorder, struct syscap *sb, int nsecs, int avgval) { register int i; register struct tstat *curstat; double perc; /* ** print info per actual process and maintain totals */ for (i=firstproc; i < lastproc; i++) { curstat = *(proclist+i); if (screen && curline >= LINES) /* screen filled entirely ? */ break; /* ** calculate occupation-percentage of this process ** depending on selected resource */ switch (showorder) { case MSORTCPU: perc = 0.0; if (sb->availcpu) { perc = (double)(curstat->cpu.stime + curstat->cpu.utime ) * 100 / (sb->availcpu / sb->nrcpu); if (perc > 100.0 * sb->nrcpu) perc = 100.0 * sb->nrcpu; if (perc > 100.0 * curstat->gen.nthr) perc = 100.0 * curstat->gen.nthr; } break; case MSORTMEM: perc = 0.0; if (sb->availmem) { perc = (double)curstat->mem.rmem * 100.0 / sb->availmem; if (perc > 100.0) perc = 100.0; } break; case MSORTDSK: perc = 0.0; if (sb->availdsk) { count_t nett_wsz; if (curstat->dsk.wsz > curstat->dsk.cwsz) nett_wsz = curstat->dsk.wsz - curstat->dsk.cwsz; else nett_wsz = 0; perc = (double)(curstat->dsk.rsz + nett_wsz) * 100.0 / sb->availdsk; if (perc > 100.0) perc = 100.0; } break; case MSORTNET: perc = 0.0; if (sb->availnet) { perc = (double)(curstat->net.tcpssz + curstat->net.tcprsz + curstat->net.udpssz + curstat->net.udprsz ) * 100.0 / sb->availnet; if (perc > 100.0) perc = 100.0; } break; case MSORTGPU: perc = 0.0; if (!curstat->gpu.state) break; if (curstat->gpu.gpubusy != -1) { perc = curstat->gpu.gpubusy; } else { perc = curstat->gpu.memnow*100 * sb->nrgpu / sb->availgpumem; } break; default: perc = 0.0; } /* ** now do the formatting of output */ if (screen) { move(curline,0); } switch (showtype) { case MPROCGEN: showprocline(genprocs, curstat, perc, nsecs, avgval); break; case MPROCMEM: showprocline(memprocs, curstat, perc, nsecs, avgval); break; case MPROCDSK: showprocline(dskprocs, curstat, perc, nsecs, avgval); break; case MPROCNET: showprocline(netprocs, curstat, perc, nsecs, avgval); break; case MPROCGPU: showprocline(gpuprocs, curstat, perc, nsecs, avgval); break; case MPROCVAR: showprocline(varprocs, curstat, perc, nsecs, avgval); break; case MPROCARG: showprocline(cmdprocs, curstat, perc, nsecs, avgval); break; case MPROCOWN: showprocline(ownprocs, curstat, perc, nsecs, avgval); break; case MPROCSCH: showprocline(schedprocs, curstat, perc, nsecs, avgval); break; case MCUMUSER: showprocline(totusers, curstat, perc, nsecs, avgval); break; case MCUMPROC: showprocline(totprocs, curstat, perc, nsecs, avgval); break; case MCUMCONT: showprocline(totconts, curstat, perc, nsecs, avgval); break; } curline++; } return curline; } /* ** print the system-wide statistics */ static void pridisklike(extraparam *, struct perdsk *, char *, char *, int, unsigned int *, int *, int, regex_t *); int prisyst(struct sstat *sstat, int curline, int nsecs, int avgval, int fixedhead, struct sselection *selp, char *highorderp, int maxcpulines, int maxgpulines, int maxdsklines, int maxmddlines, int maxlvmlines, int maxintlines, int maxifblines, int maxnfslines, int maxcontlines) { extraparam extra; int lin; count_t busy; unsigned int badness, highbadness=0; extra.nsecs = nsecs; extra.avgval = avgval; /* ** CPU statistics */ extra.cputot = 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; busy = (extra.cputot - sstat->cpu.all.itime - sstat->cpu.all.wtime) * 100.0 / extra.cputot; if (cpubadness) badness = busy * 100 / cpubadness; else badness = 0; if (highbadness < badness) { highbadness = badness; *highorderp = MSORTCPU; } if (extra.cputot == 0) extra.cputot = 1; /* avoid divide-by-zero */ extra.percputot = extra.cputot / sstat->cpu.nrcpu; if (extra.percputot == 0) extra.percputot = 1; /* avoid divide-by-zero */ if (screen) move(curline, 0); showsysline(allcpuline, sstat, &extra, "CPU", badness); curline++; if (sstat->cpu.nrcpu > 1) { for (extra.index=lin=0; extra.index < sstat->cpu.nrcpu && lin < maxcpulines; extra.index++) { extra.percputot = sstat->cpu.cpu[extra.index].stime + sstat->cpu.cpu[extra.index].utime + sstat->cpu.cpu[extra.index].ntime + sstat->cpu.cpu[extra.index].itime + sstat->cpu.cpu[extra.index].wtime + sstat->cpu.cpu[extra.index].Itime + sstat->cpu.cpu[extra.index].Stime + sstat->cpu.cpu[extra.index].steal; if (extra.percputot == (sstat->cpu.cpu[extra.index].itime + sstat->cpu.cpu[extra.index].wtime ) && !fixedhead ) continue; /* inactive cpu */ busy = (extra.percputot - sstat->cpu.cpu[extra.index].itime - sstat->cpu.cpu[extra.index].wtime) * 100.0 / extra.percputot; if (cpubadness) badness = busy * 100 / cpubadness; else badness = 0; if (highbadness < badness) { highbadness = badness; *highorderp = MSORTCPU; } if (extra.percputot == 0) extra.percputot = 1; /* avoid divide-by-zero */ if (screen) move(curline, 0); showsysline(indivcpuline, sstat, &extra, "cpu", badness); curline++; lin++; } } /* ** other CPU-related statistics */ if (screen) move(curline, 0); showsysline(cplline, sstat, &extra, "CPL", 0); curline++; /* ** GPU statistics */ if (sstat->gpu.nrgpus) { for (extra.index=0, lin=0; extra.index < sstat->gpu.nrgpus && lin < maxgpulines; extra.index++) { int totbusy; count_t avgmemuse; // notice that GPU percentage and memory percentage // are not always available; in that case both // values have the value -1 // totbusy = sstat->gpu.gpu[extra.index].gpuperccum + sstat->gpu.gpu[extra.index].memperccum; if (totbusy == -2) // metrics available? totbusy= 0; if (sstat->gpu.gpu[extra.index].samples == 0) { totbusy = sstat->gpu.gpu[extra.index].gpupercnow + sstat->gpu.gpu[extra.index].mempercnow; avgmemuse = sstat->gpu.gpu[extra.index].memusenow; } else { totbusy = totbusy / sstat->gpu.gpu[extra.index].samples; avgmemuse = sstat->gpu.gpu[extra.index].memusecum/ sstat->gpu.gpu[extra.index].samples; } if (gpubadness) badness = totbusy * 100 / gpubadness; else badness = 0; if ( totbusy > 0 || // memusage > 512 MiB (rather arbitrary)? avgmemuse > 512*1024 || fixedhead ) { showsysline(gpuline, sstat, &extra, "GPU", badness); curline++; lin++; } } } /* ** MEMORY statistics */ busy = (sstat->mem.physmem - sstat->mem.freemem - sstat->mem.cachemem - sstat->mem.buffermem - sstat->mem.slabreclaim + sstat->mem.shmem) * 100.0 / sstat->mem.physmem; if (membadness) badness = busy * 100 / membadness; else badness = 0; if (highbadness < badness) { highbadness = badness; *highorderp = MSORTMEM; } if (screen) move(curline, 0); showsysline(memline, sstat, &extra, "MEM", badness); curline++; /* ** SWAP statistics */ busy = (sstat->mem.totswap - sstat->mem.freeswap) * 100.0 / sstat->mem.totswap; if (swpbadness) { badness = busy * 100 / swpbadness; } else { badness = 0; } if (highbadness < badness) { highbadness = badness; *highorderp = MSORTMEM; } if (screen) move(curline, 0); showsysline(swpline, sstat, &extra, "SWP", badness); curline++; /* ** PAGING statistics */ if (fixedhead || sstat->mem.pgscans || sstat->mem.pgsteal || sstat->mem.allocstall || sstat->mem.swins || sstat->mem.swouts ) { busy = sstat->mem.swouts / nsecs * pagbadness; if (busy > 100) busy = 100; if (membadness) badness = busy * 100 / membadness; else badness = 0; if (highbadness < badness) { highbadness = badness; *highorderp = MSORTMEM; } /* ** take care that this line is anyhow colored for ** 'almost critical' in case of swapouts > 1 per second */ if (sstat->mem.swouts / nsecs > 0 && pagbadness && almostcrit && badness < almostcrit) badness = almostcrit; if (screen) move(curline, 0); showsysline(pagline, sstat, &extra,"PAG", badness); curline++; } /* ** Pressure statistics */ if (sstat->psi.present) { if (fixedhead || sstat->psi.cpusome.avg10 || sstat->psi.memsome.avg10 || sstat->psi.iosome.avg10 || sstat->psi.cpusome.avg60 || sstat->psi.memsome.avg60 || sstat->psi.iosome.avg60 || sstat->psi.cpusome.avg300 || sstat->psi.memsome.avg300 || sstat->psi.iosome.avg300 ) { badness = sstat->psi.cpusome.avg10 > sstat->psi.cpusome.avg60 ? sstat->psi.cpusome.avg10 : sstat->psi.cpusome.avg60; if (badness < sstat->psi.cpusome.avg300) badness = sstat->psi.cpusome.avg300; if (screen) move(curline, 0); showsysline(psiline, sstat, &extra,"PSI", badness); curline++; } } /* ** Container statistics (if any) */ for (extra.index=0, lin=0; extra.index < sstat->cfs.nrcontainer && lin < maxcontlines; extra.index++) { if (fixedhead || sstat->cfs.cont[extra.index].system || sstat->cfs.cont[extra.index].user || sstat->cfs.cont[extra.index].nice ) { if (screen) move(curline, 0); showsysline(contline, sstat, &extra, "CON", 0); curline++; lin++; } } /* ** DISK statistics */ extra.mstot = extra.cputot * 1000 / hertz / sstat->cpu.nrcpu; pridisklike(&extra, sstat->dsk.lvm, "LVM", highorderp, maxlvmlines, &highbadness, &curline, fixedhead, selp->lvmnamesz ? &(selp->lvmregex) : (void *) 0); pridisklike(&extra, sstat->dsk.mdd, "MDD", highorderp, maxmddlines, &highbadness, &curline, fixedhead, (void *) 0); pridisklike(&extra, sstat->dsk.dsk, "DSK", highorderp, maxdsklines, &highbadness, &curline, fixedhead, selp->dsknamesz ? &(selp->dskregex) : (void *) 0); /* ** NFS server and client statistics */ for (extra.index=0, lin=0; extra.index < sstat->nfs.nfsmounts.nrmounts && lin < maxnfslines; extra.index++) { int i = extra.index; if ( (sstat->nfs.nfsmounts.nfsmnt[i].bytesread + sstat->nfs.nfsmounts.nfsmnt[i].byteswrite + sstat->nfs.nfsmounts.nfsmnt[i].bytesdread + sstat->nfs.nfsmounts.nfsmnt[i].bytesdwrite + sstat->nfs.nfsmounts.nfsmnt[i].bytestotread + sstat->nfs.nfsmounts.nfsmnt[i].bytestotwrite + sstat->nfs.nfsmounts.nfsmnt[i].pagesmread + sstat->nfs.nfsmounts.nfsmnt[i].pagesmwrite ) || sstat->nfs.nfsmounts.nfsmnt[i].age < nsecs || fixedhead ) { if (screen) move(curline, 0); showsysline(nfsmountline, sstat, &extra, "NFM", 0); curline++; lin++; } } if (sstat->nfs.client.rpccnt || fixedhead ) { if (screen) move(curline, 0); showsysline(nfcline, sstat, &extra, "NFC", 0); curline++; } if (sstat->nfs.server.rpccnt || fixedhead ) { if (screen) move(curline, 0); showsysline(nfsline, sstat, &extra, "NFS", 0); curline++; } /* ** NET statistics: transport */ if (sstat->net.tcp.InSegs || sstat->net.tcp.OutSegs || sstat->net.udpv4.InDatagrams || sstat->net.udpv6.Udp6InDatagrams || sstat->net.udpv4.OutDatagrams || sstat->net.udpv6.Udp6OutDatagrams || fixedhead ) { if (screen) move(curline, 0); showsysline(nettransportline, sstat, &extra, "NET", 0); curline++; } /* ** NET statistics: network */ if (sstat->net.ipv4.InReceives || sstat->net.ipv6.Ip6InReceives || sstat->net.ipv4.OutRequests || sstat->net.ipv6.Ip6OutRequests || fixedhead ) { if (screen) move(curline, 0); showsysline(netnetline, sstat, &extra, "NET", 0); curline++; } /* ** NET statistics: interfaces */ for (extra.index=0, lin=0; sstat->intf.intf[extra.index].name[0] && lin < maxintlines; extra.index++) { if (sstat->intf.intf[extra.index].rpack || sstat->intf.intf[extra.index].spack || fixedhead) { if (selp->itfnamesz && regexec(&(selp->itfregex), sstat->intf.intf[extra.index].name, 0, NULL, 0)) continue; // suppress (not selected) /* ** calculate busy-percentage for interface */ count_t ival, oval; /* ** convert byte-transfers to bit-transfers (* 8) ** convert bit-transfers to kilobit-transfers (/ 1000) ** per second */ ival = sstat->intf.intf[extra.index].rbyte/125/nsecs; oval = sstat->intf.intf[extra.index].sbyte/125/nsecs; /* speed known? */ if (sstat->intf.intf[extra.index].speed) { if (sstat->intf.intf[extra.index].duplex) busy = (ival > oval ? ival : oval) / (sstat->intf.intf[extra.index].speed *10); else busy = (ival + oval) / (sstat->intf.intf[extra.index].speed *10); } else { busy = 0; } if (netbadness) badness = busy * 100 / netbadness; else badness = 0; if (highbadness < badness && (supportflags & NETATOP) ) { highbadness = badness; *highorderp = MSORTNET; } if (screen) move(curline, 0); showsysline(netinterfaceline, sstat, &extra, "NET", badness); curline++; lin++; } } /* ** NET statistics: InfiniBand */ for (extra.index=0, lin=0; extra.index < sstat->ifb.nrports && lin < maxifblines; extra.index++) { if (sstat->ifb.ifb[extra.index].rcvb || sstat->ifb.ifb[extra.index].sndb || fixedhead) { /* ** calculate busy-percentage for IB port */ count_t ival, oval; /* ** convert byte-transfers to bit-transfers (* 8) ** convert bit-transfers to kilobit-transfers (/ 1000) ** per second */ ival = sstat->ifb.ifb[extra.index].rcvb/125/nsecs; oval = sstat->ifb.ifb[extra.index].sndb/125/nsecs; busy = (ival > oval ? ival : oval) * sstat->ifb.ifb[extra.index].lanes / (sstat->ifb.ifb[extra.index].rate * 10); if (netbadness) badness = busy * 100 / netbadness; else badness = 0; if (highbadness < badness) { highbadness = badness; *highorderp = MSORTNET; } if (screen) move(curline, 0); showsysline(infinibandline, sstat, &extra, "IFB", badness); curline++; lin++; } } /* ** application statistics ** ** WWW: notice that we cause one access ourselves by fetching ** the statistical counters */ #if HTTPSTATS if (sstat->www.accesses > 1 || fixedhead ) { char format1[8], format2[8], format3[8], format4[8], format5[8]; if (screen) move(curline, 0); printg("WWW | reqs %s | totKB %s | byt/rq %s | iwork %s |" " bwork %s |", val2valstr(sstat->www.accesses, format1, 6, avgval, nsecs), val2valstr(sstat->www.totkbytes, format2, 6, avgval, nsecs), val2valstr(sstat->www.accesses ? sstat->www.totkbytes*1024/sstat->www.accesses : 0, format3, 5, 0, 0), val2valstr(sstat->www.iworkers, format4, 6, 0, 0), val2valstr(sstat->www.bworkers, format5, 6, 0, 0) ); if (!screen) { printg("\n"); } curline++; } #endif /* ** if the system is hardly loaded, still CPU-ordering of ** processes is most interesting (instead of memory) */ if (highbadness < 70 && *highorderp == MSORTMEM) *highorderp = MSORTCPU; return curline; } /* ** handle all instances of a specific disk-like device */ static void pridisklike(extraparam *ep, struct perdsk *dp, char *lp, char *highorderp, int maxlines, unsigned int *highbadp, int *curlinp, int fixedhead, regex_t *rep) { int lin; count_t busy; unsigned int badness; for (ep->perdsk = dp, ep->index=0, lin=0; ep->perdsk[ep->index].name[0] && lin < maxlines; ep->index++) { if (rep && regexec(rep, ep->perdsk[ep->index].name, 0, NULL, 0)) continue; // suppress (not selected) ep->iotot = ep->perdsk[ep->index].nread + ep->perdsk[ep->index].nwrite; busy = (double)(ep->perdsk[ep->index].io_ms * 100.0 / ep->mstot); if (dskbadness) badness = busy * 100 / dskbadness; else badness = 0; if (*highbadp < badness && (supportflags & IOSTAT) ) { *highbadp = badness; *highorderp = MSORTDSK; } if (ep->iotot || fixedhead) { move(*curlinp, 0); showsysline(dskline, 0, ep, lp, badness); (*curlinp)++; lin++; } } } /* ** process-level sort functions */ int compcpu(const void *a, const void *b) { register count_t acpu = (*(struct tstat **)a)->cpu.stime + (*(struct tstat **)a)->cpu.utime; register count_t bcpu = (*(struct tstat **)b)->cpu.stime + (*(struct tstat **)b)->cpu.utime; if (acpu < bcpu) return 1; if (acpu > bcpu) return -1; return compmem(a, b); } int compdsk(const void *a, const void *b) { struct tstat *ta = *(struct tstat **)a; struct tstat *tb = *(struct tstat **)b; count_t adsk; count_t bdsk; if (ta->dsk.wsz > ta->dsk.cwsz) adsk = ta->dsk.rio + ta->dsk.wsz - ta->dsk.cwsz; else adsk = ta->dsk.rio; if (tb->dsk.wsz > tb->dsk.cwsz) bdsk = tb->dsk.rio + tb->dsk.wsz - tb->dsk.cwsz; else bdsk = tb->dsk.rio; if (adsk < bdsk) return 1; if (adsk > bdsk) return -1; return compcpu(a, b); } int compmem(const void *a, const void *b) { register count_t amem = (*(struct tstat **)a)->mem.rmem; register count_t bmem = (*(struct tstat **)b)->mem.rmem; if (amem < bmem) return 1; if (amem > bmem) return -1; return 0; } int compgpu(const void *a, const void *b) { register char astate = (*(struct tstat **)a)->gpu.state; register char bstate = (*(struct tstat **)b)->gpu.state; register count_t abusy = (*(struct tstat **)a)->gpu.gpubusy; register count_t bbusy = (*(struct tstat **)b)->gpu.gpubusy; register count_t amem = (*(struct tstat **)a)->gpu.memnow; register count_t bmem = (*(struct tstat **)b)->gpu.memnow; if (!astate) // no GPU usage? abusy = amem = -2; if (!bstate) // no GPU usage? bbusy = bmem = -2; if (abusy == -1 || bbusy == -1) { if (amem < bmem) return 1; if (amem > bmem) return -1; return 0; } else { if (abusy < bbusy) return 1; if (abusy > bbusy) return -1; return 0; } } int compnet(const void *a, const void *b) { register count_t anet = (*(struct tstat **)a)->net.tcpssz + (*(struct tstat **)a)->net.tcprsz + (*(struct tstat **)a)->net.udpssz + (*(struct tstat **)a)->net.udprsz ; register count_t bnet = (*(struct tstat **)b)->net.tcpssz + (*(struct tstat **)b)->net.tcprsz + (*(struct tstat **)b)->net.udpssz + (*(struct tstat **)b)->net.udprsz ; if (anet < bnet) return 1; if (anet > bnet) return -1; return compcpu(a, b); } int compusr(const void *a, const void *b) { register int uida = (*(struct tstat **)a)->gen.ruid; register int uidb = (*(struct tstat **)b)->gen.ruid; if (uida > uidb) return 1; if (uida < uidb) return -1; return 0; } int compnam(const void *a, const void *b) { register char *nama = (*(struct tstat **)a)->gen.name; register char *namb = (*(struct tstat **)b)->gen.name; return strcmp(nama, namb); } int compcon(const void *a, const void *b) { register char *containera = (*(struct tstat **)a)->gen.container; register char *containerb = (*(struct tstat **)b)->gen.container; return strcmp(containera, containerb); } /* ** system-level sort functions */ int cpucompar(const void *a, const void *b) { register count_t aidle = ((struct percpu *)a)->itime + ((struct percpu *)a)->wtime; register count_t bidle = ((struct percpu *)b)->itime + ((struct percpu *)b)->wtime; if (aidle < bidle) return -1; if (aidle > bidle) return 1; return 0; } int gpucompar(const void *a, const void *b) { register count_t agpuperc = ((struct pergpu *)a)->gpuperccum; register count_t bgpuperc = ((struct pergpu *)b)->gpuperccum; register count_t amemuse = ((struct pergpu *)a)->memusenow; register count_t bmemuse = ((struct pergpu *)b)->memusenow; if (agpuperc == -1 || bgpuperc == -1) { if (amemuse < bmemuse) return 1; if (amemuse > bmemuse) return -1; return 0; } else { if (agpuperc < bgpuperc) return 1; if (agpuperc > bgpuperc) return -1; return 0; } } int diskcompar(const void *a, const void *b) { register count_t amsio = ((struct perdsk *)a)->io_ms; register count_t bmsio = ((struct perdsk *)b)->io_ms; if (amsio < bmsio) return 1; if (amsio > bmsio) return -1; return 0; } int intfcompar(const void *a, const void *b) { register count_t afactor=0, bfactor=0; count_t aspeed = ((struct perintf *)a)->speed; count_t bspeed = ((struct perintf *)b)->speed; char aduplex = ((struct perintf *)a)->duplex; char bduplex = ((struct perintf *)b)->duplex; count_t arbyte = ((struct perintf *)a)->rbyte; count_t brbyte = ((struct perintf *)b)->rbyte; count_t asbyte = ((struct perintf *)a)->sbyte; count_t bsbyte = ((struct perintf *)b)->sbyte; /* ** if speed of first interface known, calculate busy factor */ if (aspeed) { if (aduplex) afactor = (arbyte > asbyte ? arbyte : asbyte) * 10 / aspeed; else afactor = (arbyte + asbyte) * 10 / aspeed; } /* ** if speed of second interface known, calculate busy factor */ if (bspeed) { if (bduplex) bfactor = (brbyte > bsbyte ? brbyte : bsbyte) * 10 / bspeed; else bfactor = (brbyte + bsbyte) * 10 / bspeed; } /* ** compare interfaces */ if (aspeed && bspeed) { if (afactor < bfactor) return 1; if (afactor > bfactor) return -1; return 0; } if (!aspeed && !bspeed) { if ((arbyte + asbyte) < (brbyte + bsbyte)) return 1; if ((arbyte + asbyte) > (brbyte + bsbyte)) return -1; return 0; } if (aspeed) return -1; else return 1; } int ifbcompar(const void *a, const void *b) { count_t atransfer = ((struct perifb *)a)->rcvb + ((struct perifb *)a)->sndb; count_t btransfer = ((struct perifb *)b)->rcvb + ((struct perifb *)b)->sndb; if (atransfer < btransfer) return 1; if (atransfer > btransfer) return -1; return 0; } int nfsmcompar(const void *a, const void *b) { const struct pernfsmount *na = a; const struct pernfsmount *nb = b; register count_t aused = na->bytesread + na->byteswrite + na->bytesdread + na->bytesdwrite + na->bytestotread + na->bytestotwrite + na->pagesmread + na->pagesmwrite; register count_t bused = nb->bytesread + nb->byteswrite + nb->bytesdread + nb->bytesdwrite + nb->bytestotread + nb->bytestotwrite + nb->pagesmread + nb->pagesmwrite; if (aused < bused) return 1; if (aused > bused) return -1; return 0; } int contcompar(const void *a, const void *b) { const struct percontainer *ca = a; const struct percontainer *cb = b; register count_t aused = ca->system + ca->user + ca->nice; register count_t bused = cb->system + cb->user + cb->nice; if (aused < bused) return 1; if (aused > bused) return -1; return 0; } /* ** handle modifications from the /etc/atoprc and ~/.atoprc file */ int get_posval(char *name, char *val) { int value = atoi(val); if ( !numeric(val)) { fprintf(stderr, "atoprc: %s value %s not a (positive) numeric\n", name, val); exit(1); } if (value < 0) { fprintf(stderr, "atoprc: %s value %d not positive\n", name, value); exit(1); } return value; } int get_perc(char *name, char *val) { int value = get_posval(name, val); if (value < 0 || value > 100) { fprintf(stderr, "atoprc: %s value %d not in range 0-100\n", name, value); exit(1); } return value; } void do_cpucritperc(char *name, char *val) { cpubadness = get_perc(name, val); } void do_gpucritperc(char *name, char *val) { gpubadness = get_perc(name, val); } void do_memcritperc(char *name, char *val) { membadness = get_perc(name, val); } void do_swpcritperc(char *name, char *val) { swpbadness = get_perc(name, val); } void do_dskcritperc(char *name, char *val) { dskbadness = get_perc(name, val); } void do_netcritperc(char *name, char *val) { netbadness = get_perc(name, val); } void do_swoutcritsec(char *name, char *val) { pagbadness = get_posval(name, val); } void do_almostcrit(char *name, char *val) { almostcrit = get_perc(name, val); } void do_ownsysprcline(char *name, char *val) { make_sys_prints(sysprcline, MAXITEMS, val, prcsyspdefs, name); } void do_ownallcpuline(char *name, char *val) { make_sys_prints(allcpuline, MAXITEMS, val, cpusyspdefs, name); } void do_ownindivcpuline(char *name, char *val) { make_sys_prints(indivcpuline, MAXITEMS, val, cpisyspdefs, name); } void do_owncplline(char *name, char *val) { make_sys_prints(cplline, MAXITEMS, val, cplsyspdefs, name); } void do_owngpuline(char *name, char *val) { make_sys_prints(gpuline, MAXITEMS, val, gpusyspdefs, name); } void do_ownmemline(char *name, char *val) { make_sys_prints(memline, MAXITEMS, val, memsyspdefs, name); } void do_ownswpline(char *name, char *val) { make_sys_prints(swpline, MAXITEMS, val, swpsyspdefs, name); } void do_ownpagline(char *name, char *val) { make_sys_prints(pagline, MAXITEMS, val, pagsyspdefs, name); } void do_owndskline(char *name, char *val) { make_sys_prints(dskline, MAXITEMS, val, dsksyspdefs, name); } void do_ownnettransportline(char *name, char *val) { make_sys_prints(nettransportline, MAXITEMS, val, nettranssyspdefs, name); } void do_ownnetnetline(char *name, char *val) { make_sys_prints(netnetline, MAXITEMS, val, netnetsyspdefs, name); } void do_ownnetinterfaceline(char *name, char *val) { make_sys_prints(netinterfaceline, MAXITEMS, val, netintfsyspdefs, name); } void do_owninfinibandline(char *name, char *val) { make_sys_prints(infinibandline, MAXITEMS, val, infinisyspdefs, name); } void do_ownprocline(char *name, char *val) { make_proc_prints(ownprocs, MAXITEMS, val, name); } atop-2.4.0/showlinux.h0000664000203100020310000003430013416466037014205 0ustar gerlofgerlof/* ** 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 the Linux-specific functions to calculate ** figures to be visualized. ** ========================================================================== ** Author: JC van Winkel - AT Computing, Nijmegen, Holland ** E-mail: jc@ATComputing.nl ** Date: November 2009 ** -------------------------------------------------------------------------- ** Copyright (C) 2009 JC van Winkel ** ** 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 ** -------------------------------------------------------------------------- ** ** $Log: showlinux.h,v $ ** Initial revision ** ** Initial ** */ #define MAXITEMS 80 /* The maximum number of items per line */ /* * structure for extra parameters for system related data */ typedef struct { count_t totut; count_t totst; int nact; int nproc; int ntrun; int ntslpi; int ntslpu; int nzomb; int nexit; int noverflow; int avgval; int nsecs; count_t mstot; count_t iotot; struct perdsk *perdsk; int index; count_t cputot; count_t percputot; } extraparam; /***************************************************************/ /* * structure for system print-list */ typedef struct { char *configname; // name as used to // config print line char* (*doconvert)(void *, void *, int, int *); // ptr to convert func } sys_printdef; /* * structure for system print-list with priority * in case of leck of screen space, lowest priority items will be * removed first */ typedef struct { sys_printdef *f; int prio; } sys_printpair; /* ** structure for process print-list */ typedef struct { char *head; // column header char *configname; // name as used to config print line char *(*doactiveconvert)(struct tstat *,int,int); // pointer to conv function // for active process char *(*doexitconvert) (struct tstat *,int,int); // pointer to conv function // for exited process int width; // required width int varwidth; // width may grow (eg cmd params) } proc_printdef; typedef struct { proc_printdef *f; int prio; } proc_printpair; void showsysline(sys_printpair* elemptr, struct sstat* sstat, extraparam *extra, char *labeltext, unsigned int badness); void showhdrline(proc_printpair* elemptr, int curlist, int totlist, char showorder, char autosort); void showprocline(proc_printpair* elemptr, struct tstat *curstat, double perc, int nsecs, int avgval); extern sys_printdef *prcsyspdefs[]; extern sys_printdef *cpusyspdefs[]; extern sys_printdef *cpisyspdefs[]; extern sys_printdef *cplsyspdefs[]; extern sys_printdef *memsyspdefs[]; extern sys_printdef *swpsyspdefs[]; extern sys_printdef *pagsyspdefs[]; extern sys_printdef *dsksyspdefs[]; extern sys_printdef *nettranssyspdefs[]; extern sys_printdef *netnetsyspdefs[]; extern sys_printdef *netintfsyspdefs[]; extern sys_printdef *infinisyspdefs[]; extern sys_printdef syspdef_PRCSYS; extern sys_printdef syspdef_PRCUSER; extern sys_printdef syspdef_PRCNPROC; extern sys_printdef syspdef_PRCNRUNNING; extern sys_printdef syspdef_PRCNSLEEPING; extern sys_printdef syspdef_PRCNDSLEEPING; extern sys_printdef syspdef_PRCNZOMBIE; extern sys_printdef syspdef_PRCCLONES; extern sys_printdef syspdef_PRCNNEXIT; extern sys_printdef syspdef_CPUSYS; extern sys_printdef syspdef_CPUUSER; extern sys_printdef syspdef_CPUIRQ; extern sys_printdef syspdef_CPUIDLE; extern sys_printdef syspdef_CPUWAIT; extern sys_printdef syspdef_CPUISYS; extern sys_printdef syspdef_CPUIUSER; extern sys_printdef syspdef_CPUIIRQ; extern sys_printdef syspdef_CPUIIDLE; extern sys_printdef syspdef_CPUIWAIT; extern sys_printdef syspdef_CPUISTEAL; extern sys_printdef syspdef_CPUIFREQ; extern sys_printdef syspdef_CPUFREQ; extern sys_printdef syspdef_CPUSCALE; extern sys_printdef syspdef_CPUISCALE; extern sys_printdef syspdef_CPUSTEAL; extern sys_printdef syspdef_CPUISTEAL; extern sys_printdef syspdef_CPUGUEST; extern sys_printdef syspdef_CPUIGUEST; extern sys_printdef syspdef_CPUIPC; extern sys_printdef syspdef_CPUIIPC; extern sys_printdef syspdef_CPUCYCLE; extern sys_printdef syspdef_CPUICYCLE; extern sys_printdef syspdef_CPLAVG1; extern sys_printdef syspdef_CPLAVG5; extern sys_printdef syspdef_CPLAVG15; extern sys_printdef syspdef_CPLCSW; extern sys_printdef syspdef_CPLNUMCPU; extern sys_printdef syspdef_CPLINTR; extern sys_printdef syspdef_GPUBUS; extern sys_printdef syspdef_GPUTYPE; extern sys_printdef syspdef_GPUNRPROC; extern sys_printdef syspdef_GPUMEMPERC; extern sys_printdef syspdef_GPUMEMOCC; extern sys_printdef syspdef_GPUGPUPERC; extern sys_printdef syspdef_GPUMEMTOT; extern sys_printdef syspdef_GPUMEMUSE; extern sys_printdef syspdef_GPUMEMAVG; extern sys_printdef syspdef_MEMTOT; extern sys_printdef syspdef_MEMFREE; extern sys_printdef syspdef_MEMCACHE; extern sys_printdef syspdef_MEMDIRTY; extern sys_printdef syspdef_MEMBUFFER; extern sys_printdef syspdef_MEMSLAB; extern sys_printdef syspdef_RECSLAB; extern sys_printdef syspdef_SHMEM; extern sys_printdef syspdef_SHMRSS; extern sys_printdef syspdef_SHMSWP; extern sys_printdef syspdef_VMWBAL; extern sys_printdef syspdef_HUPTOT; extern sys_printdef syspdef_HUPUSE; extern sys_printdef syspdef_SWPTOT; extern sys_printdef syspdef_SWPFREE; extern sys_printdef syspdef_SWPCOMMITTED; extern sys_printdef syspdef_SWPCOMMITLIM; extern sys_printdef syspdef_PAGSCAN; extern sys_printdef syspdef_PAGSTEAL; extern sys_printdef syspdef_PAGSTALL; extern sys_printdef syspdef_PAGSWIN; extern sys_printdef syspdef_PAGSWOUT; extern sys_printdef syspdef_PSICPUS; extern sys_printdef syspdef_PSIMEMS; extern sys_printdef syspdef_PSIMEMF; extern sys_printdef syspdef_PSIIOS; extern sys_printdef syspdef_PSIIOF; extern sys_printdef syspdef_CONTNAME; extern sys_printdef syspdef_CONTNPROC; extern sys_printdef syspdef_CONTCPU; extern sys_printdef syspdef_CONTMEM; extern sys_printdef syspdef_DSKNAME; extern sys_printdef syspdef_DSKBUSY; extern sys_printdef syspdef_DSKNREAD; extern sys_printdef syspdef_DSKNWRITE; extern sys_printdef syspdef_DSKMBPERSECWR; extern sys_printdef syspdef_DSKMBPERSECRD; extern sys_printdef syspdef_DSKKBPERWR; extern sys_printdef syspdef_DSKKBPERRD; extern sys_printdef syspdef_DSKAVQUEUE; extern sys_printdef syspdef_DSKAVIO; extern sys_printdef syspdef_NETTRANSPORT; extern sys_printdef syspdef_NETTCPI; extern sys_printdef syspdef_NETTCPO; extern sys_printdef syspdef_NETTCPACTOPEN; extern sys_printdef syspdef_NETTCPPASVOPEN; extern sys_printdef syspdef_NETTCPRETRANS; extern sys_printdef syspdef_NETTCPINERR; extern sys_printdef syspdef_NETTCPORESET; extern sys_printdef syspdef_NETUDPNOPORT; extern sys_printdef syspdef_NETUDPINERR; extern sys_printdef syspdef_NETUDPI; extern sys_printdef syspdef_NETUDPO; extern sys_printdef syspdef_NETNETWORK; extern sys_printdef syspdef_NETIPI; extern sys_printdef syspdef_NETIPO; extern sys_printdef syspdef_NETIPFRW; extern sys_printdef syspdef_NETIPDELIV; extern sys_printdef syspdef_NETICMPIN; extern sys_printdef syspdef_NETICMPOUT; extern sys_printdef syspdef_NETNAME; extern sys_printdef syspdef_NETPCKI; extern sys_printdef syspdef_NETPCKO; extern sys_printdef syspdef_NETSPEEDMAX; extern sys_printdef syspdef_NETSPEEDIN; extern sys_printdef syspdef_NETSPEEDOUT; extern sys_printdef syspdef_NETCOLLIS; extern sys_printdef syspdef_NETMULTICASTIN; extern sys_printdef syspdef_NETRCVERR; extern sys_printdef syspdef_NETSNDERR; extern sys_printdef syspdef_NETRCVDROP; extern sys_printdef syspdef_NETSNDDROP; extern sys_printdef syspdef_NFMSERVER; extern sys_printdef syspdef_NFMPATH; extern sys_printdef syspdef_NFMTOTREAD; extern sys_printdef syspdef_NFMTOTWRITE; extern sys_printdef syspdef_NFMNREAD; extern sys_printdef syspdef_NFMNWRITE; extern sys_printdef syspdef_NFMDREAD; extern sys_printdef syspdef_NFMDWRITE; extern sys_printdef syspdef_NFMMREAD; extern sys_printdef syspdef_NFMMWRITE; extern sys_printdef syspdef_NFCRPCCNT; extern sys_printdef syspdef_NFCRPCREAD; extern sys_printdef syspdef_NFCRPCWRITE; extern sys_printdef syspdef_NFCRPCRET; extern sys_printdef syspdef_NFCRPCARF; extern sys_printdef syspdef_NFSRPCCNT; extern sys_printdef syspdef_NFSRPCREAD; extern sys_printdef syspdef_NFSRPCWRITE; extern sys_printdef syspdef_NFSBADFMT; extern sys_printdef syspdef_NFSBADAUT; extern sys_printdef syspdef_NFSBADCLN; extern sys_printdef syspdef_NFSNETTCP; extern sys_printdef syspdef_NFSNETUDP; extern sys_printdef syspdef_NFSNRBYTES; extern sys_printdef syspdef_NFSNWBYTES; extern sys_printdef syspdef_NFSRCHITS; extern sys_printdef syspdef_NFSRCMISS; extern sys_printdef syspdef_NFSRCNOCA; extern sys_printdef syspdef_IFBNAME; extern sys_printdef syspdef_IFBPCKI; extern sys_printdef syspdef_IFBPCKO; extern sys_printdef syspdef_IFBSPEEDMAX; extern sys_printdef syspdef_IFBLANES; extern sys_printdef syspdef_IFBSPEEDIN; extern sys_printdef syspdef_IFBSPEEDOUT; extern sys_printdef syspdef_BLANKBOX; /* ** functions that print ???? for unavailable data */ char *procprt_NOTAVAIL_4(struct tstat *curstat, int avgval, int nsecs); char *procprt_NOTAVAIL_5(struct tstat *curstat, int avgval, int nsecs); char *procprt_NOTAVAIL_6(struct tstat *curstat, int avgval, int nsecs); char *procprt_NOTAVAIL_7(struct tstat *curstat, int avgval, int nsecs); extern proc_printdef *allprocpdefs[]; extern proc_printdef procprt_PID; extern proc_printdef procprt_TID; extern proc_printdef procprt_PPID; extern proc_printdef procprt_SYSCPU; extern proc_printdef procprt_USRCPU; extern proc_printdef procprt_VGROW; extern proc_printdef procprt_RGROW; extern proc_printdef procprt_MINFLT; extern proc_printdef procprt_MAJFLT; extern proc_printdef procprt_VSTEXT; extern proc_printdef procprt_VSIZE; extern proc_printdef procprt_RSIZE; extern proc_printdef procprt_PSIZE; extern proc_printdef procprt_VSLIBS; extern proc_printdef procprt_VDATA; extern proc_printdef procprt_VSTACK; extern proc_printdef procprt_SWAPSZ; extern proc_printdef procprt_CMD; extern proc_printdef procprt_RUID; extern proc_printdef procprt_EUID; extern proc_printdef procprt_SUID; extern proc_printdef procprt_FSUID; extern proc_printdef procprt_RGID; extern proc_printdef procprt_EGID; extern proc_printdef procprt_SGID; extern proc_printdef procprt_FSGID; extern proc_printdef procprt_CTID; extern proc_printdef procprt_VPID; extern proc_printdef procprt_CID; extern proc_printdef procprt_STDATE; extern proc_printdef procprt_STTIME; extern proc_printdef procprt_ENDATE; extern proc_printdef procprt_ENTIME; extern proc_printdef procprt_THR; extern proc_printdef procprt_TRUN; extern proc_printdef procprt_TSLPI; extern proc_printdef procprt_TSLPU; extern proc_printdef procprt_POLI; extern proc_printdef procprt_NICE; extern proc_printdef procprt_PRI; extern proc_printdef procprt_RTPR; extern proc_printdef procprt_CURCPU; extern proc_printdef procprt_ST; extern proc_printdef procprt_EXC; extern proc_printdef procprt_S; extern proc_printdef procprt_COMMAND_LINE; extern proc_printdef procprt_NPROCS; extern proc_printdef procprt_RDDSK; extern proc_printdef procprt_WRDSK; extern proc_printdef procprt_CWRDSK; extern proc_printdef procprt_WCANCEL; extern proc_printdef procprt_TCPRCV; extern proc_printdef procprt_TCPRASZ; extern proc_printdef procprt_TCPSND; extern proc_printdef procprt_TCPSASZ; extern proc_printdef procprt_UDPRCV; extern proc_printdef procprt_UDPRASZ; extern proc_printdef procprt_UDPSND; extern proc_printdef procprt_UDPSASZ; extern proc_printdef procprt_RNET; extern proc_printdef procprt_SNET; extern proc_printdef procprt_BANDWI; extern proc_printdef procprt_BANDWO; extern proc_printdef procprt_GPULIST; extern proc_printdef procprt_GPUMEMNOW; extern proc_printdef procprt_GPUMEMAVG; extern proc_printdef procprt_GPUGPUBUSY; extern proc_printdef procprt_GPUMEMBUSY; extern proc_printdef procprt_SORTITEM; //extern char *procprt_NRDDSK_ae(struct tstat *, int, int); //extern char *procprt_NWRDSK_a(struct tstat *, int, int); //extern char *procprt_NRDDSK_e(struct tstat *, int, int); //extern char *procprt_NWRDSK_e(struct tstat *, int, int); extern char *procprt_SNET_a(struct tstat *, int, int); extern char *procprt_SNET_e(struct tstat *, int, int); extern char *procprt_RNET_a(struct tstat *, int, int); extern char *procprt_RNET_e(struct tstat *, int, int); extern char *procprt_TCPSND_a(struct tstat *, int, int); extern char *procprt_TCPRCV_a(struct tstat *, int, int); extern char *procprt_UDPSND_a(struct tstat *, int, int); extern char *procprt_UDPRCV_a(struct tstat *, int, int); extern char *procprt_TCPSASZ_a(struct tstat *, int, int); extern char *procprt_TCPRASZ_a(struct tstat *, int, int); extern char *procprt_UDPSASZ_a(struct tstat *, int, int); extern char *procprt_UDPRASZ_a(struct tstat *, int, int); extern char *procprt_TCPSND_e(struct tstat *, int, int); extern char *procprt_TCPRCV_e(struct tstat *, int, int); extern char *procprt_UDPSND_e(struct tstat *, int, int); extern char *procprt_UDPRCV_e(struct tstat *, int, int); extern char *procprt_TCPSASZ_e(struct tstat *, int, int); 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); atop-2.4.0/showprocs.c0000664000203100020310000014772513416466037014207 0ustar gerlofgerlof/* ** 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 the Linux-specific functions to calculate ** figures to be visualized. ** ========================================================================== ** Author: JC van Winkel - AT Computing, Nijmegen, Holland ** E-mail: jc@ATComputing.nl ** Date: November 2009 ** -------------------------------------------------------------------------- ** Copyright (C) 2009 JC van Winkel ** ** 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 ** -------------------------------------------------------------------------- ** ** $Log: showprocs.c,v $ ** Revision 1.15 2011/09/05 11:44:16 gerlof ** *** empty log message *** ** ** Revision 1.14 2010/12/01 09:05:38 gerlof ** Added a dash in the column PPID for exited processes. ** ** Revision 1.13 2010/11/12 06:11:58 gerlof ** Sometimes segmentation-fault on particular CPU-types ** due to memcpy i.s.o. memmove when moving memory in overlap. ** ** Revision 1.12 2010/04/23 14:06:42 gerlof ** Added special routined for uid/gid not available for exited processes. ** ** Revision 1.11 2010/01/16 12:54:08 gerlof ** Minor change for CPUNR. ** ** Revision 1.10 2010/01/16 11:37:25 gerlof ** Corrected counters for patched kernels (JC van Winkel). ** ** Revision 1.9 2010/01/08 13:44:47 gerlof ** Added policies batch, iso and idle for scheduling class. ** ** Revision 1.8 2010/01/08 11:25:13 gerlof ** Corrected column-width and priorities of network-stats. ** ** Revision 1.7 2010/01/03 18:26:53 gerlof ** Consistent naming of columns for process-related info. ** ** Revision 1.6 2009/12/19 21:03:21 gerlof ** Alignment of CMD column (JC van Winkel). ** ** Revision 1.5 2009/12/12 10:11:49 gerlof ** Register and display end date and end time for process. ** ** Revision 1.4 2009/12/12 09:05:56 gerlof ** Corrected cumulated disk I/O per user/program (JC van Winkel). ** ** Revision 1.3 2009/12/10 14:01:52 gerlof ** Add EUID, SUID and FSUID (and similar for GID's). ** ** Revision 1.2 2009/12/10 11:56:22 gerlof ** Various bug-solutions. ** ** Revision 1.1 2009/12/10 09:31:23 gerlof ** Initial revision ** ** Initial revision ** ** ** Initial ** */ static const char rcsid[] = "$Id: showprocs.c,v 1.15 2011/09/05 11:44:16 gerlof Exp $"; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "atop.h" #include "photoproc.h" #include "photosyst.h" #include "showgeneric.h" #include "showlinux.h" static void format_bandw(char *, count_t); static char *columnhead[] = { [MSORTCPU]= "CPU", [MSORTMEM]= "MEM", [MSORTDSK]= "DSK", [MSORTNET]= "NET", [MSORTGPU]= "GPU", }; /***************************************************************/ static int *colspacings; // ugly static var, // but saves a lot of recomputations // points to table with intercolumn // spacings static proc_printpair newelems[MAXITEMS]; // ugly static var, // but saves a lot of recomputations // contains the actual list of items to // be printed // // /***************************************************************/ /* * gettotwidth: calculate the sum of widths and number of columns * Also copys the printpair elements to the static array newelems * for later removal of lower priority elements. * Params: * elemptr: the array of what to print * nitems: (ref) returns the number of printitems in the array * 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 gettotwidth(proc_printpair* elemptr, int *nitems, int *sumwidth, int* varwidth) { int i; int col; int varw=0; for (i=0, col=0; elemptr[i].f!=0; ++i) { col += (elemptr[i].f->varwidth ? 0 : elemptr[i].f->width); varw += elemptr[i].f->varwidth; newelems[i]=elemptr[i]; // copy element } newelems[i].f=0; *nitems=i; *sumwidth=col; *varwidth=varw; } /***************************************************************/ /* * getspacings: determine how much extra space there is for * inter-column space. * returns an int array this number of spaces to add after each column * also removes items from the newelems array if the available width * is lower than what is needed. The lowest priority columns are * removed first. * * Note: this function is only to be called when screen is true. */ int * getspacings(proc_printpair* elemptr) { static int spacings[MAXITEMS]; int col=0; int nitems; int varwidth=0; int j; int maxw=screen ? COLS : linelen; // for non screen: 80 columns max // get width etc; copy elemptr array to static newelms gettotwidth(elemptr, &nitems, &col, &varwidth); /* cases: * 1) nitems==1: just one column, no spacing needed. Done * * 2) total width is more than COLS: remove low prio columns * 2a) a varwidth column: no spacing needed * 2b) total width is less than COLS: compute inter spacing */ if (nitems==1) // no inter column spacing if 1 column { spacings[0]=0; return spacings; } // Check if available width is less than required. // If so, delete columns to make things fit // space required: // width + (nitems-1) * 1 space + 12 for a varwidth column. while (col + nitems-1+ 12*varwidth > maxw) { int lowestprio=999999; int lowestprio_index=-1; int i; for (i=0; iwidth; varwidth -= newelems[lowestprio_index].f->varwidth; memmove(newelems+lowestprio_index, newelems+lowestprio_index+1, (nitems-lowestprio_index)* sizeof(proc_printpair)); // also copies final 0 entry nitems--; } /* if there is a var width column, handle that separately */ if (varwidth) { for (j=0; jvarwidth) { elemptr[j].f->width=maxw-col-(nitems-1); // only nitems-1 in-between spaces // needed } } return spacings; } /* fixed columns, spread whitespace over columns */ double over=(0.0+maxw-col)/(nitems-1); double todo=over; for (j=0; jhead==0) // empty header==special: SORTITEM { chead=columnhead[order]; autoindic= autosort ? "A" : " "; } else { chead=curelem.f->head; autoindic=""; } if (screen) { col += sprintf(buf+col, "%s%s%*s", autoindic, chead, colspacings[n], ""); } else { col += sprintf(buf+col, "%s%s ", autoindic, chead); } elemptr++; n++; } if (screen) // add page number, eat from last header if needed... { pagindiclen=sprintf(pagindic,"%d/%d", curlist, totlist); allign=COLS-col-pagindiclen; // extra spaces needed if (allign >= 0) // allign by adding spaces { sprintf(buf+col, "%*s", allign+pagindiclen, pagindic); } else { // allign by removing from the right sprintf(buf+col+allign, "%s", pagindic); } } printg("%s", buf); if (!screen) { printg("\n"); } } /***************************************************************/ /* * showprocline: show line for processes. * if in interactive mode, columns are aligned to fill out rows * params: * elemptr: pointer to array of print definition structs ptrs * curstat: the process to print * perc: the sort order used * nsecs: number of seconds elapsed between previous and this sample * avgval: is averaging out per second needed? */ void showprocline(proc_printpair* elemptr, struct tstat *curstat, double perc, int nsecs, int avgval) { proc_printpair curelem; elemptr=newelems; // point to static array int n=0; if (screen && threadview) { if (usecolors && !curstat->gen.isproc) { attron(COLOR_PAIR(COLORTHR)); } else { if (!usecolors && curstat->gen.isproc) attron(A_BOLD); } } while ((curelem=*elemptr).f!=0) { // what to print? SORTITEM, or active process or // exited process? if (curelem.f->head==0) // empty string=sortitem { printg("%3.0lf%%", perc); // cannot pass perc } else if (curstat->gen.state != 'E') // active process { printg("%s", curelem.f->doactiveconvert(curstat, avgval, nsecs)); } else // exited process { printg("%s", curelem.f->doexitconvert(curstat, avgval, nsecs)); } if (screen) { printg("%*s",colspacings[n], ""); } else { printg(" "); } elemptr++; n++; } if (screen && threadview) { if (usecolors && !curstat->gen.isproc) { attroff(COLOR_PAIR(COLORTHR)); } else { if (!usecolors && curstat->gen.isproc) attroff(A_BOLD); } } if (!screen) { printg("\n"); } } /*******************************************************************/ /* PROCESS PRINT FUNCTIONS */ /***************************************************************/ char * procprt_NOTAVAIL_4(struct tstat *curstat, int avgval, int nsecs) { return " ?"; } char * procprt_NOTAVAIL_5(struct tstat *curstat, int avgval, int nsecs) { return " ?"; } char * procprt_NOTAVAIL_6(struct tstat *curstat, int avgval, int nsecs) { return " ?"; } char * procprt_NOTAVAIL_7(struct tstat *curstat, int avgval, int nsecs) { return " ?"; } /***************************************************************/ char * procprt_TID_ae(struct tstat *curstat, int avgval, int nsecs) { static char buf[64]; if (curstat->gen.isproc) sprintf(buf, "%*s", procprt_TID.width, "-"); else sprintf(buf, "%*d", procprt_TID.width, curstat->gen.pid); return buf; } proc_printdef procprt_TID = { "TID", "TID", procprt_TID_ae, procprt_TID_ae, 5}; //DYNAMIC WIDTH! /***************************************************************/ char * procprt_PID_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[64]; sprintf(buf, "%*d", procprt_PID.width, curstat->gen.tgid); return buf; } char * procprt_PID_e(struct tstat *curstat, int avgval, int nsecs) { static char buf[64]; if (curstat->gen.pid == 0) sprintf(buf, "%*s", procprt_PID.width, "?"); else sprintf(buf, "%*d", procprt_PID.width, curstat->gen.tgid); return buf; } proc_printdef procprt_PID = { "PID", "PID", procprt_PID_a, procprt_PID_e, 5}; //DYNAMIC WIDTH! /***************************************************************/ char * procprt_PPID_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[64]; sprintf(buf, "%*d", procprt_PPID.width, curstat->gen.ppid); return buf; } char * procprt_PPID_e(struct tstat *curstat, int avgval, int nsecs) { static char buf[64]; sprintf(buf, "%*s", procprt_PPID.width, "-"); return buf; } proc_printdef procprt_PPID = { "PPID", "PPID", procprt_PPID_a, procprt_PPID_e, 5 }; //DYNAMIC WIDTH! /***************************************************************/ char * procprt_VPID_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[64]; sprintf(buf, "%*d", procprt_VPID.width, curstat->gen.vpid); return buf; } char * procprt_VPID_e(struct tstat *curstat, int avgval, int nsecs) { static char buf[64]; sprintf(buf, "%*s", procprt_VPID.width, "-"); return buf; } proc_printdef procprt_VPID = { "VPID", "VPID", procprt_VPID_a, procprt_VPID_e, 5 }; //DYNAMIC WIDTH! /***************************************************************/ char * procprt_CTID_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[32]; sprintf(buf, "%5d", curstat->gen.ctid); return buf; } char * procprt_CTID_e(struct tstat *curstat, int avgval, int nsecs) { return " -"; } proc_printdef procprt_CTID = { " CTID", "CTID", procprt_CTID_a, procprt_CTID_e, 5 }; /***************************************************************/ char * procprt_CID_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[64]; if (curstat->gen.container[0]) sprintf(buf, "%-12s", curstat->gen.container); else sprintf(buf, "%-12s", "host--------"); return buf; } char * procprt_CID_e(struct tstat *curstat, int avgval, int nsecs) { static char buf[64]; if (curstat->gen.container[0]) sprintf(buf, "%-12s", curstat->gen.container); else sprintf(buf, "%-12s", "?"); return buf; } proc_printdef procprt_CID = { "CID ", "CID", procprt_CID_a, procprt_CID_e, 12}; /***************************************************************/ char * procprt_SYSCPU_ae(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2cpustr(curstat->cpu.stime*1000/hertz, buf); return buf; } proc_printdef procprt_SYSCPU = { "SYSCPU", "SYSCPU", procprt_SYSCPU_ae, procprt_SYSCPU_ae, 6 }; /***************************************************************/ char * procprt_USRCPU_ae(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2cpustr(curstat->cpu.utime*1000/hertz, buf); return buf; } proc_printdef procprt_USRCPU = { "USRCPU", "USRCPU", procprt_USRCPU_ae, procprt_USRCPU_ae, 6 }; /***************************************************************/ char * procprt_VGROW_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2memstr(curstat->mem.vgrow*1024, buf, KBFORMAT, 0, 0); return buf; } char * procprt_VGROW_e(struct tstat *curstat, int avgval, int nsecs) { return " 0K"; } proc_printdef procprt_VGROW = { " VGROW", "VGROW", procprt_VGROW_a, procprt_VGROW_e, 6 }; /***************************************************************/ char * procprt_RGROW_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2memstr(curstat->mem.rgrow*1024, buf, KBFORMAT, 0, 0); return buf; } char * procprt_RGROW_e(struct tstat *curstat, int avgval, int nsecs) { return " 0K"; } proc_printdef procprt_RGROW = { " RGROW", "RGROW", procprt_RGROW_a, procprt_RGROW_e, 6 }; /***************************************************************/ char * procprt_MINFLT_ae(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2valstr(curstat->mem.minflt, buf, 6, avgval, nsecs); return buf; } proc_printdef procprt_MINFLT = { "MINFLT", "MINFLT", procprt_MINFLT_ae, procprt_MINFLT_ae, 6 }; /***************************************************************/ char * procprt_MAJFLT_ae(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2valstr(curstat->mem.majflt, buf, 6, avgval, nsecs); return buf; } proc_printdef procprt_MAJFLT = { "MAJFLT", "MAJFLT", procprt_MAJFLT_ae, procprt_MAJFLT_ae, 6 }; /***************************************************************/ char * procprt_VSTEXT_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2memstr(curstat->mem.vexec*1024, buf, KBFORMAT, 0, 0); return buf; } char * procprt_VSTEXT_e(struct tstat *curstat, int avgval, int nsecs) { return " 0K"; } proc_printdef procprt_VSTEXT = { "VSTEXT", "VSTEXT", procprt_VSTEXT_a, procprt_VSTEXT_e, 6 }; /***************************************************************/ char * procprt_VSIZE_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2memstr(curstat->mem.vmem*1024, buf, KBFORMAT, 0, 0); return buf; } char * procprt_VSIZE_e(struct tstat *curstat, int avgval, int nsecs) { return " 0K"; } proc_printdef procprt_VSIZE = { " VSIZE", "VSIZE", procprt_VSIZE_a, procprt_VSIZE_e, 6 }; /***************************************************************/ char * procprt_RSIZE_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2memstr(curstat->mem.rmem*1024, buf, KBFORMAT, 0, 0); return buf; } char * procprt_RSIZE_e(struct tstat *curstat, int avgval, int nsecs) { return " 0K"; } proc_printdef procprt_RSIZE = { " RSIZE", "RSIZE", procprt_RSIZE_a, procprt_RSIZE_e, 6 }; /***************************************************************/ char * procprt_PSIZE_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; if (curstat->mem.pmem == (unsigned long long)-1LL) return " ?K"; val2memstr(curstat->mem.pmem*1024, buf, KBFORMAT, 0, 0); return buf; } char * procprt_PSIZE_e(struct tstat *curstat, int avgval, int nsecs) { return " 0K"; } proc_printdef procprt_PSIZE = { " PSIZE", "PSIZE", procprt_PSIZE_a, procprt_PSIZE_e, 6 }; /***************************************************************/ char * procprt_VSLIBS_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2memstr(curstat->mem.vlibs*1024, buf, KBFORMAT, 0, 0); return buf; } char * procprt_VSLIBS_e(struct tstat *curstat, int avgval, int nsecs) { return " 0K"; } proc_printdef procprt_VSLIBS = { "VSLIBS", "VSLIBS", procprt_VSLIBS_a, procprt_VSLIBS_e, 6 }; /***************************************************************/ char * procprt_VDATA_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2memstr(curstat->mem.vdata*1024, buf, KBFORMAT, 0, 0); return buf; } char * procprt_VDATA_e(struct tstat *curstat, int avgval, int nsecs) { return " 0K"; } proc_printdef procprt_VDATA = { " VDATA", "VDATA", procprt_VDATA_a, procprt_VDATA_e, 6 }; /***************************************************************/ char * procprt_VSTACK_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2memstr(curstat->mem.vstack*1024, buf, KBFORMAT, 0, 0); return buf; } char * procprt_VSTACK_e(struct tstat *curstat, int avgval, int nsecs) { return " 0K"; } proc_printdef procprt_VSTACK = { "VSTACK", "VSTACK", procprt_VSTACK_a, procprt_VSTACK_e, 6 }; /***************************************************************/ char * procprt_SWAPSZ_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2memstr(curstat->mem.vswap*1024, buf, KBFORMAT, 0, 0); return buf; } char * procprt_SWAPSZ_e(struct tstat *curstat, int avgval, int nsecs) { return " 0K"; } proc_printdef procprt_SWAPSZ = { "SWAPSZ", "SWAPSZ", procprt_SWAPSZ_a, procprt_SWAPSZ_e, 6 }; /***************************************************************/ char * procprt_CMD_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[15]; sprintf(buf, "%-14.14s", curstat->gen.name); return buf; } char * procprt_CMD_e(struct tstat *curstat, int avgval, int nsecs) { static char buf[15]="<"; char helpbuf[15]; sprintf(helpbuf, "<%.12s>", curstat->gen.name); sprintf(buf, "%-14.14s", helpbuf); return buf; } proc_printdef procprt_CMD = { "CMD ", "CMD", procprt_CMD_a, procprt_CMD_e, 14 }; /***************************************************************/ char * procprt_RUID_ae(struct tstat *curstat, int avgval, int nsecs) { static char buf[9]; struct passwd *pwd; if ( (pwd = getpwuid(curstat->gen.ruid)) ) { sprintf(buf, "%-8.8s", pwd->pw_name); } else { snprintf(buf, sizeof buf, "%-8d", curstat->gen.ruid); } return buf; } proc_printdef procprt_RUID = { "RUID ", "RUID", procprt_RUID_ae, procprt_RUID_ae, 8 }; /***************************************************************/ char * procprt_EUID_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[9]; struct passwd *pwd; if ( (pwd = getpwuid(curstat->gen.euid)) ) { sprintf(buf, "%-8.8s", pwd->pw_name); } else { snprintf(buf, sizeof buf, "%-8d", curstat->gen.euid); } return buf; } char * procprt_EUID_e(struct tstat *curstat, int avgval, int nsecs) { return "- "; } proc_printdef procprt_EUID = { "EUID ", "EUID", procprt_EUID_a, procprt_EUID_e, 8 }; /***************************************************************/ char * procprt_SUID_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[9]; struct passwd *pwd; if ( (pwd = getpwuid(curstat->gen.suid)) ) { sprintf(buf, "%-8.8s", pwd->pw_name); } else { snprintf(buf, sizeof buf, "%-8d", curstat->gen.suid); } return buf; } char * procprt_SUID_e(struct tstat *curstat, int avgval, int nsecs) { return "- "; } proc_printdef procprt_SUID = { "SUID ", "SUID", procprt_SUID_a, procprt_SUID_e, 8 }; /***************************************************************/ char * procprt_FSUID_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[9]; struct passwd *pwd; if ( (pwd = getpwuid(curstat->gen.fsuid)) ) { sprintf(buf, "%-8.8s", pwd->pw_name); } else { snprintf(buf, sizeof buf, "%-8d", curstat->gen.fsuid); } return buf; } char * procprt_FSUID_e(struct tstat *curstat, int avgval, int nsecs) { return "- "; } proc_printdef procprt_FSUID = { "FSUID ", "FSUID", procprt_FSUID_a, procprt_FSUID_e, 8 }; /***************************************************************/ char * procprt_RGID_ae(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; struct group *grp; char *groupname; char grname[16]; if ( (grp = getgrgid(curstat->gen.rgid)) ) { groupname = grp->gr_name; } else { snprintf(grname, sizeof grname, "%d",curstat->gen.rgid); groupname = grname; } sprintf(buf, "%-8.8s", groupname); return buf; } proc_printdef procprt_RGID = { "RGID ", "RGID", procprt_RGID_ae, procprt_RGID_ae, 8 }; /***************************************************************/ char * procprt_EGID_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; struct group *grp; char *groupname; char grname[16]; if ( (grp = getgrgid(curstat->gen.egid)) ) { groupname = grp->gr_name; } else { snprintf(grname, sizeof grname, "%d",curstat->gen.egid); groupname = grname; } sprintf(buf, "%-8.8s", groupname); return buf; } char * procprt_EGID_e(struct tstat *curstat, int avgval, int nsecs) { return "- "; } proc_printdef procprt_EGID = { "EGID ", "EGID", procprt_EGID_a, procprt_EGID_e, 8 }; /***************************************************************/ char * procprt_SGID_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; struct group *grp; char *groupname; char grname[16]; if ( (grp = getgrgid(curstat->gen.sgid)) ) { groupname = grp->gr_name; } else { snprintf(grname, sizeof grname, "%d",curstat->gen.sgid); groupname = grname; } sprintf(buf, "%-8.8s", groupname); return buf; } char * procprt_SGID_e(struct tstat *curstat, int avgval, int nsecs) { return "- "; } proc_printdef procprt_SGID = { "SGID ", "SGID", procprt_SGID_a, procprt_SGID_e, 8 }; /***************************************************************/ char * procprt_FSGID_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; struct group *grp; char *groupname; char grname[16]; if ( (grp = getgrgid(curstat->gen.fsgid)) ) { groupname = grp->gr_name; } else { snprintf(grname, sizeof grname,"%d",curstat->gen.fsgid); groupname = grname; } sprintf(buf, "%-8.8s", groupname); return buf; } char * procprt_FSGID_e(struct tstat *curstat, int avgval, int nsecs) { return "- "; } proc_printdef procprt_FSGID = { "FSGID ", "FSGID", procprt_FSGID_a, procprt_FSGID_e, 8 }; /***************************************************************/ char * procprt_STDATE_ae(struct tstat *curstat, int avgval, int nsecs) { static char buf[11]; convdate(curstat->gen.btime, buf); return buf; } proc_printdef procprt_STDATE = { " STDATE ", "STDATE", procprt_STDATE_ae, procprt_STDATE_ae, 10 }; /***************************************************************/ char * procprt_STTIME_ae(struct tstat *curstat, int avgval, int nsecs) { static char buf[9]; convtime(curstat->gen.btime, buf); return buf; } proc_printdef procprt_STTIME = { " STTIME ", "STTIME", procprt_STTIME_ae, procprt_STTIME_ae, 8 }; /***************************************************************/ char * procprt_ENDATE_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[11]; strcpy(buf, " active "); return buf; } char * procprt_ENDATE_e(struct tstat *curstat, int avgval, int nsecs) { static char buf[11]; convdate(curstat->gen.btime + curstat->gen.elaps/hertz, buf); return buf; } proc_printdef procprt_ENDATE = { " ENDATE ", "ENDATE", procprt_ENDATE_a, procprt_ENDATE_e, 10 }; /***************************************************************/ char * procprt_ENTIME_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[9]; strcpy(buf, " active "); return buf; } char * procprt_ENTIME_e(struct tstat *curstat, int avgval, int nsecs) { static char buf[9]; convtime(curstat->gen.btime + curstat->gen.elaps/hertz, buf); return buf; } proc_printdef procprt_ENTIME = { " ENTIME ", "ENTIME", procprt_ENTIME_a, procprt_ENTIME_e, 8 }; /***************************************************************/ char * procprt_THR_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[15]; sprintf(buf, "%4d", curstat->gen.nthr); return buf; } char * procprt_THR_e(struct tstat *curstat, int avgval, int nsecs) { return " 0"; } proc_printdef procprt_THR = { " THR", "THR", procprt_THR_a, procprt_THR_e, 4 }; /***************************************************************/ char * procprt_TRUN_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[15]; sprintf(buf, "%4d", curstat->gen.nthrrun); return buf; } char * procprt_TRUN_e(struct tstat *curstat, int avgval, int nsecs) { return " 0"; } proc_printdef procprt_TRUN = { "TRUN", "TRUN", procprt_TRUN_a, procprt_TRUN_e, 4 }; /***************************************************************/ char * procprt_TSLPI_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[15]; sprintf(buf, "%5d", curstat->gen.nthrslpi); return buf; } char * procprt_TSLPI_e(struct tstat *curstat, int avgval, int nsecs) { return " 0"; } proc_printdef procprt_TSLPI = { "TSLPI", "TSLPI", procprt_TSLPI_a, procprt_TSLPI_e, 5 }; /***************************************************************/ char * procprt_TSLPU_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[15]; sprintf(buf, "%5d", curstat->gen.nthrslpu); return buf; } char * procprt_TSLPU_e(struct tstat *curstat, int avgval, int nsecs) { return " 0"; } proc_printdef procprt_TSLPU = { "TSLPU", "TSLPU", procprt_TSLPU_a, procprt_TSLPU_e, 5 }; /***************************************************************/ #define SCHED_NORMAL 0 #define SCHED_FIFO 1 #define SCHED_RR 2 #define SCHED_BATCH 3 #define SCHED_ISO 4 #define SCHED_IDLE 5 #define SCHED_DEADLINE 6 char * procprt_POLI_a(struct tstat *curstat, int avgval, int nsecs) { switch (curstat->cpu.policy) { case SCHED_NORMAL: return "norm"; break; case SCHED_FIFO: return "fifo"; break; case SCHED_RR: return "rr "; break; case SCHED_BATCH: return "btch"; break; case SCHED_ISO: return "iso "; break; case SCHED_IDLE: return "idle"; break; case SCHED_DEADLINE: return "dead"; break; } return "? "; } char * procprt_POLI_e(struct tstat *curstat, int avgval, int nsecs) { return "- "; } proc_printdef procprt_POLI = { "POLI", "POLI", procprt_POLI_a, procprt_POLI_e, 4 }; /***************************************************************/ char * procprt_NICE_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[15]; sprintf(buf, "%4d", curstat->cpu.nice); return buf; } char * procprt_NICE_e(struct tstat *curstat, int avgval, int nsecs) { return " -"; } proc_printdef procprt_NICE = { "NICE", "NICE", procprt_NICE_a, procprt_NICE_e, 4 }; /***************************************************************/ char * procprt_PRI_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[15]; sprintf(buf, "%3d", curstat->cpu.prio); return buf; } char * procprt_PRI_e(struct tstat *curstat, int avgval, int nsecs) { return " -"; } proc_printdef procprt_PRI = { "PRI", "PRI", procprt_PRI_a, procprt_PRI_e, 3 }; /***************************************************************/ char * procprt_RTPR_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[15]; sprintf(buf, "%4d", curstat->cpu.rtprio); return buf; } char * procprt_RTPR_e(struct tstat *curstat, int avgval, int nsecs) { return " -"; } proc_printdef procprt_RTPR = { "RTPR", "RTPR", procprt_RTPR_a, procprt_RTPR_e, 4 }; /***************************************************************/ char * procprt_CURCPU_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[15]; sprintf(buf, "%5d", curstat->cpu.curcpu); return buf; } char * procprt_CURCPU_e(struct tstat *curstat, int avgval, int nsecs) { return " -"; } proc_printdef procprt_CURCPU = { "CPUNR", "CPUNR", procprt_CURCPU_a, procprt_CURCPU_e, 5 }; /***************************************************************/ char * procprt_ST_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[3]="--"; if (curstat->gen.excode & ~(INT_MAX)) { buf[0]='N'; } else { buf[0]='-'; } return buf; } char * procprt_ST_e(struct tstat *curstat, int avgval, int nsecs) { static char buf[3]; if (curstat->gen.excode & ~(INT_MAX)) { buf[0]='N'; } else { buf[0]='-'; } if (curstat->gen.excode & 0xff) { if (curstat->gen.excode & 0x80) buf[1] = 'C'; else buf[1] = 'S'; } else { buf[1] = 'E'; } return buf; } proc_printdef procprt_ST = { "ST", "ST", procprt_ST_a, procprt_ST_e, 2 }; /***************************************************************/ char * procprt_EXC_a(struct tstat *curstat, int avgval, int nsecs) { return " -"; } char * procprt_EXC_e(struct tstat *curstat, int avgval, int nsecs) { static char buf[4]; sprintf(buf, "%3d", curstat->gen.excode & 0xff ? curstat->gen.excode & 0x7f : (curstat->gen.excode>>8) & 0xff); return buf; } proc_printdef procprt_EXC = { "EXC", "EXC", procprt_EXC_a, procprt_EXC_e, 3 }; /***************************************************************/ char * procprt_S_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[2]="E"; buf[0]=curstat->gen.state; return buf; } char * procprt_S_e(struct tstat *curstat, int avgval, int nsecs) { return "E"; } proc_printdef procprt_S = { "S", "S", procprt_S_a, procprt_S_e, 1 }; /***************************************************************/ char * procprt_COMMAND_LINE_ae(struct tstat *curstat, int avgval, int nsecs) { extern proc_printdef procprt_COMMAND_LINE; extern int startoffset; // influenced by -> and <- keys static char buf[CMDLEN+1]; char *pline = curstat->gen.cmdline[0] ? curstat->gen.cmdline : curstat->gen.name; int curwidth = procprt_COMMAND_LINE.width <= CMDLEN ? procprt_COMMAND_LINE.width : CMDLEN; int cmdlen = strlen(pline); int curoffset = startoffset <= cmdlen ? startoffset : cmdlen; if (screen) sprintf(buf, "%-*.*s", curwidth, curwidth, pline+curoffset); else sprintf(buf, "%.*s", CMDLEN, pline+curoffset); return buf; } proc_printdef procprt_COMMAND_LINE = { "COMMAND-LINE (horizontal scroll with <- and -> keys)", "COMMAND-LINE", procprt_COMMAND_LINE_ae, procprt_COMMAND_LINE_ae, 0, 1 }; /***************************************************************/ char * procprt_NPROCS_ae(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2valstr(curstat->gen.pid, buf, 6, 0, 0); // pid abused as proc counter return buf; } proc_printdef procprt_NPROCS = { "NPROCS", "NPROCS", procprt_NPROCS_ae, procprt_NPROCS_ae, 6 }; /***************************************************************/ char * procprt_RDDSK_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2memstr(curstat->dsk.rsz*512, buf, KBFORMAT, avgval, nsecs); return buf; } char * procprt_RDDSK_e(struct tstat *curstat, int avgval, int nsecs) { return " -"; } proc_printdef procprt_RDDSK = { " RDDSK", "RDDSK", procprt_RDDSK_a, procprt_RDDSK_e, 6 }; /***************************************************************/ char * procprt_WRDSK_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2memstr(curstat->dsk.wsz*512, buf, KBFORMAT, avgval, nsecs); return buf; } char * procprt_WRDSK_e(struct tstat *curstat, int avgval, int nsecs) { return " -"; } proc_printdef procprt_WRDSK = { " WRDSK", "WRDSK", procprt_WRDSK_a, procprt_WRDSK_e, 6 }; /***************************************************************/ char * procprt_CWRDSK_a(struct tstat *curstat, int avgval, int nsecs) { count_t nett_wsz; static char buf[10]; if (curstat->dsk.wsz > curstat->dsk.cwsz) nett_wsz = curstat->dsk.wsz - curstat->dsk.cwsz; else nett_wsz = 0; val2memstr(nett_wsz*512, buf, KBFORMAT, avgval, nsecs); return buf; } proc_printdef procprt_CWRDSK = {" WRDSK", "CWRDSK", procprt_CWRDSK_a, procprt_WRDSK_e, 6 }; /***************************************************************/ char * procprt_WCANCEL_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2memstr(curstat->dsk.cwsz*512, buf, KBFORMAT, avgval, nsecs); return buf; } char * procprt_WCANCEL_e(struct tstat *curstat, int avgval, int nsecs) { return " -"; } proc_printdef procprt_WCANCEL = {"WCANCL", "WCANCL", procprt_WCANCEL_a, procprt_WCANCEL_e, 6}; /***************************************************************/ char * procprt_TCPRCV_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2valstr(curstat->net.tcprcv, buf, 6, avgval, nsecs); return buf; } char * procprt_TCPRCV_e(struct tstat *curstat, int avgval, int nsecs) { if (supportflags & NETATOPD) { static char buf[10]; val2valstr(curstat->net.tcprcv, buf, 6, avgval, nsecs); return buf; } else return " -"; } proc_printdef procprt_TCPRCV = { "TCPRCV", "TCPRCV", procprt_TCPRCV_a, procprt_TCPRCV_e, 6 }; /***************************************************************/ char * procprt_TCPRASZ_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; int avgtcpr = curstat->net.tcprcv ? curstat->net.tcprsz / curstat->net.tcprcv : 0; val2valstr(avgtcpr, buf, 7, 0, 0); return buf; } char * procprt_TCPRASZ_e(struct tstat *curstat, int avgval, int nsecs) { if (supportflags & NETATOPD) { static char buf[10]; int avgtcpr = curstat->net.tcprcv ? curstat->net.tcprsz / curstat->net.tcprcv : 0; val2valstr(avgtcpr, buf, 7, 0, 0); return buf; } else return " -"; } proc_printdef procprt_TCPRASZ = { "TCPRASZ", "TCPRASZ", procprt_TCPRASZ_a, procprt_TCPRASZ_e, 7 }; /***************************************************************/ char * procprt_TCPSND_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2valstr(curstat->net.tcpsnd, buf, 6, avgval, nsecs); return buf; } char * procprt_TCPSND_e(struct tstat *curstat, int avgval, int nsecs) { if (supportflags & NETATOPD) { static char buf[10]; val2valstr(curstat->net.tcpsnd, buf, 6, avgval, nsecs); return buf; } else return " -"; } proc_printdef procprt_TCPSND = { "TCPSND", "TCPSND", procprt_TCPSND_a, procprt_TCPSND_e, 6 }; /***************************************************************/ char * procprt_TCPSASZ_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; int avgtcps = curstat->net.tcpsnd ? curstat->net.tcpssz / curstat->net.tcpsnd : 0; val2valstr(avgtcps, buf, 7, 0, 0); return buf; } char * procprt_TCPSASZ_e(struct tstat *curstat, int avgval, int nsecs) { if (supportflags & NETATOPD) { static char buf[10]; int avgtcps = curstat->net.tcpsnd ? curstat->net.tcpssz / curstat->net.tcpsnd : 0; val2valstr(avgtcps, buf, 7, 0, 0); return buf; } else return " -"; } proc_printdef procprt_TCPSASZ = { "TCPSASZ", "TCPSASZ", procprt_TCPSASZ_a, procprt_TCPSASZ_e, 7 }; /***************************************************************/ char * procprt_UDPRCV_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2valstr(curstat->net.udprcv, buf, 6, avgval, nsecs); return buf; } char * procprt_UDPRCV_e(struct tstat *curstat, int avgval, int nsecs) { if (supportflags & NETATOPD) { static char buf[10]; val2valstr(curstat->net.udprcv, buf, 6, avgval, nsecs); return buf; } else return " -"; } proc_printdef procprt_UDPRCV = { "UDPRCV", "UDPRCV", procprt_UDPRCV_a, procprt_UDPRCV_e, 6 }; /***************************************************************/ char * procprt_UDPRASZ_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; int avgudpr = curstat->net.udprcv ? curstat->net.udprsz / curstat->net.udprcv : 0; val2valstr(avgudpr, buf, 7, 0, 0); return buf; } char * procprt_UDPRASZ_e(struct tstat *curstat, int avgval, int nsecs) { if (supportflags & NETATOPD) { static char buf[10]; int avgudpr = curstat->net.udprcv ? curstat->net.udprsz / curstat->net.udprcv : 0; val2valstr(avgudpr, buf, 7, 0, 0); return buf; } else return " -"; } proc_printdef procprt_UDPRASZ = { "UDPRASZ", "UDPRASZ", procprt_UDPRASZ_a, procprt_UDPRASZ_e, 7 }; /***************************************************************/ char * procprt_UDPSND_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2valstr(curstat->net.udpsnd, buf, 6, avgval, nsecs); return buf; } char * procprt_UDPSND_e(struct tstat *curstat, int avgval, int nsecs) { if (supportflags & NETATOPD) { static char buf[10]; val2valstr(curstat->net.udpsnd, buf, 6, avgval, nsecs); return buf; } else return " -"; } proc_printdef procprt_UDPSND = { "UDPSND", "UDPSND", procprt_UDPSND_a, procprt_UDPSND_e, 6 }; /***************************************************************/ char * procprt_UDPSASZ_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; int avgudps = curstat->net.udpsnd ? curstat->net.udpssz / curstat->net.udpsnd : 0; val2valstr(avgudps, buf, 7, 0, 0); return buf; } char * procprt_UDPSASZ_e(struct tstat *curstat, int avgval, int nsecs) { if (supportflags & NETATOPD) { static char buf[10]; int avgudps = curstat->net.udpsnd ? curstat->net.udpssz / curstat->net.udpsnd : 0; val2valstr(avgudps, buf, 7, 0, 0); return buf; } else return " -"; } proc_printdef procprt_UDPSASZ = { "UDPSASZ", "UDPSASZ", procprt_UDPSASZ_a, procprt_UDPSASZ_e, 7 }; /***************************************************************/ char * procprt_RNET_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2valstr(curstat->net.tcprcv + curstat->net.udprcv , buf, 5, avgval, nsecs); return buf; } char * procprt_RNET_e(struct tstat *curstat, int avgval, int nsecs) { if (supportflags & NETATOPD) { static char buf[10]; val2valstr(curstat->net.tcprcv + curstat->net.udprcv , buf, 5, avgval, nsecs); return buf; } else return " -"; } proc_printdef procprt_RNET = { " RNET", "RNET", procprt_RNET_a, procprt_RNET_e, 5 }; /***************************************************************/ char * procprt_SNET_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; val2valstr(curstat->net.tcpsnd + curstat->net.udpsnd, buf, 5, avgval, nsecs); return buf; } char * procprt_SNET_e(struct tstat *curstat, int avgval, int nsecs) { if (supportflags & NETATOPD) { static char buf[10]; val2valstr(curstat->net.tcpsnd + curstat->net.udpsnd, buf, 5, avgval, nsecs); return buf; } else return " -"; } proc_printdef procprt_SNET = { " SNET", "SNET", procprt_SNET_a, procprt_SNET_e, 5 }; /***************************************************************/ char * procprt_BANDWI_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[16]; count_t rkbps = (curstat->net.tcprsz+curstat->net.udprsz)/125/nsecs; format_bandw(buf, rkbps); return buf; } char * procprt_BANDWI_e(struct tstat *curstat, int avgval, int nsecs) { if (supportflags & NETATOPD) { static char buf[16]; count_t rkbps = (curstat->net.tcprsz + curstat->net.udprsz) /125/nsecs; format_bandw(buf, rkbps); return buf; } else return " -"; } proc_printdef procprt_BANDWI = { " BANDWI", "BANDWI", procprt_BANDWI_a, procprt_BANDWI_e, 9}; /***************************************************************/ char * procprt_BANDWO_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[16]; count_t skbps = (curstat->net.tcpssz+curstat->net.udpssz)/125/nsecs; format_bandw(buf, skbps); return buf; } char * procprt_BANDWO_e(struct tstat *curstat, int avgval, int nsecs) { if (supportflags & NETATOPD) { static char buf[16]; count_t skbps = (curstat->net.tcpssz + curstat->net.udpssz) /125/nsecs; format_bandw(buf, skbps); return buf; } else return " -"; } proc_printdef procprt_BANDWO = { " BANDWO", "BANDWO", procprt_BANDWO_a, procprt_BANDWO_e, 9}; /***************************************************************/ static void format_bandw(char *buf, count_t kbps) { char c; if (kbps < 10000) { c='K'; } else if (kbps < (count_t)10000 * 1000) { kbps/=1000; c = 'M'; } else if (kbps < (count_t)10000 * 1000 * 1000) { kbps/=1000 * 1000; c = 'G'; } else { kbps = kbps / 1000 / 1000 / 1000; c = 'T'; } sprintf(buf, "%4lld %cbps", kbps, c); } /***************************************************************/ char * procprt_GPULIST_ae(struct tstat *curstat, int avgval, int nsecs) { static char buf[64]; char tmp[64], *p=tmp; int i; if (!curstat->gpu.state) return " -"; if (!curstat->gpu.gpulist) return " -"; for (i=0; i < nrgpus; i++) { if (curstat->gpu.gpulist & 1< 8) { snprintf(tmp, sizeof tmp, "0x%06x", curstat->gpu.gpulist); break; } } } snprintf(buf, sizeof buf, "%8.8s", tmp); return buf; } proc_printdef procprt_GPULIST = { " GPUNUMS", "GPULIST", procprt_GPULIST_ae, procprt_GPULIST_ae, 8}; /***************************************************************/ char * procprt_GPUMEMNOW_ae(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; if (!curstat->gpu.state) return " -"; val2memstr(curstat->gpu.memnow*1024, buf, KBFORMAT, 0, 0); return buf; } proc_printdef procprt_GPUMEMNOW = { "MEMNOW", "GPUMEM", procprt_GPUMEMNOW_ae, procprt_GPUMEMNOW_ae, 6}; /***************************************************************/ char * procprt_GPUMEMAVG_ae(struct tstat *curstat, int avgval, int nsecs) { static char buf[10]; if (!curstat->gpu.state) return " -"; if (curstat->gpu.sample == 0) return(" 0K"); val2memstr(curstat->gpu.nrgpus * curstat->gpu.memcum / curstat->gpu.sample*1024, buf, KBFORMAT, 0, 0); return buf; } proc_printdef procprt_GPUMEMAVG = { "MEMAVG", "GPUMEMAVG", procprt_GPUMEMAVG_ae, procprt_GPUMEMAVG_ae, 6}; /***************************************************************/ char * procprt_GPUGPUBUSY_ae(struct tstat *curstat, int avgval, int nsecs) { static char buf[16]; if (!curstat->gpu.state) return " -"; if (curstat->gpu.gpubusy == -1) return " N/A"; snprintf(buf, sizeof buf, "%6d%%", curstat->gpu.gpubusy); return buf; } proc_printdef procprt_GPUGPUBUSY = { "GPUBUSY", "GPUGPUBUSY", procprt_GPUGPUBUSY_ae, procprt_GPUGPUBUSY_ae, 7}; /***************************************************************/ char * procprt_GPUMEMBUSY_ae(struct tstat *curstat, int avgval, int nsecs) { static char buf[16]; if (!curstat->gpu.state) return " -"; if (curstat->gpu.membusy == -1) return " N/A"; snprintf(buf, sizeof buf, "%6d%%", curstat->gpu.membusy); return buf; } proc_printdef procprt_GPUMEMBUSY = { "MEMBUSY", "GPUMEMBUSY", procprt_GPUMEMBUSY_ae, procprt_GPUMEMBUSY_ae, 7}; /***************************************************************/ char * procprt_SORTITEM_ae(struct tstat *curstat, int avgval, int nsecs) { return ""; // dummy function } proc_printdef procprt_SORTITEM = { 0, "SORTITEM", procprt_SORTITEM_ae, procprt_SORTITEM_ae, 4 }; atop-2.4.0/showsys.c0000664000203100020310000024444213416466037013671 0ustar gerlofgerlof/* ** 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 the Linux-specific functions to calculate ** figures to be visualized. ** ========================================================================== ** Author: JC van Winkel - AT Computing, Nijmegen, Holland ** E-mail: jc@ATComputing.nl ** Date: November 2009 ** -------------------------------------------------------------------------- ** Copyright (C) 2009 JC van Winkel ** ** 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 ** -------------------------------------------------------------------------- ** ** $Log: showsys.c,v $ ** Revision 1.10 2010/11/12 06:06:43 gerlof ** Sometimes segmentation-fault on particular CPU-types ** due to memcpy i.s.o. memmove when moving memory in overlap. ** ** Revision 1.9 2010/10/23 14:04:20 gerlof ** Counters for total number of running and sleep threads (JC van Winkel). ** ** Revision 1.8 2010/05/18 19:20:02 gerlof ** Introduce CPU frequency and scaling (JC van Winkel). ** ** Revision 1.7 2010/04/23 08:16:58 gerlof ** Field 'avque' modified to 'avq' to be able to show higher values ** (especially on LVM-level). ** ** Revision 1.6 2010/03/04 10:53:37 gerlof ** Support I/O-statistics on logical volumes and MD devices. ** ** Revision 1.5 2009/12/17 11:59:36 gerlof ** Gather and display new counters: dirty cache and guest cpu usage. ** ** Revision 1.4 2009/12/17 08:53:03 gerlof ** If no coclors wanted, use bold display for critical resources. ** ** Revision 1.3 2009/12/17 07:33:05 gerlof ** Scale system-statistics properly when modifying window size (JC van Winkel). ** ** Revision 1.2 2009/12/10 11:56:08 gerlof ** Various bug-solutions. ** ** Revision 1.1 2009/12/10 09:46:16 gerlof ** Initial revision ** ** Initial revision ** ** ** Initial ** */ static const char rcsid[] = "XXXXXX"; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "atop.h" #include "photoproc.h" #include "photosyst.h" #include "showgeneric.h" #include "showlinux.h" /*******************************************************************/ /* ** print the label of a system-statistics line and switch on ** colors if needed */ static int syscolorlabel(char *labeltext, unsigned int badness) { if (screen) { if (badness >= 100) { attron (A_BLINK); if (usecolors) { attron(COLOR_PAIR(COLORCRIT)); printg(labeltext); attroff(COLOR_PAIR(COLORCRIT)); } else { attron(A_BOLD); printg(labeltext); attroff(A_BOLD); } attroff(A_BLINK); return COLORCRIT; } if (almostcrit && badness >= almostcrit) { if (usecolors) { attron(COLOR_PAIR(COLORALMOST)); printg(labeltext); attroff(COLOR_PAIR(COLORALMOST)); } else { attron(A_BOLD); printg(labeltext); attroff(A_BOLD); } return COLORALMOST; } } /* ** no colors required or no reason to show colors */ printg(labeltext); return 0; } char *sysprt_BLANKBOX(void *p, void *notused, int, int *); void addblanks(double *charslackused, double *charslackover) { *charslackused+=*charslackover; while (*charslackused>0.5) { printg(" "); *charslackused-=1; } } /* * showsysline * print an array of sys_printpair things. If the screen contains to * few character columns, lower priority items are removed * */ void showsysline(sys_printpair* elemptr, struct sstat* sstat, extraparam *extra, char *labeltext, unsigned int badness) { sys_printdef *curelem; int maxw = screen ? COLS : linelen; // every 15-char item is printed as: // >>>> | datadatadata<<<<< // 012345678901234 /* how many items will fit on one line? */ int avail = (maxw-5)/15; syscolorlabel(labeltext, badness); /* count number of items */ #define MAXELEMS 40 sys_printpair newelems[MAXELEMS]; int nitems; for (nitems=0; nitems < MAXELEMS-1 && elemptr[nitems].f != 0; ++nitems) newelems[nitems]=elemptr[nitems]; newelems[nitems].f=0; /* remove lowest priority box to make room as needed */ while (nitems > avail) { int lowestprio=999999; int lowestprio_index=-1; int i; for (i=0; i1) { slackitemsover=(double)(avail-nitems)/(nitems); } else { slackitemsover=(avail-nitems)/2; } // charslack: the slack in characters after using as many // items as possible double charslackover = screen ? ((COLS - 5) % 15) : ((linelen - 5) %15); // two places per items where blanks can be added charslackover /= (avail * 2); double charslackused=0.0; double itemslackused=0.0; elemptr=newelems; while ((curelem=elemptr->f)!=0) { char *itemp; int color; printg(" | "); addblanks(&charslackused, &charslackover); /* ** by default no color is shown for this field (color = 0) ** ** the convert-function can set a color-number (color > 0) ** when a specific color is wanted or the convert-function ** can leave the decision to display with a color to the piece ** of code below (color == -1) */ color = 0; itemp = curelem->doconvert(sstat, extra, badness, &color); if (screen) { if (color == -1) // default color wanted { color = 0; if (badness >= 100) color = COLORCRIT; else if (almostcrit && badness >= almostcrit) color = COLORALMOST; } if (color) // after all: has a color been set? { if (usecolors) attron(COLOR_PAIR(color)); else attron(A_BOLD); } } printg("%s", itemp); if (color && screen) // color set for this value? { if (usecolors) attroff(COLOR_PAIR(color)); else attroff(A_BOLD); } itemslackused+=slackitemsover; while (itemslackused>0.5) { addblanks(&charslackused, &charslackover); printg(" | "); printg("%s", sysprt_BLANKBOX(0, 0, 0, 0)); addblanks(&charslackused, &charslackover); itemslackused-=1; } elemptr++; addblanks(&charslackused, &charslackover); } printg(" |"); if (!screen) { printg("\n"); } } /*******************************************************************/ /* SYSTEM PRINT FUNCTIONS */ /*******************************************************************/ char * sysprt_PRCSYS(void *notused, void *q, int badness, int *color) { extraparam *as=q; static char buf[15]="sys "; val2cpustr(as->totst * 1000/hertz, buf+6); return buf; } sys_printdef syspdef_PRCSYS = {"PRCSYS", sysprt_PRCSYS}; /*******************************************************************/ char * sysprt_PRCUSER(void *notused, void *q, int badness, int *color) { extraparam *as=q; static char buf[15]="user "; val2cpustr(as->totut * 1000/hertz, buf+6); return buf; } sys_printdef syspdef_PRCUSER = {"PRCUSER", sysprt_PRCUSER}; /*******************************************************************/ char * sysprt_PRCNPROC(void *notused, void *q, int badness, int *color) { extraparam *as=q; static char buf[15]="#proc "; val2valstr(as->nproc - as->nexit, buf+6, 6, 0, 0); return buf; } sys_printdef syspdef_PRCNPROC = {"PRCNPROC", sysprt_PRCNPROC}; /*******************************************************************/ char * sysprt_PRCNRUNNING(void *notused, void *q, int badness, int *color) { extraparam *as=q; static char buf[15]="#trun "; val2valstr(as->ntrun, buf+6, 6, 0, 0); return buf; } sys_printdef syspdef_PRCNRUNNING = {"PRCNRUNNING", sysprt_PRCNRUNNING}; /*******************************************************************/ char * sysprt_PRCNSLEEPING(void *notused, void *q, int badness, int *color) { extraparam *as=q; static char buf[15]="#tslpi "; val2valstr(as->ntslpi, buf+8, 4, 0, 0); return buf; } sys_printdef syspdef_PRCNSLEEPING = {"PRCNSLEEPING", sysprt_PRCNSLEEPING}; /*******************************************************************/ char * sysprt_PRCNDSLEEPING(void *notused, void *q, int badness, int *color) { extraparam *as=q; static char buf[15]="#tslpu "; val2valstr(as->ntslpu, buf+8, 4, 0, 0); return buf; } sys_printdef syspdef_PRCNDSLEEPING = {"PRCNDSLEEPING", sysprt_PRCNDSLEEPING}; /*******************************************************************/ char * sysprt_PRCNZOMBIE(void *notused, void *q, int badness, int *color) { extraparam *as=q; static char buf[15]="#zombie "; if (as->nzomb > 30) *color = COLORALMOST; if (as->nzomb > 50) *color = COLORCRIT; val2valstr(as->nzomb, buf+8, 4, 0, 0); return buf; } sys_printdef syspdef_PRCNZOMBIE = {"PRCNZOMBIE", sysprt_PRCNZOMBIE}; /*******************************************************************/ char * sysprt_PRCNNEXIT(void *notused, void *q, int badness, int *color) { static char firstcall = 1; extraparam *as=q; static char buf[15]="#exit "; if (supportflags & ACCTACTIVE) { if (as->noverflow) { *color = COLORCRIT; buf[6] = '>'; val2valstr(as->nexit, buf+7, 5, as->avgval, as->nsecs); } else { val2valstr(as->nexit, buf+6, 6, as->avgval, as->nsecs); } return buf; } else { if (firstcall) { *color = COLORCRIT; firstcall = 0; } else { *color = COLORINFO; } switch (acctreason) { case 1: return "no procacct"; // "no acctread"; case 2: return "no procacct"; // "no acctwant"; case 3: return "no procacct"; // "no acctsema"; case 4: return "no procacct"; // "no acctmkdir"; case 5: return "no procacct"; // "no rootprivs"; default: return "no procacct"; } } } sys_printdef syspdef_PRCNNEXIT = {"PRCNNEXIT", sysprt_PRCNNEXIT}; /*******************************************************************/ char * sysprt_CPUSYS(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[15]; float perc = (sstat->cpu.all.stime * 100.0) / as->percputot; if (perc > 1.0) *color = -1; sprintf(buf, "sys %6.0f%%", perc); return buf; } sys_printdef syspdef_CPUSYS = {"CPUSYS", sysprt_CPUSYS}; /*******************************************************************/ char * sysprt_CPUUSER(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[15]; float perc = (sstat->cpu.all.utime + sstat->cpu.all.ntime) * 100.0 / as->percputot; if (perc > 1.0) *color = -1; sprintf(buf, "user %6.0f%%", perc); return buf; } sys_printdef syspdef_CPUUSER = {"CPUUSER", sysprt_CPUUSER}; /*******************************************************************/ char * sysprt_CPUIRQ(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[15]; float perc = (sstat->cpu.all.Itime + sstat->cpu.all.Stime) * 100.0 / as->percputot; if (perc > 1.0) *color = -1; sprintf(buf, "irq %6.0f%%", perc); return buf; } sys_printdef syspdef_CPUIRQ = {"CPUIRQ", sysprt_CPUIRQ}; /*******************************************************************/ char * sysprt_CPUIDLE(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[15]; sprintf(buf, "idle %6.0f%%", (sstat->cpu.all.itime * 100.0) / as->percputot); return buf; } sys_printdef syspdef_CPUIDLE = {"CPUIDLE", sysprt_CPUIDLE}; /*******************************************************************/ char * sysprt_CPUWAIT(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[15]; sprintf(buf, "wait %6.0f%%", (sstat->cpu.all.wtime * 100.0) / as->percputot); return buf; } sys_printdef syspdef_CPUWAIT = {"CPUWAIT", sysprt_CPUWAIT}; /*******************************************************************/ char * sysprt_CPUISYS(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[15]; float perc = sstat->cpu.cpu[as->index].stime * 100.0 / as->percputot; if (perc > 1.0) *color = -1; sprintf(buf, "sys %6.0f%%", perc); return buf; } sys_printdef syspdef_CPUISYS = {"CPUISYS", sysprt_CPUISYS}; /*******************************************************************/ char * sysprt_CPUIUSER(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[15]; float perc = (sstat->cpu.cpu[as->index].utime + sstat->cpu.cpu[as->index].ntime) * 100.0 / as->percputot; if (perc > 1.0) *color = -1; sprintf(buf, "user %6.0f%%", perc); return buf; } sys_printdef syspdef_CPUIUSER = {"CPUIUSER", sysprt_CPUIUSER}; /*******************************************************************/ char * sysprt_CPUIIRQ(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[15]; float perc = (sstat->cpu.cpu[as->index].Itime + sstat->cpu.cpu[as->index].Stime) * 100.0 / as->percputot; if (perc > 1.0) *color = -1; sprintf(buf, "irq %6.0f%%", perc); return buf; } sys_printdef syspdef_CPUIIRQ = {"CPUIIRQ", sysprt_CPUIIRQ}; /*******************************************************************/ char * sysprt_CPUIIDLE(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[15]; sprintf(buf, "idle %6.0f%%", (sstat->cpu.cpu[as->index].itime * 100.0) / as->percputot); return buf; } sys_printdef syspdef_CPUIIDLE = {"CPUIIDLE", sysprt_CPUIIDLE}; /*******************************************************************/ char * sysprt_CPUIWAIT(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[15]; sprintf(buf, "cpu%03d w%3.0f%%", sstat->cpu.cpu[as->index].cpunr, (sstat->cpu.cpu[as->index].wtime * 100.0) / as->percputot); return buf; } sys_printdef syspdef_CPUIWAIT = {"CPUIWAIT", sysprt_CPUIWAIT}; /*******************************************************************/ void dofmt_cpufreq(char *buf, count_t maxfreq, count_t cnt, count_t ticks) { // if ticks != 0, do full output if (ticks) { count_t curfreq = cnt/ticks; strcpy(buf, "avgf "); val2Hzstr(curfreq, buf+5); } else if (cnt) // no max, no %. if freq is known: print it { strcpy(buf, "curf "); val2Hzstr(cnt, buf+5); } else // nothing is known: print ????? { strcpy(buf, "curf ?MHz"); } } /* * sumscaling: sum scaling info for all processors * */ void sumscaling(struct sstat *sstat, count_t *maxfreq, count_t *cnt, count_t *ticks) { count_t mymaxfreq = 0; count_t mycnt = 0; count_t myticks = 0; int n=sstat->cpu.nrcpu; int i; for (i=0; i < n; ++i) { mymaxfreq+= sstat->cpu.cpu[i].freqcnt.maxfreq; mycnt += sstat->cpu.cpu[i].freqcnt.cnt; myticks += sstat->cpu.cpu[i].freqcnt.ticks; } *maxfreq= mymaxfreq; *cnt = mycnt; *ticks = myticks; } void dofmt_cpuscale(char *buf, count_t maxfreq, count_t cnt, count_t ticks) { if (ticks) { count_t curfreq = cnt/ticks; int perc = maxfreq ? 100 * curfreq / maxfreq : 0; strcpy(buf, "avgscal "); sprintf(buf+7, "%4d%%", perc); } else if (maxfreq) // max frequency is known so % can be calculated { strcpy(buf, "curscal "); sprintf(buf+7, "%4lld%%", 100 * cnt / maxfreq); } else // nothing is known: print ????? { strcpy(buf, "curscal ?%"); } } /*******************************************************************/ char * sysprt_CPUIFREQ(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[15]; count_t maxfreq = sstat->cpu.cpu[as->index].freqcnt.maxfreq; count_t cnt = sstat->cpu.cpu[as->index].freqcnt.cnt; count_t ticks = sstat->cpu.cpu[as->index].freqcnt.ticks; dofmt_cpufreq(buf, maxfreq, cnt, ticks); return buf; } sys_printdef syspdef_CPUIFREQ = {"CPUIFREQ", sysprt_CPUIFREQ}; /*******************************************************************/ char * sysprt_CPUFREQ(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; static char buf[15]; count_t maxfreq; count_t cnt; count_t ticks; int n = sstat->cpu.nrcpu; sumscaling(sstat, &maxfreq, &cnt, &ticks); dofmt_cpufreq(buf, maxfreq/n, cnt/n, ticks/n); return buf; } sys_printdef syspdef_CPUFREQ = {"CPUFREQ", sysprt_CPUFREQ}; /*******************************************************************/ char * sysprt_CPUISCALE(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[15]; count_t maxfreq = sstat->cpu.cpu[as->index].freqcnt.maxfreq; count_t cnt = sstat->cpu.cpu[as->index].freqcnt.cnt; count_t ticks = sstat->cpu.cpu[as->index].freqcnt.ticks; dofmt_cpuscale(buf, maxfreq, cnt, ticks); return buf; } sys_printdef syspdef_CPUISCALE = {"CPUISCALE", sysprt_CPUISCALE}; /*******************************************************************/ char * sysprt_CPUSCALE(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; static char buf[15]; count_t maxfreq; count_t cnt; count_t ticks; int n = sstat->cpu.nrcpu; sumscaling(sstat, &maxfreq, &cnt, &ticks); dofmt_cpuscale(buf, maxfreq/n, cnt/n, ticks/n); return buf; } sys_printdef syspdef_CPUSCALE = {"CPUSCALE", sysprt_CPUSCALE}; /*******************************************************************/ char * sysprt_CPUSTEAL(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[15]; float perc = sstat->cpu.all.steal * 100.0 / as->percputot; if (perc > 1.0) *color = -1; sprintf(buf, "steal %5.0f%%", perc); return buf; } sys_printdef syspdef_CPUSTEAL = {"CPUSTEAL", sysprt_CPUSTEAL}; /*******************************************************************/ char * sysprt_CPUISTEAL(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[15]; float perc = sstat->cpu.cpu[as->index].steal * 100.0 / as->percputot; if (perc > 1.0) *color = -1; sprintf(buf, "steal %5.0f%%", perc); return buf; } sys_printdef syspdef_CPUISTEAL = {"CPUISTEAL", sysprt_CPUISTEAL}; /*******************************************************************/ char * sysprt_CPUGUEST(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[15]; float perc = sstat->cpu.all.guest * 100.0 / as->percputot; if (perc > 1.0) *color = -1; sprintf(buf, "guest %5.0f%%", perc); return buf; } sys_printdef syspdef_CPUGUEST = {"CPUGUEST", sysprt_CPUGUEST}; /*******************************************************************/ char * sysprt_CPUIGUEST(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[15]; float perc = sstat->cpu.cpu[as->index].guest * 100.0 / as->percputot; if (perc > 1.0) *color = -1; sprintf(buf, "guest %5.0f%%", perc); return buf; } sys_printdef syspdef_CPUIGUEST = {"CPUIGUEST", sysprt_CPUIGUEST}; /*******************************************************************/ char * sysprt_CPUIPC(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; static char buf[15]; float ipc = 0.0; switch (sstat->cpu.all.cycle) { case 0: *color = COLORINFO; sprintf(buf, "ipc notavail"); break; case 1: *color = COLORINFO; sprintf(buf, "ipc initial"); break; default: ipc = sstat->cpu.all.instr * 100 / sstat->cpu.all.cycle / 100.0; sprintf(buf, "ipc %8.2f", ipc); } return buf; } sys_printdef syspdef_CPUIPC = {"CPUIPC", sysprt_CPUIPC}; /*******************************************************************/ char * sysprt_CPUIIPC(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[15]; float ipc = 0.0; switch (sstat->cpu.all.cycle) { case 0: *color = COLORINFO; sprintf(buf, "ipc notavail"); break; case 1: *color = COLORINFO; sprintf(buf, "ipc initial"); break; default: if (sstat->cpu.cpu[as->index].cycle) ipc = sstat->cpu.cpu[as->index].instr * 100 / sstat->cpu.cpu[as->index].cycle / 100.0; sprintf(buf, "ipc %8.2f", ipc); } return buf; } sys_printdef syspdef_CPUIIPC = {"CPUIIPC", sysprt_CPUIIPC}; /*******************************************************************/ char * sysprt_CPUCYCLE(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[15] = "cycl "; switch (sstat->cpu.all.cycle) { case 0: *color = COLORINFO; sprintf(buf+5, "unknown"); break; case 1: *color = COLORINFO; sprintf(buf+5, "initial"); break; default: val2Hzstr(sstat->cpu.all.cycle/1000000/as->nsecs/ sstat->cpu.nrcpu, buf+5); } return buf; } sys_printdef syspdef_CPUCYCLE = {"CPUCYCLE", sysprt_CPUCYCLE}; /*******************************************************************/ char * sysprt_CPUICYCLE(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[15] = "cycl "; switch (sstat->cpu.all.cycle) { case 0: *color = COLORINFO; sprintf(buf+5, "unknown"); break; case 1: *color = COLORINFO; sprintf(buf+5, "initial"); break; default: val2Hzstr(sstat->cpu.cpu[as->index].cycle/1000000/ as->nsecs, buf+5); } return buf; } sys_printdef syspdef_CPUICYCLE = {"CPUICYCLE", sysprt_CPUICYCLE}; /*******************************************************************/ char * sysprt_CPLAVG1(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[15]="avg1 "; if (sstat->cpu.lavg1 > 999.0) { sprintf(buf+5, "%7.0f", sstat->cpu.lavg1); } else { sprintf(buf+5, "%7.2f", sstat->cpu.lavg1); } return buf; } sys_printdef syspdef_CPLAVG1 = {"CPLAVG1", sysprt_CPLAVG1}; /*******************************************************************/ char * sysprt_CPLAVG5(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[15]="avg5 "; if (sstat->cpu.lavg5 > 999.0) { sprintf(buf+5, "%7.0f", sstat->cpu.lavg5); } else { sprintf(buf+5, "%7.2f", sstat->cpu.lavg5); } return buf; } sys_printdef syspdef_CPLAVG5 = {"CPLAVG5", sysprt_CPLAVG5}; /*******************************************************************/ char * sysprt_CPLAVG15(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[15]="avg15 "; if (sstat->cpu.lavg15 > (2 * sstat->cpu.nrcpu) ) *color = COLORALMOST; if (sstat->cpu.lavg15 > 999.0) { sprintf(buf+6, "%6.0f", sstat->cpu.lavg15); } else { sprintf(buf+6, "%6.2f", sstat->cpu.lavg15); } return buf; } sys_printdef syspdef_CPLAVG15 = {"CPLAVG15", sysprt_CPLAVG15}; /*******************************************************************/ char * sysprt_CPLCSW(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="csw "; val2valstr(sstat->cpu.csw, buf+4 , 8,as->avgval,as->nsecs); return buf; } sys_printdef syspdef_CPLCSW = {"CPLCSW", sysprt_CPLCSW}; /*******************************************************************/ char * sysprt_PRCCLONES(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="clones "; val2valstr(sstat->cpu.nprocs, buf+7 , 5,as->avgval,as->nsecs); return buf; } sys_printdef syspdef_PRCCLONES = {"PRCCLONES", sysprt_PRCCLONES}; /*******************************************************************/ char * sysprt_CPLNUMCPU(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="numcpu "; val2valstr(sstat->cpu.nrcpu, buf+7 , 5,0,as->nsecs); return buf; } sys_printdef syspdef_CPLNUMCPU = {"CPLNUMCPU", sysprt_CPLNUMCPU}; /*******************************************************************/ char * sysprt_CPLINTR(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="intr "; val2valstr(sstat->cpu.devint, buf+5 , 7,as->avgval,as->nsecs); return buf; } sys_printdef syspdef_CPLINTR = {"CPLINTR", sysprt_CPLINTR}; /*******************************************************************/ char * sysprt_GPUBUS(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]; char *pn; int len; if ( (len = strlen(sstat->gpu.gpu[as->index].busid)) > 9) pn = sstat->gpu.gpu[as->index].busid + len - 9; else pn = sstat->gpu.gpu[as->index].busid; sprintf(buf, "%9.9s %2d", pn, sstat->gpu.gpu[as->index].gpunr); return buf; } sys_printdef syspdef_GPUBUS = {"GPUBUS", sysprt_GPUBUS}; /*******************************************************************/ char * sysprt_GPUTYPE(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]; char *pn; int len; if ( (len = strlen(sstat->gpu.gpu[as->index].type)) > 12) pn = sstat->gpu.gpu[as->index].type + len - 12; else pn = sstat->gpu.gpu[as->index].type; sprintf(buf, "%12.12s", pn); return buf; } sys_printdef syspdef_GPUTYPE = {"GPUTYPE", sysprt_GPUTYPE}; /*******************************************************************/ char * sysprt_GPUNRPROC(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16] = "#proc "; val2valstr(sstat->gpu.gpu[as->index].nrprocs, buf+6, 6, 0, 0); return buf; } sys_printdef syspdef_GPUNRPROC = {"GPUNRPROC", sysprt_GPUNRPROC}; /*******************************************************************/ char * sysprt_GPUMEMPERC(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="membusy "; int perc = sstat->gpu.gpu[as->index].mempercnow; if (perc == -1) { sprintf(buf+8, " N/A"); } else { // preferably take the average percentage over sample if (sstat->gpu.gpu[as->index].samples) perc = sstat->gpu.gpu[as->index].memperccum / sstat->gpu.gpu[as->index].samples; if (perc >= 40) *color = COLORALMOST; snprintf(buf+8, sizeof buf-8, "%3d%%", perc); } return buf; } sys_printdef syspdef_GPUMEMPERC = {"GPUMEMPERC", sysprt_GPUMEMPERC}; /*******************************************************************/ char * sysprt_GPUGPUPERC(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="gpubusy "; int perc = sstat->gpu.gpu[as->index].gpupercnow; if (perc == -1) // metric not available? { sprintf(buf+8, " N/A"); } else { // preferably take the average percentage over sample if (sstat->gpu.gpu[as->index].samples) perc = sstat->gpu.gpu[as->index].gpuperccum / sstat->gpu.gpu[as->index].samples; if (perc >= 90) *color = COLORALMOST; snprintf(buf+8, sizeof buf-8, "%3d%%", perc); } return buf; } sys_printdef syspdef_GPUGPUPERC = {"GPUGPUPERC", sysprt_GPUGPUPERC}; /*******************************************************************/ char * sysprt_GPUMEMOCC(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="memocc "; int perc; perc = sstat->gpu.gpu[as->index].memusenow * 100 / (sstat->gpu.gpu[as->index].memtotnow ? sstat->gpu.gpu[as->index].memtotnow : 1); snprintf(buf+7, sizeof buf-7, "%4d%%", perc); return buf; } sys_printdef syspdef_GPUMEMOCC = {"GPUMEMOCC", sysprt_GPUMEMOCC}; /*******************************************************************/ char * sysprt_GPUMEMTOT(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16] = "total "; val2memstr(sstat->gpu.gpu[as->index].memtotnow * 1024, buf+6, MBFORMAT, 0, 0); return buf; } sys_printdef syspdef_GPUMEMTOT = {"GPUMEMTOT", sysprt_GPUMEMTOT}; /*******************************************************************/ char * sysprt_GPUMEMUSE(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16] = "used "; val2memstr(sstat->gpu.gpu[as->index].memusenow * 1024, buf+6, MBFORMAT, 0, 0); return buf; } sys_printdef syspdef_GPUMEMUSE = {"GPUMEMUSE", sysprt_GPUMEMUSE}; /*******************************************************************/ char * sysprt_GPUMEMAVG(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16] = "usavg "; if (sstat->gpu.gpu[as->index].samples) val2memstr(sstat->gpu.gpu[as->index].memusecum * 1024 / sstat->gpu.gpu[as->index].samples, buf+6, MBFORMAT, 0, 0); else return "usavg ?"; return buf; } sys_printdef syspdef_GPUMEMAVG = {"GPUMEMAVG", sysprt_GPUMEMAVG}; /*******************************************************************/ char * sysprt_MEMTOT(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[16]="tot "; *color = -1; val2memstr(sstat->mem.physmem * pagesize, buf+6, MBFORMAT, 0, 0); return buf; } sys_printdef syspdef_MEMTOT = {"MEMTOT", sysprt_MEMTOT}; /*******************************************************************/ char * sysprt_MEMFREE(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[16]="free "; *color = -1; val2memstr(sstat->mem.freemem * pagesize, buf+6, MBFORMAT, 0, 0); return buf; } sys_printdef syspdef_MEMFREE = {"MEMFREE", sysprt_MEMFREE}; /*******************************************************************/ char * sysprt_MEMCACHE(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[16]="cache "; *color = -1; val2memstr(sstat->mem.cachemem * pagesize, buf+6, MBFORMAT, 0, 0); return buf; } sys_printdef syspdef_MEMCACHE = {"MEMCACHE", sysprt_MEMCACHE}; /*******************************************************************/ char * sysprt_MEMDIRTY(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[16] = "dirty "; val2memstr(sstat->mem.cachedrt * pagesize, buf+6, MBFORMAT, 0, 0); return buf; } sys_printdef syspdef_MEMDIRTY = {"MEMDIRTY", sysprt_MEMDIRTY}; /*******************************************************************/ char * sysprt_MEMBUFFER(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[16]="buff "; *color = -1; val2memstr(sstat->mem.buffermem * pagesize, buf+6, MBFORMAT, 0, 0); return buf; } sys_printdef syspdef_MEMBUFFER = {"MEMBUFFER", sysprt_MEMBUFFER}; /*******************************************************************/ char * sysprt_MEMSLAB(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[16]="slab "; *color = -1; val2memstr(sstat->mem.slabmem * pagesize, buf+6, MBFORMAT, 0, 0); return buf; } sys_printdef syspdef_MEMSLAB = {"MEMSLAB", sysprt_MEMSLAB}; /*******************************************************************/ char * sysprt_RECSLAB(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[16]="slrec "; *color = -1; val2memstr(sstat->mem.slabreclaim * pagesize, buf+6, MBFORMAT, 0, 0); return buf; } sys_printdef syspdef_RECSLAB = {"RECSLAB", sysprt_RECSLAB}; /*******************************************************************/ char * sysprt_SHMEM(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[16]="shmem "; *color = -1; val2memstr(sstat->mem.shmem * pagesize, buf+6, MBFORMAT, 0, 0); return buf; } sys_printdef syspdef_SHMEM = {"SHMEM", sysprt_SHMEM}; /*******************************************************************/ char * sysprt_SHMRSS(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[16]="shrss "; *color = -1; val2memstr(sstat->mem.shmrss * pagesize, buf+6, MBFORMAT, 0, 0); return buf; } sys_printdef syspdef_SHMRSS = {"SHMRSS", sysprt_SHMRSS}; /*******************************************************************/ char * sysprt_SHMSWP(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[16]="shswp "; *color = -1; val2memstr(sstat->mem.shmswp * pagesize, buf+6, MBFORMAT, 0, 0); return buf; } sys_printdef syspdef_SHMSWP = {"SHMSWP", sysprt_SHMSWP}; /*******************************************************************/ char * sysprt_HUPTOT(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[16]="hptot "; *color = -1; val2memstr(sstat->mem.tothugepage * sstat->mem.hugepagesz, buf+6, MBFORMAT, 0, 0); return buf; } sys_printdef syspdef_HUPTOT = {"HUPTOT", sysprt_HUPTOT}; /*******************************************************************/ char * sysprt_HUPUSE(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[16]="hpuse "; *color = -1; val2memstr( (sstat->mem.tothugepage - sstat->mem.freehugepage) * sstat->mem.hugepagesz, buf+6, MBFORMAT, 0, 0); return buf; } sys_printdef syspdef_HUPUSE = {"HUPUSE", sysprt_HUPUSE}; /*******************************************************************/ char * sysprt_VMWBAL(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[16]="vmbal "; *color = -1; val2memstr(sstat->mem.vmwballoon * pagesize, buf+6, MBFORMAT, 0, 0); return buf; } sys_printdef syspdef_VMWBAL = {"VMWBAL", sysprt_VMWBAL}; /*******************************************************************/ char * sysprt_SWPTOT(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[16]="tot "; *color = -1; val2memstr(sstat->mem.totswap * pagesize, buf+6, MBFORMAT, 0, 0); return buf; } sys_printdef syspdef_SWPTOT = {"SWPTOT", sysprt_SWPTOT}; /*******************************************************************/ char * sysprt_SWPFREE(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[16]="free "; *color = -1; val2memstr(sstat->mem.freeswap * pagesize, buf+6, MBFORMAT, 0, 0); return buf; } sys_printdef syspdef_SWPFREE = {"SWPFREE", sysprt_SWPFREE}; /*******************************************************************/ char * sysprt_SWPCOMMITTED(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[16]="vmcom "; val2memstr(sstat->mem.committed * pagesize, buf+6, MBFORMAT, 0, 0); if (sstat->mem.commitlim && sstat->mem.committed > sstat->mem.commitlim) *color = COLORALMOST; return buf; } sys_printdef syspdef_SWPCOMMITTED = {"SWPCOMMITTED", sysprt_SWPCOMMITTED}; /*******************************************************************/ char * sysprt_SWPCOMMITLIM(void *p, void *notused, int badness, int *color) { struct sstat *sstat=p; static char buf[16]="vmlim "; val2memstr(sstat->mem.commitlim * pagesize, buf+6, MBFORMAT, 0, 0); if (sstat->mem.commitlim && sstat->mem.committed > sstat->mem.commitlim) *color = COLORINFO; return buf; } sys_printdef syspdef_SWPCOMMITLIM = {"SWPCOMMITLIM", sysprt_SWPCOMMITLIM}; /*******************************************************************/ char * sysprt_PAGSCAN(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="scan "; val2valstr(sstat->mem.pgscans, buf+5, 7, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_PAGSCAN = {"PAGSCAN", sysprt_PAGSCAN}; /*******************************************************************/ char * sysprt_PAGSTEAL(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="steal "; val2valstr(sstat->mem.pgsteal, buf+ 6, 6, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_PAGSTEAL = {"PAGSTEAL", sysprt_PAGSTEAL}; /*******************************************************************/ char * sysprt_PAGSTALL(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="stall "; val2valstr(sstat->mem.allocstall, buf+6, 6, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_PAGSTALL = {"PAGSTALL", sysprt_PAGSTALL}; /*******************************************************************/ char * sysprt_PAGSWIN(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="swin "; val2valstr(sstat->mem.swins, buf+5, 7, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_PAGSWIN = {"PAGSWIN", sysprt_PAGSWIN}; /*******************************************************************/ char * sysprt_PAGSWOUT(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="swout "; *color = -1; val2valstr(sstat->mem.swouts, buf+6, 6, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_PAGSWOUT = {"PAGSWOUT", sysprt_PAGSWOUT}; /*******************************************************************/ // general formatting of PSI field void psiformat(struct psi *p, char *head, char *buf, int bufsize) { static char formats[] = "%.0f/%.0f/%.0f"; char tmpbuf[32]; snprintf(tmpbuf, sizeof tmpbuf, formats, p->avg10, p->avg60, p->avg300); if (strlen(tmpbuf) > 9) // reformat needed? { float avg10 = p->avg10; float avg60 = p->avg60; float avg300 = p->avg300; if (avg10 > 99.0) avg10 = 99.0; if (avg60 > 99.0) avg60 = 99.0; if (avg300 > 99.0) avg300 = 99.0; snprintf(tmpbuf, sizeof tmpbuf, formats, avg10, avg60, avg300); } snprintf(buf, bufsize, "%s %9s", head, tmpbuf); } char * sysprt_PSICPUS(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; static char buf[16]; psiformat(&(sstat->psi.cpusome), "cs", buf, sizeof buf); return buf; } sys_printdef syspdef_PSICPUS = {"PSICPUS", sysprt_PSICPUS}; char * sysprt_PSIMEMS(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; static char buf[16]; psiformat(&(sstat->psi.memsome), "ms", buf, sizeof buf); return buf; } sys_printdef syspdef_PSIMEMS = {"PSIMEMS", sysprt_PSIMEMS}; char * sysprt_PSIMEMF(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; static char buf[16]; psiformat(&(sstat->psi.memfull), "mf", buf, sizeof buf); return buf; } sys_printdef syspdef_PSIMEMF = {"PSIMEMF", sysprt_PSIMEMF}; char * sysprt_PSIIOS(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; static char buf[16]; psiformat(&(sstat->psi.iosome), "is", buf, sizeof buf); return buf; } sys_printdef syspdef_PSIIOS = {"PSIIOS", sysprt_PSIIOS}; char * sysprt_PSIIOF(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; static char buf[16]; psiformat(&(sstat->psi.iosome), "if", buf, sizeof buf); return buf; } sys_printdef syspdef_PSIIOF = {"PSIIOF", sysprt_PSIIOF}; /*******************************************************************/ char * sysprt_CONTNAME(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[32] = "ctid "; *color = -1; sprintf(buf+5, "%7lu", sstat->cfs.cont[as->index].ctid); return buf; } sys_printdef syspdef_CONTNAME = {"CONTNAME", sysprt_CONTNAME}; /*******************************************************************/ char * sysprt_CONTNPROC(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="nproc "; *color = -1; val2valstr(sstat->cfs.cont[as->index].numproc, buf+6, 6, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_CONTNPROC = {"CONTNPROC", sysprt_CONTNPROC}; /*******************************************************************/ char * sysprt_CONTCPU(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]; float perc; count_t used = sstat->cfs.cont[as->index].system + sstat->cfs.cont[as->index].user + sstat->cfs.cont[as->index].nice; *color = -1; if (sstat->cfs.cont[as->index].uptime) { perc = used * 100.0 / sstat->cfs.cont[as->index].uptime; sprintf(buf, "cpubusy %3.0f%%", perc); } else sprintf(buf, "cpubusy ?%%"); return buf; } sys_printdef syspdef_CONTCPU = {"CONTCPU", sysprt_CONTCPU}; /*******************************************************************/ char * sysprt_CONTMEM(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="mem "; *color = -1; val2memstr(sstat->cfs.cont[as->index].physpages * pagesize, buf+6, MBFORMAT, 0, 0); return buf; } sys_printdef syspdef_CONTMEM = {"CONTMEM", sysprt_CONTMEM}; /*******************************************************************/ char * sysprt_DSKNAME(void *p, void *q, int badness, int *color) { extraparam *as=q; static char buf[16]; char *pn; int len; *color = -1; if ( (len = strlen(as->perdsk[as->index].name)) > 12) pn = as->perdsk[as->index].name + len - 12; else pn = as->perdsk[as->index].name; sprintf(buf, "%12.12s", pn); return buf; } sys_printdef syspdef_DSKNAME = {"DSKNAME", sysprt_DSKNAME}; /*******************************************************************/ char * sysprt_DSKBUSY(void *p, void *q, int badness, int *color) { extraparam *as=q; double perc; static char buf[16]="busy "; *color = -1; perc = as->perdsk[as->index].io_ms * 100.0 / as->mstot; if (perc >= 0.0 && perc < 1000000.0) sprintf(buf+5, "%6.0lf%%", perc); else sprintf(buf+5, "%6.0lf%%", 999999.0); return buf; } sys_printdef syspdef_DSKBUSY = {"DSKBUSY", sysprt_DSKBUSY}; /*******************************************************************/ char * sysprt_DSKNREAD(void *p, void *q, int badness, int *color) { extraparam *as=q; static char buf[16]="read "; *color = -1; val2valstr(as->perdsk[as->index].nread >= 0 ? as->perdsk[as->index].nread : 0, buf+5, 7, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_DSKNREAD = {"DSKNREAD", sysprt_DSKNREAD}; /*******************************************************************/ char * sysprt_DSKNWRITE(void *p, void *q, int badness, int *color) { extraparam *as=q; static char buf[16]="write "; *color = -1; val2valstr(as->perdsk[as->index].nwrite >= 0 ? as->perdsk[as->index].nwrite : 0, buf+6, 6, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_DSKNWRITE = {"DSKNWRITE", sysprt_DSKNWRITE}; /*******************************************************************/ char * sysprt_DSKKBPERWR(void *p, void *q, int badness, int *color) { extraparam *as=q; static char buf[16]="KiB/w "; struct perdsk *dp = &(as->perdsk[as->index]); val2valstr(dp->nwrite > 0 ? dp->nwsect / dp->nwrite / 2 : 0, buf+6, 6, 0, as->nsecs); return buf; } sys_printdef syspdef_DSKKBPERWR = {"DSKKBPERWR", sysprt_DSKKBPERWR}; /*******************************************************************/ char * sysprt_DSKKBPERRD(void *p, void *q, int badness, int *color) { extraparam *as=q; static char buf[16]="KiB/r "; struct perdsk *dp = &(as->perdsk[as->index]); val2valstr(dp->nread > 0 ? dp->nrsect / dp->nread / 2 : 0, buf+6, 6, 0, as->nsecs); return buf; } sys_printdef syspdef_DSKKBPERRD = {"DSKKBPERRD", sysprt_DSKKBPERRD}; /*******************************************************************/ char * sysprt_DSKMBPERSECWR(void *p, void *q, int badness, int *color) { extraparam *as=q; static char buf[16]="MBw/s "; struct perdsk *dp = &(as->perdsk[as->index]); snprintf(buf+6, sizeof buf-6, "%6.1lf", dp->nwsect / 2.0 / 1024 / as->nsecs); return buf; } sys_printdef syspdef_DSKMBPERSECWR = {"DSKMBPERSECWR", sysprt_DSKMBPERSECWR}; /*******************************************************************/ char * sysprt_DSKMBPERSECRD(void *p, void *q, int badness, int *color) { extraparam *as=q; static char buf[16]="MBr/s "; struct perdsk *dp = &(as->perdsk[as->index]); snprintf(buf+6, sizeof buf-6, "%6.1lf", dp->nrsect / 2.0 / 1024 / as->nsecs); return buf; } sys_printdef syspdef_DSKMBPERSECRD = {"DSKMBPERSECRD", sysprt_DSKMBPERSECRD}; /*******************************************************************/ char * sysprt_DSKAVQUEUE(void *p, void *q, int badness, int *color) { extraparam *as=q; static char buf[16]="avq "; struct perdsk *dp = &(as->perdsk[as->index]); sprintf(buf+4, "%8.2f", dp->io_ms > 0 ? (double)dp->avque / dp->io_ms : 0.0); return buf; } sys_printdef syspdef_DSKAVQUEUE = {"DSKAVQUEUE", sysprt_DSKAVQUEUE}; /*******************************************************************/ char * sysprt_DSKAVIO(void *p, void *q, int badness, int *color) { extraparam *as=q; static char buf[16]="avio "; double tim = as->iotot > 0 ? (double)(as->perdsk[as->index].io_ms)/as->iotot:0.0; *color = -1; if (tim > 100.0) { sprintf(buf+5, "%4.0lf ms", tim); } else if (tim > 10.0) { sprintf(buf+5, "%4.1lf ms", tim); } else { sprintf(buf+5, "%4.2lf ms", tim); } return buf; } sys_printdef syspdef_DSKAVIO = {"DSKAVIO", sysprt_DSKAVIO}; /*******************************************************************/ char * sysprt_NETTRANSPORT(void *p, void *notused, int badness, int *color) { return "transport "; } sys_printdef syspdef_NETTRANSPORT = {"NETTRANSPORT", sysprt_NETTRANSPORT}; /*******************************************************************/ char * sysprt_NETTCPI(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="tcpi "; val2valstr(sstat->net.tcp.InSegs, buf+5, 7, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETTCPI = {"NETTCPI", sysprt_NETTCPI}; /*******************************************************************/ char * sysprt_NETTCPO(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="tcpo "; val2valstr(sstat->net.tcp.OutSegs, buf+5, 7, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETTCPO = {"NETTCPO", sysprt_NETTCPO}; /*******************************************************************/ char * sysprt_NETTCPACTOPEN(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="tcpao "; val2valstr(sstat->net.tcp.ActiveOpens, buf+6, 6, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETTCPACTOPEN = {"NETTCPACTOPEN", sysprt_NETTCPACTOPEN}; /*******************************************************************/ char * sysprt_NETTCPPASVOPEN(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="tcppo "; val2valstr(sstat->net.tcp.PassiveOpens, buf+6, 6, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETTCPPASVOPEN = {"NETTCPPASVOPEN", sysprt_NETTCPPASVOPEN}; /*******************************************************************/ char * sysprt_NETTCPRETRANS(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="tcprs "; val2valstr(sstat->net.tcp.RetransSegs, buf+6, 6, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETTCPRETRANS = {"NETTCPRETRANS", sysprt_NETTCPRETRANS}; /*******************************************************************/ char * sysprt_NETTCPINERR(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="tcpie "; val2valstr(sstat->net.tcp.InErrs, buf+6, 6, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETTCPINERR = {"NETTCPINERR", sysprt_NETTCPINERR}; /*******************************************************************/ char * sysprt_NETTCPORESET(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="tcpor "; val2valstr(sstat->net.tcp.OutRsts, buf+6, 6, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETTCPORESET = {"NETTCPORESET", sysprt_NETTCPORESET}; /*******************************************************************/ char * sysprt_NETUDPNOPORT(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="udpnp "; val2valstr(sstat->net.udpv4.NoPorts, buf+6, 6, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETUDPNOPORT = {"NETUDPNOPORT", sysprt_NETUDPNOPORT}; /*******************************************************************/ char * sysprt_NETUDPINERR(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="udpie "; val2valstr(sstat->net.udpv4.InErrors, buf+6, 6, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETUDPINERR = {"NETUDPINERR", sysprt_NETUDPINERR}; /*******************************************************************/ char * sysprt_NETUDPI(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="udpi "; count_t udpin = sstat->net.udpv4.InDatagrams + sstat->net.udpv6.Udp6InDatagrams; val2valstr(udpin, buf+5, 7, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETUDPI = {"NETUDPI", sysprt_NETUDPI}; /*******************************************************************/ char * sysprt_NETUDPO(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="udpo "; count_t udpout = sstat->net.udpv4.OutDatagrams + sstat->net.udpv6.Udp6OutDatagrams; val2valstr(udpout, buf+5, 7, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETUDPO = {"NETUDPO", sysprt_NETUDPO}; /*******************************************************************/ char * sysprt_NETNETWORK(void *p, void *notused, int badness, int *color) { return "network "; } sys_printdef syspdef_NETNETWORK = {"NETNETWORK", sysprt_NETNETWORK}; /*******************************************************************/ char * sysprt_NETIPI(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="ipi "; count_t ipin = sstat->net.ipv4.InReceives + sstat->net.ipv6.Ip6InReceives; val2valstr(ipin, buf+4, 8, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETIPI = {"NETIPI", sysprt_NETIPI}; /*******************************************************************/ char * sysprt_NETIPO(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="ipo "; count_t ipout = sstat->net.ipv4.OutRequests + sstat->net.ipv6.Ip6OutRequests; val2valstr(ipout, buf+4, 8, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETIPO = {"NETIPO", sysprt_NETIPO}; /*******************************************************************/ char * sysprt_NETIPFRW(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="ipfrw "; count_t ipfrw = sstat->net.ipv4.ForwDatagrams + sstat->net.ipv6.Ip6OutForwDatagrams; val2valstr(ipfrw, buf+6, 6, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETIPFRW = {"NETIPFRW", sysprt_NETIPFRW}; /*******************************************************************/ char * sysprt_NETIPDELIV(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="deliv "; count_t ipindel = sstat->net.ipv4.InDelivers + sstat->net.ipv6.Ip6InDelivers; val2valstr(ipindel, buf+6, 6, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETIPDELIV = {"NETIPDELIV", sysprt_NETIPDELIV}; /*******************************************************************/ char * sysprt_NETICMPIN(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="icmpi "; count_t icmpin = sstat->net.icmpv4.InMsgs+ sstat->net.icmpv6.Icmp6InMsgs; val2valstr(icmpin , buf+6, 6, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETICMPIN = {"NETICMPIN", sysprt_NETICMPIN}; /*******************************************************************/ char * sysprt_NETICMPOUT(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="icmpo "; count_t icmpin = sstat->net.icmpv4.OutMsgs+ sstat->net.icmpv6.Icmp6OutMsgs; val2valstr(icmpin , buf+6, 6, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETICMPOUT = {"NETICMPOUT", sysprt_NETICMPOUT}; /*******************************************************************/ char * sysprt_NETNAME(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; count_t busy; count_t ival = sstat->intf.intf[as->index].rbyte/125/as->nsecs; count_t oval = sstat->intf.intf[as->index].sbyte/125/as->nsecs; static char buf[16] = "ethxxxx ----"; // 012345678901 *color = -1; if (sstat->intf.intf[as->index].speed) /* speed known? */ { if (sstat->intf.intf[as->index].duplex) busy = (ival > oval ? ival : oval) / (sstat->intf.intf[as->index].speed *10); else busy = (ival + oval) / (sstat->intf.intf[as->index].speed *10); // especially with wireless, the speed might have dropped // temporarily to a very low value (snapshot) // then it might be better to take the speed of the previous // sample if (busy > 100 && sstat->intf.intf[as->index].speed < sstat->intf.intf[as->index].speedp) { sstat->intf.intf[as->index].speed = sstat->intf.intf[as->index].speedp; if (sstat->intf.intf[as->index].duplex) busy = (ival > oval ? ival : oval) / (sstat->intf.intf[as->index].speed *10); else busy = (ival + oval) / (sstat->intf.intf[as->index].speed *10); } snprintf(buf, sizeof(buf)-1, "%-7.7s %3lld%%", sstat->intf.intf[as->index].name, busy); } else { snprintf(buf, sizeof(buf)-1, "%-7.7s ----", sstat->intf.intf[as->index].name); strcpy(buf+8, "----"); } return buf; } sys_printdef syspdef_NETNAME = {"NETNAME", sysprt_NETNAME}; /*******************************************************************/ char * sysprt_NETPCKI(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="pcki "; *color = -1; val2valstr(sstat->intf.intf[as->index].rpack, buf+5, 7, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETPCKI = {"NETPCKI", sysprt_NETPCKI}; /*******************************************************************/ char * sysprt_NETPCKO(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="pcko "; *color = -1; val2valstr(sstat->intf.intf[as->index].spack, buf+5, 7, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETPCKO = {"NETPCKO", sysprt_NETPCKO}; /*******************************************************************/ /* ** convert byte-transfers to bit-transfers (* 8) ** convert bit-transfers to kilobit-transfers (/ 1000) ** per second */ char *makenetspeed(count_t val, int nsecs) { char c; static char buf[16]="si ?bps"; // 012345678901 val=val/125/nsecs; // convert to Kbps if (val < 10000) { c='K'; } else if (val < (count_t)10000 * 1000) { val/=1000; c = 'M'; } else if (val < (count_t)10000 * 1000 * 1000) { val/=1000 * 1000; c = 'G'; } else { val = val / 1000 / 1000 / 1000; c = 'T'; } sprintf(buf+3, "%4lld %cbps", val, c); return buf; } /*******************************************************************/ char * sysprt_NETSPEEDMAX(void *p, void *q, int badness, int *color) { struct sstat *sstat = p; extraparam *as = q; static char buf[16]; count_t speed = sstat->intf.intf[as->index].speed; *color = -1; if (speed < 10000) { snprintf(buf, sizeof buf, "sp %4lld Mbps", speed); } else { speed /= 1000; snprintf(buf, sizeof buf, "sp %4lld Gbps", speed); } return buf; } sys_printdef syspdef_NETSPEEDMAX = {"NETSPEEDMAX", sysprt_NETSPEEDMAX}; /*******************************************************************/ char * sysprt_NETSPEEDIN(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; *color = -1; char *ps=makenetspeed(sstat->intf.intf[as->index].rbyte,as->nsecs); ps[0]='s'; ps[1]='i'; return ps; } sys_printdef syspdef_NETSPEEDIN = {"NETSPEEDIN", sysprt_NETSPEEDIN}; /*******************************************************************/ char * sysprt_NETSPEEDOUT(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; *color = -1; char *ps=makenetspeed(sstat->intf.intf[as->index].sbyte,as->nsecs); ps[0]='s'; ps[1]='o'; return ps; } sys_printdef syspdef_NETSPEEDOUT = {"NETSPEEDOUT", sysprt_NETSPEEDOUT}; /*******************************************************************/ char * sysprt_NETCOLLIS(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="coll "; val2valstr(sstat->intf.intf[as->index].scollis, buf+5, 7, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETCOLLIS = {"NETCOLLIS", sysprt_NETCOLLIS}; /*******************************************************************/ char * sysprt_NETMULTICASTIN(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="mlti "; val2valstr(sstat->intf.intf[as->index].rmultic, buf+5, 7, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETMULTICASTIN = {"NETMULTICASTIN", sysprt_NETMULTICASTIN}; /*******************************************************************/ char * sysprt_NETRCVERR(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="erri "; val2valstr(sstat->intf.intf[as->index].rerrs, buf+5, 7, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETRCVERR = {"NETRCVERR", sysprt_NETRCVERR}; /*******************************************************************/ char * sysprt_NETSNDERR(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="erro "; val2valstr(sstat->intf.intf[as->index].serrs, buf+5, 7, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETSNDERR = {"NETSNDERR", sysprt_NETSNDERR}; /*******************************************************************/ char * sysprt_NETRCVDROP(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="drpi "; val2valstr(sstat->intf.intf[as->index].rdrop, buf+5, 7, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETRCVDROP = {"NETRCVDROP", sysprt_NETRCVDROP}; /*******************************************************************/ char * sysprt_NETSNDDROP(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="drpo "; val2valstr(sstat->intf.intf[as->index].sdrop, buf+5, 7, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NETSNDDROP = {"NETSNDDROP", sysprt_NETSNDDROP}; /*******************************************************************/ char * sysprt_IFBNAME(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; count_t busy; count_t ival = sstat->ifb.ifb[as->index].rcvb/125/as->nsecs; count_t oval = sstat->ifb.ifb[as->index].sndb/125/as->nsecs; int len; static char buf[16] = "ethxxxx ----", tmp[32], *ps=tmp; // 012345678901 *color = -1; busy = (ival > oval ? ival : oval) * sstat->ifb.ifb[as->index].lanes / (sstat->ifb.ifb[as->index].rate * 10); snprintf(tmp, sizeof tmp, "%s/%d", sstat->ifb.ifb[as->index].ibname, sstat->ifb.ifb[as->index].portnr); len = strlen(ps); if (len > 7) ps = ps + len - 7; snprintf(buf, sizeof buf, "%-7.7s %3lld%%", ps, busy); return buf; } sys_printdef syspdef_IFBNAME = {"IFBNAME", sysprt_IFBNAME}; /*******************************************************************/ char * sysprt_IFBPCKI(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="pcki "; *color = -1; val2valstr(sstat->ifb.ifb[as->index].rcvp, buf+5, 7, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_IFBPCKI = {"IFBPCKI", sysprt_IFBPCKI}; /*******************************************************************/ char * sysprt_IFBPCKO(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="pcko "; *color = -1; val2valstr(sstat->ifb.ifb[as->index].sndp, buf+5, 7, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_IFBPCKO = {"IFBPCKO", sysprt_IFBPCKO}; /*******************************************************************/ char * sysprt_IFBSPEEDMAX(void *p, void *q, int badness, int *color) { struct sstat *sstat = p; extraparam *as = q; static char buf[16]; count_t rate = sstat->ifb.ifb[as->index].rate; *color = -1; if (rate < 10000) { snprintf(buf, sizeof buf, "sp %4lld Mbps", rate); } else { rate /= 1000; snprintf(buf, sizeof buf, "sp %4lld Gbps", rate); } return buf; } sys_printdef syspdef_IFBSPEEDMAX = {"IFBSPEEDMAX", sysprt_IFBSPEEDMAX}; /*******************************************************************/ char * sysprt_IFBLANES(void *p, void *q, int badness, int *color) { struct sstat *sstat = p; extraparam *as = q; static char buf[16]="lanes "; val2valstr(sstat->ifb.ifb[as->index].lanes, buf+6, 6, 0, 0); return buf; } sys_printdef syspdef_IFBLANES = {"IFBLANES", sysprt_IFBLANES}; /*******************************************************************/ char * sysprt_IFBSPEEDIN(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; *color = -1; char *ps=makenetspeed(sstat->ifb.ifb[as->index].rcvb * sstat->ifb.ifb[as->index].lanes, as->nsecs); ps[0]='s'; ps[1]='i'; return ps; } sys_printdef syspdef_IFBSPEEDIN = {"IFBSPEEDIN", sysprt_IFBSPEEDIN}; /*******************************************************************/ char * sysprt_IFBSPEEDOUT(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; *color = -1; char *ps=makenetspeed(sstat->ifb.ifb[as->index].sndb * sstat->ifb.ifb[as->index].lanes, as->nsecs); ps[0]='s'; ps[1]='o'; return ps; } sys_printdef syspdef_IFBSPEEDOUT = {"IFBSPEEDOUT", sysprt_IFBSPEEDOUT}; /*******************************************************************/ char * sysprt_NFMSERVER(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16] = "srv "; char mntdev[128], *ps; memcpy(mntdev, sstat->nfs.nfsmounts.nfsmnt[as->index].mountdev, sizeof mntdev); if ( (ps = strchr(mntdev, ':')) ) // colon found? *ps = '\0'; else strcpy(mntdev, "?"); sprintf(buf+4, "%8.8s", mntdev); return buf; } sys_printdef syspdef_NFMSERVER = {"NFMSERVER", sysprt_NFMSERVER}; /*******************************************************************/ char * sysprt_NFMPATH(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]; char mntdev[128], *ps; int len; memcpy(mntdev, sstat->nfs.nfsmounts.nfsmnt[as->index].mountdev, sizeof mntdev); if ( (ps = strchr(mntdev, ':')) ) // colon found? ps++; else ps = mntdev; len = strlen(ps); if (len > 12) ps = ps + len - 12; sprintf(buf, "%12.12s", ps); return buf; } sys_printdef syspdef_NFMPATH = {"NFMPATH", sysprt_NFMPATH}; /*******************************************************************/ char * sysprt_NFMTOTREAD(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="read "; val2memstr(sstat->nfs.nfsmounts.nfsmnt[as->index].bytestotread, buf+6, KBFORMAT, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFMTOTREAD = {"NFMTOTREAD", sysprt_NFMTOTREAD}; /*******************************************************************/ char * sysprt_NFMTOTWRITE(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="write "; val2memstr(sstat->nfs.nfsmounts.nfsmnt[as->index].bytestotwrite, buf+6, KBFORMAT, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFMTOTWRITE = {"NFMTOTWRITE", sysprt_NFMTOTWRITE}; /*******************************************************************/ char * sysprt_NFMNREAD(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="nread "; val2memstr(sstat->nfs.nfsmounts.nfsmnt[as->index].bytesread, buf+6, KBFORMAT, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFMNREAD = {"NFMNREAD", sysprt_NFMNREAD}; /*******************************************************************/ char * sysprt_NFMNWRITE(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="nwrit "; val2memstr(sstat->nfs.nfsmounts.nfsmnt[as->index].byteswrite, buf+6, KBFORMAT, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFMNWRITE = {"NFMNWRITE", sysprt_NFMNWRITE}; /*******************************************************************/ char * sysprt_NFMDREAD(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="dread "; val2memstr(sstat->nfs.nfsmounts.nfsmnt[as->index].bytesdread, buf+6, KBFORMAT, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFMDREAD = {"NFMDREAD", sysprt_NFMDREAD}; /*******************************************************************/ char * sysprt_NFMDWRITE(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="dwrit "; val2memstr(sstat->nfs.nfsmounts.nfsmnt[as->index].bytesdwrite, buf+6, KBFORMAT, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFMDWRITE = {"NFMDWRITE", sysprt_NFMDWRITE}; /*******************************************************************/ char * sysprt_NFMMREAD(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="mread "; val2memstr(sstat->nfs.nfsmounts.nfsmnt[as->index].pagesmread *pagesize, buf+6, KBFORMAT, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFMMREAD = {"NFMMREAD", sysprt_NFMMREAD}; /*******************************************************************/ char * sysprt_NFMMWRITE(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="mwrit "; val2memstr(sstat->nfs.nfsmounts.nfsmnt[as->index].pagesmwrite *pagesize, buf+6, KBFORMAT, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFMMWRITE = {"NFMMWRITE", sysprt_NFMMWRITE}; /*******************************************************************/ char * sysprt_NFCRPCCNT(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="rpc "; val2valstr(sstat->nfs.client.rpccnt, buf+4, 8, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFCRPCCNT = {"NFCRPCCNT", sysprt_NFCRPCCNT}; /*******************************************************************/ char * sysprt_NFCRPCREAD(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="read "; val2valstr(sstat->nfs.client.rpcread, buf+5, 7, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFCRPCREAD = {"NFCRPCREAD", sysprt_NFCRPCREAD}; /*******************************************************************/ char * sysprt_NFCRPCWRITE(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="write "; val2valstr(sstat->nfs.client.rpcwrite, buf+6, 6, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFCRPCWRITE = {"NFCRPCWRITE", sysprt_NFCRPCWRITE}; /*******************************************************************/ char * sysprt_NFCRPCRET(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="retxmit "; val2valstr(sstat->nfs.client.rpcretrans, buf+8, 4, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFCRPCRET = {"NFCRPCRET", sysprt_NFCRPCRET}; /*******************************************************************/ char * sysprt_NFCRPCARF(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="autref "; val2valstr(sstat->nfs.client.rpcautrefresh, buf+7, 5, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFCRPCARF = {"NFCRPCARF", sysprt_NFCRPCARF}; /*******************************************************************/ char * sysprt_NFSRPCCNT(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="rpc "; val2valstr(sstat->nfs.server.rpccnt, buf+4, 8, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFSRPCCNT = {"NFSRPCCNT", sysprt_NFSRPCCNT}; /*******************************************************************/ char * sysprt_NFSRPCREAD(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="cread "; val2valstr(sstat->nfs.server.rpcread, buf+6, 6, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFSRPCREAD = {"NFSRPCREAD", sysprt_NFSRPCREAD}; /*******************************************************************/ char * sysprt_NFSRPCWRITE(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="cwrit "; val2valstr(sstat->nfs.server.rpcwrite, buf+6, 6, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFSRPCWRITE = {"NFSRPCWRITE", sysprt_NFSRPCWRITE}; /*******************************************************************/ char * sysprt_NFSBADFMT(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="badfmt "; val2valstr(sstat->nfs.server.rpcbadfmt, buf+7, 5, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFSBADFMT = {"NFSBADFMT", sysprt_NFSBADFMT}; /*******************************************************************/ char * sysprt_NFSBADAUT(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="badaut "; val2valstr(sstat->nfs.server.rpcbadaut, buf+7, 5, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFSBADAUT = {"NFSBADAUT", sysprt_NFSBADAUT}; /*******************************************************************/ char * sysprt_NFSBADCLN(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="badcln "; val2valstr(sstat->nfs.server.rpcbadcln, buf+7, 5, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFSBADCLN = {"NFSBADCLN", sysprt_NFSBADCLN}; /*******************************************************************/ char * sysprt_NFSNETTCP(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="nettcp "; val2valstr(sstat->nfs.server.nettcpcnt, buf+7, 5, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFSNETTCP = {"NFSNETTCP", sysprt_NFSNETTCP}; /*******************************************************************/ char * sysprt_NFSNETUDP(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="netudp "; val2valstr(sstat->nfs.server.netudpcnt, buf+7, 5, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFSNETUDP = {"NFSNETUDP", sysprt_NFSNETUDP}; /*******************************************************************/ char * sysprt_NFSNRBYTES(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[32]="MBcr/s "; sprintf(buf+7, "%5.1lf", sstat->nfs.server.nrbytes / 1024.0 / 1024.0 / as->nsecs); return buf; } sys_printdef syspdef_NFSNRBYTES = {"NFSNRBYTES", sysprt_NFSNRBYTES}; /*******************************************************************/ char * sysprt_NFSNWBYTES(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[32]="MBcw/s "; sprintf(buf+7, "%5.1lf", sstat->nfs.server.nwbytes / 1024.0 / 1024.0 / as->nsecs); return buf; } sys_printdef syspdef_NFSNWBYTES = {"NFSNWBYTES", sysprt_NFSNWBYTES}; /*******************************************************************/ char * sysprt_NFSRCHITS(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="rchits "; val2valstr(sstat->nfs.server.rchits, buf+8, 4, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFSRCHITS = {"NFSRCHITS", sysprt_NFSRCHITS}; /*******************************************************************/ char * sysprt_NFSRCMISS(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="rcmiss "; val2valstr(sstat->nfs.server.rcmiss, buf+8, 4, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFSRCMISS = {"NFSRCMISS", sysprt_NFSRCMISS}; /*******************************************************************/ char * sysprt_NFSRCNOCA(void *p, void *q, int badness, int *color) { struct sstat *sstat=p; extraparam *as=q; static char buf[16]="rcnoca "; val2valstr(sstat->nfs.server.rcnoca, buf+8, 4, as->avgval, as->nsecs); return buf; } sys_printdef syspdef_NFSRCNOCA = {"NFSRCNOCA", sysprt_NFSRCNOCA}; /*******************************************************************/ char * sysprt_BLANKBOX(void *p, void *notused, int badness, int *color) { return " "; } sys_printdef syspdef_BLANKBOX = {"BLANKBOX", sysprt_BLANKBOX}; atop-2.4.0/various.c0000664000203100020310000003311213416466037013630 0ustar gerlofgerlof/* ** 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 various functions to a.o. format the ** time-of-day, the cpu-time consumption and the memory-occupation. ** ========================================================================== ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl ** Date: November 1996 ** LINUX-port: June 2000 ** -------------------------------------------------------------------------- ** Copyright (C) 2000-2010 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 ** -------------------------------------------------------------------------- ** ** $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 #include #include #include #include #include #include #include #include #include #include #include #include #include "atop.h" #include "acctproc.h" /* ** Function convtime() converts a value (number of seconds since ** 1-1-1970) to an ascii-string in the format hh:mm:ss, stored in ** chartim (9 bytes long). */ char * convtime(time_t utime, char *chartim) { struct tm *tt; tt = localtime(&utime); sprintf(chartim, "%02d:%02d:%02d", tt->tm_hour, tt->tm_min, tt->tm_sec); return chartim; } /* ** Function convdate() converts a value (number of seconds since ** 1-1-1970) to an ascii-string in the format yyyy/mm/dd, stored in ** chardat (11 bytes long). */ char * convdate(time_t utime, char *chardat) { struct tm *tt; tt = localtime(&utime); sprintf(chardat, "%04d/%02d/%02d", tt->tm_year+1900, tt->tm_mon+1, tt->tm_mday); return chardat; } /* ** Convert a hh:mm string into a number of seconds since 00:00 ** ** Return-value: 0 - Wrong input-format ** 1 - Success */ int hhmm2secs(char *itim, unsigned int *otim) { register int i; int hours, minutes; /* ** check string syntax */ for (i=0; *(itim+i); i++) if ( !isdigit(*(itim+i)) && *(itim+i) != ':' ) return(0); sscanf(itim, "%d:%d", &hours, &minutes); if ( hours < 0 || hours > 23 || minutes < 0 || minutes > 59 ) return(0); *otim = (hours * 3600) + (minutes * 60); if (*otim >= SECSDAY) *otim = SECSDAY-1; return(1); } /* ** Return number of seconds since midnight according local clock time ** ** Return-value: Number of seconds */ int daysecs(time_t itime) { struct tm *tt; tt = localtime(&itime); return( (tt->tm_hour*3600) + (tt->tm_min*60) ); } /* ** Function val2valstr() converts a positive value to an ascii-string of a ** fixed number of positions; if the value does not fit, it will be formatted ** to exponent-notation (as short as possible, so not via the standard printf- ** formatters %f or %e). The offered string should have a length of width+1. ** The value might even be printed as an average for the interval-time. */ char * val2valstr(count_t value, char *strvalue, int width, int avg, int nsecs) { count_t maxval, remain = 0; int exp = 0; char *suffix = ""; if (avg && nsecs) { value = (value + (nsecs/2)) / nsecs; /* rounded value */ width = width - 2; /* subtract two positions for '/s' */ suffix = "/s"; } if (value < 0) // no negative value expected { sprintf(strvalue, "%*s%s", width, "?", suffix); return strvalue; } maxval = pow(10.0, width) - 1; if (value < maxval) { sprintf(strvalue, "%*lld%s", width, value, suffix); } else { if (width < 3) { /* ** cannot avoid ignoring width */ sprintf(strvalue, "%lld%s", value, suffix); } else { /* ** calculate new maximum value for the string, ** calculating space for 'e' (exponent) + one digit */ width -= 2; maxval = pow(10.0, width) - 1; while (value > maxval) { exp++; remain = value % 10; value /= 10; } if (remain >= 5) value++; sprintf(strvalue, "%*llde%d%s", width, value, exp, suffix); } } return strvalue; } #define DAYSECS (24*60*60) #define HOURSECS (60*60) #define MINSECS (60) /* ** Function val2elapstr() converts a value (number of seconds) ** to an ascii-string of up to max 13 positions in NNNdNNhNNmNNs ** stored in strvalue (at least 14 positions). ** returnvalue: number of bytes stored */ int val2elapstr(int value, char *strvalue) { char *p=strvalue; if (value >= DAYSECS) { p+=sprintf(p, "%dd", value/DAYSECS); } if (value >= HOURSECS) { p+=sprintf(p, "%dh", (value%DAYSECS)/HOURSECS); } if (value >= MINSECS) { p+=sprintf(p, "%dm", (value%HOURSECS)/MINSECS); } p+=sprintf(p, "%ds", (value%MINSECS)); return p-strvalue; } /* ** Function val2cpustr() converts a value (number of milliseconds) ** to an ascii-string of 6 positions in milliseconds or minute-seconds or ** hours-minutes, stored in strvalue (at least 7 positions). */ #define MAXMSEC (count_t)100000 #define MAXSEC (count_t)6000 #define MAXMIN (count_t)6000 char * val2cpustr(count_t value, char *strvalue) { if (value < MAXMSEC) { sprintf(strvalue, "%2lld.%02llds", value/1000, value%1000/10); } else { /* ** millisecs irrelevant; round to seconds */ value = (value + 500) / 1000; if (value < MAXSEC) { sprintf(strvalue, "%2lldm%02llds", value/60, value%60); } else { /* ** seconds irrelevant; round to minutes */ value = (value + 30) / 60; if (value < MAXMIN) { sprintf(strvalue, "%2lldh%02lldm", value/60, value%60); } else { /* ** minutes irrelevant; round to hours */ value = (value + 30) / 60; sprintf(strvalue, "%2lldd%02lldh", value/24, value%24); } } } return strvalue; } /* ** Function val2Hzstr() converts a value (in MHz) ** to an ascii-string. ** The result-string is placed in the area pointed to strvalue, ** which should be able to contain 7 positions plus null byte. */ char * val2Hzstr(count_t value, char *strvalue) { char *fformat; if (value < 1000) { sprintf(strvalue, "%4lldMHz", value); } else { double fval=value/1000.0; // fval is double in GHz char prefix='G'; if (fval >= 1000.0) // prepare for the future { prefix='T'; fval /= 1000.0; } if (fval < 10.0) { fformat = "%4.2f%cHz"; } else { if (fval < 100.0) fformat = "%4.1f%cHz"; else fformat = "%4.0f%cHz"; } sprintf(strvalue, fformat, fval, prefix); } return strvalue; } /* ** Function val2memstr() converts a value (number of bytes) ** to an ascii-string in a specific format (indicated by pformat). ** The result-string is placed in the area pointed to strvalue, ** which should be able to contain at least 7 positions. */ #define ONEKBYTE 1024 #define ONEMBYTE 1048576 #define ONEGBYTE 1073741824L #define ONETBYTE 1099511627776LL #define ONEPBYTE 1125899906842624LL #define MAXBYTE 1024 #define MAXKBYTE ONEKBYTE*99999L #define MAXMBYTE ONEMBYTE*999L #define MAXGBYTE ONEGBYTE*999LL #define MAXTBYTE ONETBYTE*999LL char * val2memstr(count_t value, char *strvalue, int pformat, int avgval, int nsecs) { char aformat; /* advised format */ count_t verifyval; char *suffix = ""; int basewidth = 6; /* ** notice that the value can be negative, in which case the ** modulo-value should be evaluated and an extra position should ** be reserved for the sign */ if (value < 0) verifyval = -value * 10; else verifyval = value; /* ** verify if printed value is required per second (average) or total */ if (avgval && nsecs) { value /= nsecs; verifyval = verifyval * 100 /nsecs; basewidth -= 2; suffix = "/s"; } /* ** determine which format will be used on bases of the value itself */ if (verifyval <= MAXBYTE) /* bytes ? */ aformat = ANYFORMAT; else if (verifyval <= MAXKBYTE) /* kbytes ? */ aformat = KBFORMAT; else if (verifyval <= MAXMBYTE) /* mbytes ? */ aformat = MBFORMAT; else if (verifyval <= MAXGBYTE) /* gbytes ? */ aformat = GBFORMAT; else if (verifyval <= MAXTBYTE)/* tbytes? */ aformat = TBFORMAT;/* tbytes! */ else aformat = PBFORMAT;/* pbytes! */ /* ** check if this is also the preferred format */ if (aformat <= pformat) aformat = pformat; switch (aformat) { case ANYFORMAT: sprintf(strvalue, "%*lld%s", basewidth, value, suffix); break; case KBFORMAT: sprintf(strvalue, "%*lldK%s", basewidth-1, value/ONEKBYTE, suffix); break; case MBFORMAT: sprintf(strvalue, "%*.1lfM%s", basewidth-1, (double)((double)value/ONEMBYTE), suffix); break; case GBFORMAT: sprintf(strvalue, "%*.1lfG%s", basewidth-1, (double)((double)value/ONEGBYTE), suffix); break; case TBFORMAT: sprintf(strvalue, "%*.1lfT%s", basewidth-1, (double)((double)value/ONETBYTE), suffix); break; case PBFORMAT: sprintf(strvalue, "%*.1lfP%s", basewidth-1, (double)((double)value/ONEPBYTE), suffix); break; default: sprintf(strvalue, "!TILT!"); } return strvalue; } /* ** Function numeric() checks if the ascii-string contains ** a numeric (positive) value. ** Returns 1 (true) if so, or 0 (false). */ int numeric(char *ns) { register char *s = ns; while (*s) if (*s < '0' || *s > '9') return(0); /* false */ else s++; return(1); /* true */ } /* ** Function getboot() returns the boot-time of this system ** as number of jiffies since 1-1-1970. */ unsigned long long getboot(void) { static unsigned long long boottime; unsigned long long getbootlinux(long); if (!boottime) /* do this only once */ boottime = getbootlinux(hertz); return boottime; } /* ** generic pointer verification after malloc */ void ptrverify(const void *ptr, const char *errormsg, ...) { if (!ptr) { va_list args; acctswoff(); netatop_signoff(); if (vis.show_end) (vis.show_end)(); va_start(args, errormsg); vfprintf(stderr, errormsg, args); va_end (args); exit(13); } } /* ** signal catcher for cleanup before exit */ void cleanstop(int exitcode) { acctswoff(); netatop_signoff(); (vis.show_end)(); exit(exitcode); } /* ** drop the root privileges that might be obtained via setuid-bit ** ** this action may only fail with errno EPERM (normal situation when ** atop has not been started with setuid-root privs); when this ** action fails with EAGAIN or ENOMEM, atop should not continue ** without root privs being dropped... */ int droprootprivs(void) { if (seteuid( getuid() ) == -1 && errno != EPERM) return 0; /* false */ else return 1; /* true */ } /* ** regain the root privileges that might be dropped earlier */ void regainrootprivs(void) { seteuid(0); } atop-2.4.0/versdate.h0000664000203100020310000000004713416466037013763 0ustar gerlofgerlof#define ATOPDATE "2019/01/12 20:37:57" atop-2.4.0/version.c0000664000203100020310000000102313416466037013621 0ustar gerlofgerlof/* No manual changes in this file */ #include #include #include "version.h" #include "versdate.h" static char atopversion[] = ATOPVERS; static char atopdate[] = ATOPDATE; char * getstrvers(void) { static char vers[256]; snprintf(vers, sizeof vers, "Version: %s - %s ", atopversion, atopdate); return vers; } unsigned short getnumvers(void) { int vers1, vers2; sscanf(atopversion, "%u.%u", &vers1, &vers2); return (unsigned short) ((vers1 << 8) + vers2); } atop-2.4.0/version.h0000664000203100020310000000003113416466037013624 0ustar gerlofgerlof#define ATOPVERS "2.4.0" atop-2.4.0/ChangeLog0000664000203100020310000023725513416466037013564 0ustar gerlofgerlofcommit 3ca52a7c0c9948eedd6ba25a1a902ebc6488a79f Author: Gerlof Langeveld Date: Sat Jan 12 22:31:10 2019 +0100 Prepare for version 2.4 M README.md M version.h commit 1929641c525c259bbc2563fa979ecb97063b219e Author: Gerlof Langeveld Date: Sat Jan 12 20:03:41 2019 +0100 Support for conversion of raw files to atop 2.4 M atopconvert.c M man/atopconvert.1 M photoproc.h M photosyst.h A prev/photoproc_24.h A prev/photosyst_24.h commit 46000ef14ff2cbd755d4e1b620e68218ea55f81f Author: Gerlof Langeveld Date: Sat Jan 12 13:13:37 2019 +0100 Introduction of Pressure Stall Information (PSI). The average percentages of CPU, memory and I/O are reported, as provided by kernel 4.20 onwards. M atopsar.c M deviate.c M man/atop.1 M man/atopsar.1 M parseable.c M photosyst.c M photosyst.h M showlinux.c M showlinux.h M showsys.c commit 00ffc2f338ee038e3775846b7471228935afcf54 Author: Gerlof Langeveld Date: Thu Jan 10 18:56:52 2019 +0100 Introduction of Infiniband statistics Maintain stats about bandwidth utilization of Infiniband ports, with atopsar (-h) and in atop system statistics. M atop.c M atop.h M atopsar.c M deviate.c M gpucom.c M man/atop.1 M man/atopconvert.1 M man/atopgpud.8 M man/atoprc.5 M man/atopsar.1 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 2f71beced5f061cb1b0b783e0ede3c85e8e54b35 Author: Gerlof Langeveld Date: Tue Jan 8 20:12:00 2019 +0100 Introduction of GPU statistics A separate daemon 'atopgpud' has been developed to maintain statistics of Nvidia GPUs in the system. When this daemon is running, atop will connect to this daemon via a TCP socket. With every intreval, atop gets GPU statistics from the daemon. M Makefile M atop.c M atop.h A atopgpu.service A atopgpud M atopsar.c M deviate.c A gpucom.c A gpucom.h A man/atopgpud.8 M parseable.c M photoproc.c M photoproc.h M photosyst.h M rawlog.c M rpmspec/atop.specsystemd M showgeneric.c M showgeneric.h M showlinux.c M showlinux.h M showprocs.c M showsys.c commit 8fe68ff3ed14bd25da93ba0480ec116a7f36b731 Author: Gerlof Langeveld Date: Thu Jan 3 13:30:42 2019 +0100 Performance improvement when gathering scaling info of CPUs Retrieving the frequency scaling information for every single CPU on a system with lots of CPUs is extremely time consuming. Therefore, frequency scaling info is only gathered on systems with 8 CPUs or less. M photosyst.c commit 4297811aa2815b247e320a00236f0650e449c328 Author: Gerlof Langeveld Date: Thu Jan 3 13:26:07 2019 +0100 Performance improvement for gathering process/thread stats Gathering the process and threads statistics was too time consuming, especially for the first interval. This was extremely noticeable on systems with a lot of multi-threaded processes. M atop.c M photoproc.c M photoproc.h commit a11bf6746c7998eee7ca4b9204b536062948f91c Merge: 725dc2c 0e43049 Author: Gerlof Langeveld Date: Sat Dec 8 14:29:47 2018 +0100 Merge pull request #43 from vinc17fr/master Fixed va_list usage. commit 725dc2cb0b2785a4fa77a98a5a204c977c2a6b53 Author: Gerlof Langeveld Date: Sat Dec 8 14:25:06 2018 +0100 Removed debugging statements M Makefile commit d858714ffb0e11ea88aa582d16bb2c948a3e2fce Author: Gerlof Langeveld Date: Sat Dec 8 14:24:21 2018 +0100 Removed debugging statements M acctproc.c M atop.c commit 1a2fbeaa823f102e988a74123b660598f143d353 Author: Gerlof Langeveld Date: Thu Dec 6 21:48:49 2018 +0100 Only lock atop in memory when the hard and soft limits could be raised. M atop.c commit 0e43049493e65b412e1c0def62a09ceac2bb3110 Author: Vincent Lefevre Date: Tue Dec 4 14:17:46 2018 +0100 Fixed va_list usage. M atopconvert.c M various.c commit b5e7e1cad051e909824ddc12cd82b6e8269d114e Author: Gerlof Langeveld Date: Sun Dec 2 07:49:58 2018 +0100 Added additional debug statements. M acctproc.c commit 7051f61691e1be8bf06a1301dda21236d60e9dc1 Author: Gerlof Langeveld Date: Sat Dec 1 20:21:48 2018 +0100 Consistent type usage for number of processes present and terminated M Makefile M acctproc.c M acctproc.h M atop.c M deviate.c M photoproc.c M photoproc.h commit e163fda6396b854adfbe027380444d0402e315e9 Merge: 2fd27e4 bae7b24 Author: Gerlof Langeveld Date: Sat Dec 1 18:44:16 2018 +0100 Merge pull request #42 from vinc17fr/master Fixed type mismatch in format string. commit bae7b244b87b1af4dc0db4bc3a59532cb88cab5d Author: Vincent Lefevre Date: Mon Nov 19 14:22:16 2018 +0100 Fixed type mismatch in format string. M deviate.c commit e9a2c492f250700ed352a650d255b60deea5c18f Author: Vincent Lefevre Date: Mon Nov 19 14:04:01 2018 +0100 Fixed type mismatch in format string. M atop.c commit 2fd27e47d70920c4c61a54c311c229e11a93c9d6 Author: Gerlof Langeveld Date: Tue Oct 9 14:00:25 2018 +0200 Removed rcsid from source files. M acctproc.c M atop.c M atopsar.c M deviate.c M photoproc.c M photosyst.c M procdbase.c M showgeneric.c M showlinux.c M showprocs.c M showsys.c M various.c commit 7f48aa0294bd9be1d25e930fd6269aa78394a74f Author: Gerlof Langeveld Date: Tue Oct 9 13:57:13 2018 +0200 Added atopsar to .gitignore M .gitignore commit 7f75dcaacdc341d9b3c191b47dc4f8bcc120bf3b Author: Gerlof Langeveld Date: Tue Oct 9 13:54:35 2018 +0200 Removed .gitignore from .gitignore A .gitignore commit 2f83c2fc572162ef36659f7715a2d3527b24ef8f Merge: 6fabd47 2c0a960 Author: Gerlof Langeveld Date: Tue Oct 9 13:29:55 2018 +0200 Merge branch 'master' of github.com:Atoptool/atop commit 6fabd477c3d766a294da5fd70cf984ab58b9b9f8 Author: Gerlof Langeveld Date: Tue Oct 9 13:25:26 2018 +0200 Error message and other exit code for chdir/getcwd Previously only exit code 53 is given in case of a failing getcwd or chdir call, without further message. Now an error message is given combined with exit code 53 (current directory can not be saved), 54 (can not switch to /proc) or 55 (can not switch back to former current directory). M photoproc.c M photosyst.c commit 2c0a9606b1596a50489d4deef124d0b349ccbfbb Merge: 9f705ab 414127c Author: Gerlof Langeveld Date: Tue Oct 9 12:41:00 2018 +0200 Merge pull request #35 from SjonHortensius/patch-1 Include sysmacros.h to compile with newer gcc commit 9f705abee3cc757f0ca5403c71bad8c2b2c532b2 Author: Gerlof Langeveld Date: Tue Oct 9 12:39:25 2018 +0200 Removed MAJOR and MINOR macro's for better solution via include M photosyst.c commit 4742978c79d8faf5b519487e11fc25164cb3cb33 Author: Gerlof Langeveld Date: Sat Sep 22 12:10:34 2018 +0200 Document the behavior of signals SIGUSR1 and SIGUSR2 M man/atop.1 commit 7bf30c52a37118ff4f211e67e1736099f3d1dcb3 Author: Gerlof Langeveld Date: Sat Sep 22 11:50:50 2018 +0200 Own macro's added to determine major/minor of logical volume. The standard 'minor' and 'major' macro's are not available any more in gcc8. M photosyst.c commit 20375c1a7a3622ba2fe776e146c1a2dfc6f17fa2 Author: Gerlof Langeveld Date: Sat Sep 15 10:53:37 2018 +0200 Wrong signal number as exit code in parseable output The exit code (or signal number) in the output of the option -PPRG was wrong. Now the value represents the exit code if it is less than 256 and it represents a fatal signal number if the code is larger then 256 (then subtract 256 for the signal number). M man/atop.1 M parseable.c commit 414127c03669b4eedc85778a7bff80cf601311d8 Author: SjonHortensius Date: Fri Aug 24 18:26:58 2018 +0200 Include sysmacros.h to compile with newer gcc Older gcc throws a warning ``` photosyst.c: In function 'lvmmapname': photosyst.c:1465:13: warning: In the GNU C Library, "major" is defined by . For historical compatibility, it is currently defined by as well, but we plan to remove this soon. To use "major", include directly. If you did not intend to use a system-defined macro "major", you should undefine it after including . dmp->major = major(statbuf.st_rdev); ``` Newer gcc throws an error: ``` photosyst.c: In function ‘lvmmapname’: photosyst.c:1482:19: error: called object ‘major’ is not a function or function pointer dmp->major = major(statbuf.st_rdev); ^~~~~ photosyst.c:1437:25: note: declared here lvmmapname(unsigned int major, unsigned int minor, ~~~~~~~~~~~~~^~~~~ ``` M photosyst.c commit 8d2d68c0dc26d457871e120a57b71be91c6dcbd7 Author: Gerlof Langeveld Date: Sun Aug 5 19:34:47 2018 +0200 Added symlink atop.spec A atop.spec commit a891eddaf4d1fca4895dfb296b6092980c147aef Author: Gerlof Langeveld Date: Sun Aug 5 19:31:32 2018 +0200 Cosmetic changes to new tool atopconvert M atopconvert.c commit 21598140df014b38b1c57cdc9303386cbd869f62 Author: Gerlof Langeveld Date: Sun Aug 5 15:58:40 2018 +0200 Finalize the modification to introduce atopconvert M Makefile M atopconvert.c commit 335922298a6b9e788f7b0b8d7582f8ef6878636e Author: Gerlof Langeveld Date: Sun Aug 5 15:48:24 2018 +0200 Modified RPM spec files to install new tool atopconvert M rpmspec/atop.specsystemd M rpmspec/atop.specsysv commit acc29f246900234181abe5641ae67cecf6999dc5 Author: Gerlof Langeveld Date: Sun Aug 5 15:33:31 2018 +0200 Introduce new tool atopconvert to convert raw files The command atopconvert expect the name of an existing raw file as first argument and the name of an output raw file as second argument. The input file will be converted to the output file, which will be by default the raw format of the newest atop version. Raw input raw files created by atop 2.0 and higher are supported. M Makefile A atopconvert.c M man/atop.1 A man/atopconvert.1 A prev/photoproc_20.h A prev/photoproc_21.h A prev/photoproc_22.h A prev/photoproc_23.h A prev/photosyst_20.h A prev/photosyst_21.h A prev/photosyst_22.h A prev/photosyst_23.h commit 25db7dfbecc258757a83c31921e60e295bd48840 Author: Gerlof Langeveld Date: Thu Jul 12 15:04:42 2018 +0200 Adapt man pages to introduce new program atopconvert M man/atop.1 M man/atopsar.1 commit 07aad3dbfc8458eb23213ecaf02ddeaf34b55a35 Author: Gerlof Langeveld Date: Wed Jul 11 09:54:13 2018 +0200 Value of '#proc' should not include exited processes M showsys.c commit 4a104c7377c2f0f694d75b0936f2722bab652e46 Merge: c10ed57 3a8871b Author: Gerlof Langeveld Date: Sat Jun 9 13:40:34 2018 +0200 Merge pull request #21 from Zugschlus/makefile make sure that all rm operations are -f to allow consecutive cleans commit c10ed57346e359dafe80cda8b82ab7bf829fec1b Author: Gerlof Langeveld Date: Sat Jun 9 13:11:51 2018 +0200 Modified URL of atop website M rpmspec/atop.specsystemd M rpmspec/atop.specsysv commit 68180d5e88d4aec665582ea3d9485a89ba29ec67 Author: Gerlof Langeveld Date: Sat Jun 9 13:11:30 2018 +0200 Added depencies to build and run atop M README commit bb23382c17ce228fce315d4c398f29e80dbd34b0 Author: Gerlof Langeveld Date: Sat Jun 9 12:09:55 2018 +0200 Adapt URL in man pages (from http to https) M man/atopacctd.8 M man/atoprc.5 M man/atopsar.1 commit 96287919c311a17ff3c5e3d4b5ebb4507a8ddadf Author: Gerlof Langeveld Date: Sat Jun 9 12:06:49 2018 +0200 Modify default values in atop.daily script Add possibility to override all necessary default values in the atop.daily script, i.e. variable LOGOPTS, LOGINTERVAL and LOGGENERATIONS. M atop.daily M man/atop.1 commit dad4dab702a75b95c8276dbfe199a0d7018f8821 Merge: 2bb5204 a88a541 Author: Gerlof Langeveld Date: Sat Jun 9 10:57:11 2018 +0200 Merge branch 'configurable-options' of git://github.com/Zugschlus/atop commit 2bb5204b93d7649608b2a6525fae3c5e2e71a1e4 Merge: 4516bd3 9d3011d Author: Gerlof Langeveld Date: Sat Jun 9 10:27:53 2018 +0200 Merge pull request #23 from natoscott/master Fix string malloc length in init_proc_prints, check result commit a88a54107142d057e36be15285c972031a0e8c0a Author: Marc Haber Date: Tue Apr 24 11:42:53 2018 +0200 make atop options configurable, introduce config file M atop.daily commit 4516bd3300e7865f8ec1bb69ba80d42928487633 Author: Gerlof Langeveld Date: Mon Apr 23 13:46:23 2018 +0200 Additional rule to make versdate.h file. M Makefile commit 9d3011d6b81bd7f2fa9e07892a2c5f24ee7f4449 Author: Nathan Scott Date: Fri Jan 19 15:40:47 2018 +1100 Fix string malloc length in init_proc_prints, check result M showlinux.c commit 3a8871b1ba108d6ccf46246625983d3f830e998b Author: Marc Haber Date: Sat Dec 30 16:24:42 2017 +0100 make sure that all rm operations are -f to allow consecutive cleans M Makefile commit 2d615475d922ae611f8cc00cdca79ed32bd3ff33 Author: Gerlof Langeveld Date: Sat Dec 16 11:59:31 2017 +0100 Recognize if current system supports PMC event counters. M man/atop.1 M parseable.c M photosyst.c M showsys.c commit db7a23d193415fef62f889f285687910d675b11f Author: Gerlof Langeveld Date: Wed Nov 8 21:26:11 2017 +0100 Remove versdate.h D versdate.h commit de8179c9b483950b633753365a9889f9d4d0d149 Author: Gerlof Langeveld Date: Wed Nov 8 21:25:28 2017 +0100 Make perf_event counter for IPC optional at compile time M Makefile M showsys.c commit 1a9c8eb7acac64fde33d72c036a3a487cb51baf3 Author: Gerlof Langeveld Date: Thu Oct 5 11:19:02 2017 +0200 Add SCHED_DEADLINE as scheduling policy possibility. M showprocs.c commit 6dd88897ba984e67a526e0a4278f7bc4d023bae1 Author: Gerlof Langeveld Date: Sat Sep 23 11:20:57 2017 +0200 Minor modifications in description of NFS output line. M man/atop.1 commit ba10627812c347460f650c877c3f3eaee194571e Author: Gerlof Langeveld Date: Fri Jun 30 13:13:22 2017 +0200 Include file versdate.h hould be ignored. M versdate.h commit f2f6717a9c633668f3ce3de4ebf8e521bd6bc01f Author: Gerlof Langeveld Date: Fri Jun 30 12:53:56 2017 +0200 Introduce CPU instructions per cycle For every CPU, the average number of instructions per CPU cycle is shown as 'ipc'. Besides, a column is shown with the number of cycles executed per second as `cycl` (shown as effective Hz frequency). 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 M various.c commit 33d561dcc766ca27cb7d1e09a9b0f99c3d98e124 Author: Gerlof Langeveld Date: Fri Jun 30 12:53:08 2017 +0200 Variable date of last build. M versdate.h commit 5f6813c11b58e307b9f2b8d0eb66a5c68ec613de Author: Gerlof Langeveld Date: Wed Jun 28 21:21:00 2017 +0200 Modify the date string for every new version of atop/atopacctd M Makefile M atopacctd.c A mkdate A versdate.h M version.c M version.h commit 5bcf22b32a2b2bc83802a48ee05b3451066f1fbc Author: Gerlof Langeveld Date: Sat Sep 23 12:49:21 2017 +0200 Recognize nbd devices M photosyst.c commit 4df0bcf37f8ef698afad4a528c2665b427c8e74d Author: Gerlof Langeveld Date: Sat Sep 23 12:38:48 2017 +0200 atop.init: execute script with bash instead of sh M atop.init commit 06ec90d6fc3c7d608b03a3f3d000e97a9a847955 Merge: 0a34810 7cac234 Author: Gerlof Langeveld Date: Sat Sep 23 11:37:52 2017 +0200 Merge pull request #5 from roadrunner2/add-nvme-support Recognize nvme disks as such too. commit 0a34810d1ce704311b62adaf97d30a2f02c94bd3 Merge: d99c19f 6bb8d2d Author: Gerlof Langeveld Date: Sat Sep 23 11:22:54 2017 +0200 Merge pull request #3 from sylmarch/sylmarch-patch-nfm-parseable-output Fix bytestotwrite in NFM parseable output commit d99c19f2e64df15ebd54a7934a39a10bd8bb9ef0 Merge: 2b1ad6a 1acea75 Author: Gerlof Langeveld Date: Sat Sep 23 10:40:19 2017 +0200 Merge pull request #1 from sylmarch/sylmarch-patch-nfs-parseable-output Fix rpcread / rpcwrite in NFS parseable output commit 7cac2341ba7e2419267a7e9ee5e5871de744bedb Author: Ronald Tschalär Date: Tue May 16 18:49:14 2017 -0700 Recognize nvme disks as such too. The pattern is based on name assignment in nvme_alloc_ns() in the linux kernel in drivers/nvme/host/core.c . M photosyst.c commit 6bb8d2d1fc53a68c3b68c998feabddf1efde033e Author: Sylvain Date: Fri Apr 21 16:09:31 2017 +0200 Fix bytestotwrite in NFM parseable output Fix NFS total number of bytes physically written to the server in NFM parseable output M parseable.c commit 1acea756e9863d52f973907ac06abab333c7235f Author: Sylvain Date: Fri Apr 21 15:40:40 2017 +0200 Fix rpcread / rpcwrite in NFS parseable output Fix NFS read/write RPC calls counters in parseable output M parseable.c commit 2b1ad6a78db3f52aec17cf675f1edacefa46a2db Author: Gerlof Langeveld Date: Sat Mar 25 15:09:24 2017 +0100 Highlights added. M README.md commit 42e86fcc42ce60f8c92f3c7d5f3a6ccde47c0b33 Author: Gerlof Langeveld Date: Sat Mar 25 14:36:13 2017 +0100 Preparation for github M Makefile A version.h commit 2d2cf7e29fdc7ef66f005ed491477a8551c8f554 Author: Gerlof Langeveld Date: Sat Mar 25 14:11:32 2017 +0100 Markdown text addded A README.md commit a8d850d06efc8d70a19f55ec93fe83df51e99077 Author: Gerlof Langeveld Date: Sat Mar 25 13:06:05 2017 +0100 Preparation for github M Makefile A version.c commit 6dac6bc7dc2adf27a3414955b8791db75c6a7397 Author: Gerlof Langeveld Date: Sat Mar 25 12:46:25 2017 +0100 Preparation to move atop to github D mkdistr D mkversion commit 5f101e656a24271726d1e9cd672631b6033c36c1 Author: Gerlof Langeveld Date: Sat Mar 25 12:40:23 2017 +0100 Preparations to move atop to github D atop.specsystemd D atop.specsysv T netatop.h T netatopd.h A rpmspec/atop.specsystemd A rpmspec/atop.specsysv commit 8ce799fdd3bb50978c00735cc72bbeb2c70d6844 Author: Gerlof Langeveld Date: Fri Mar 24 08:54:05 2017 +0100 Adapt man page for showing full process list for memory sorting M man/atop.1 commit 3105ce8d46562cb48081cb92eaee0afbda05166c Author: Gerlof Langeveld Date: Fri Mar 24 08:35:17 2017 +0100 Show full process list when sorting on memory is active M showgeneric.c commit 35869466fc30f318ac404454c322bad039033251 Author: Gerlof Langeveld Date: Fri Mar 17 16:32:30 2017 +0100 Solved segmentation fault Segmentation fault occurred in case of a selection (e.g. on user) in combination with switching from active processes to all processes. M atop.h M photoproc.c M rawlog.c M showgeneric.c M showprocs.c commit eaeb7c500820cccc7bf25606a86c4843cd70ad31 Author: Gerlof Langeveld Date: Fri Mar 17 11:25:46 2017 +0100 Type in man page M man/atop.1 commit 630d66700ca38ddda24d1797636d498e1e600866 Author: Gerlof Langeveld Date: Thu Mar 9 08:30:57 2017 +0100 Corrected accumulated disk writes When accumulating disk writes for programs, users or containers, values were accumulated twice per process. M showgeneric.c commit 989185c62c3a023e80bb9b2a5bb2e5563cda1651 Author: Gerlof Langeveld Date: Tue Mar 7 14:10:33 2017 +0100 Determine containerid per process generically The containerid of a process is determined via the file /proc/PID/cpuset that sometimes contains ".../docker-CONTAINERID" (on e.g. Redhat/CentOS) and sometimes "/docker/CONTAINERID" (e.g. Ubuntu). Both layouts should be supported. M photoproc.c commit 6678463533947894e06b178c84213c17a5faae98 Author: Gerlof Langeveld Date: Tue Mar 7 10:23:21 2017 +0100 Code optimizations releated to Docker containers M photoproc.c M showlinux.c commit fae417d905f6425035df0d3a4c99ddfa61b54e60 Author: Gerlof Langeveld Date: Mon Mar 6 19:20:37 2017 +0100 Smaal correction on the man page description of CID. M man/atop.1 commit ef95f26bdad331b441fbeae2148b0352889256fd Author: Gerlof Langeveld Date: Mon Mar 6 15:51:47 2017 +0100 Introduce Docker container statistics Maintain the Docker container id (12 positions) per process and per thread. This container id will be shown in various lists as CID, but only if at least one Docker container is present. Furthermore, it is possible to select all processes and threads that are related to a specific container id (keystroke 'J') and to accumulate the resource consumption for all processes/threads per container (keystroke 'j'). M atop.h M man/atop.1 M parseable.c M photoproc.c M photoproc.h M showgeneric.c M showgeneric.h M showlinux.c M showlinux.h M showprocs.c commit 0dc5a116cdbe8b1ccd6a0c3784e23a0e7e7abe41 Author: Gerlof Langeveld Date: Fri Feb 24 15:55:28 2017 +0100 Solved segmentation fault in case of threadview Sometimes a process is considered to be inactive while one of its threads appears to be active. This situation could lead to a segmentation fault in case of threadview of only active tasks. It has been solved by marking the inactive process as active when later on a thread is discovered that appears to be active. M deviate.c commit b4811a24801d8c35b64ab3c1b919418e934bb957 Author: Gerlof Langeveld Date: Fri Feb 24 13:16:06 2017 +0100 Determine maximum number of digits in PID/TID Since the maximum PID number may vary (/proc/sys/kernel/pid_max), the width of PID/PPID/TID/... columns should be determined dynamically. M showlinux.c M showprocs.c commit eb30f1d229cb5ac2c4b3ffe639c1efc8cbf70b72 Author: Gerlof Langeveld Date: Fri Feb 24 09:58:40 2017 +0100 Add dependency between version.c and version.h M Makefile commit fc0a5d5f15d5ffcf2203f95d290ce4e046ad1840 Merge: f498827 0aa208a Author: Gerlof Langeveld Date: Thu Feb 23 13:57:46 2017 +0100 Polling mode when NETLINK refuses with error EINVAL Due to kernel bug 190711, the NETLINK interface gives EINVAL when it is activated. Since atopacctd misses a trigger then to read the process accounting records when processes in the system terminate, a polling loop has to be used to verify the existance of new process accounting records. commit f49882721e5dbb065038ba74ae44b85457f50645 Merge: 17b2911 51d6285 Author: Gerlof Langeveld Date: Thu Feb 23 13:53:53 2017 +0100 Retry activation of process accounting after failure According to kernel bug 190271 (process accounting sometimes does not work), the kernel sometimes returns SUCCESS to switching on process accounting while it does not work at all. commit 17b2911b172eaeafe9f0b8e0bd7e721d1766b81e Merge: e402891 e743f1b Author: Gerlof Langeveld Date: Thu Feb 23 13:52:43 2017 +0100 Modified version numbering (without dashes) commit e4028912e77cb1b092cae20173b4c3dea34971fe Author: Gerlof Langeveld Date: Thu Feb 23 13:34:09 2017 +0100 Modify the date in the man pages M man/atop.1 M man/atopacctd.8 M man/atoprc.5 M man/atopsar.1 commit eb10042167d1d3b72049619c36deeaf7f272d4fe Merge: c873d6c c8e2e3f Author: Gerlof Langeveld Date: Thu Feb 23 13:29:45 2017 +0100 Improved error handling on the NETLINK interface Properly check the error values that are returned via the field nlmsg_type. commit c873d6c1eddcbfb3bd84a350684d7d7163aae377 Merge: 5ad6f1d 2b6aab6 Author: Gerlof Langeveld Date: Thu Feb 23 13:27:49 2017 +0100 Also show xvd... disk drives without a digit at the end of the name commit 5ad6f1dffae71cae39685e2883a8a178a40a6531 Merge: 78c478a 51b4a83 Author: Gerlof Langeveld Date: Thu Feb 23 13:25:06 2017 +0100 Atopacctd should terminate upon receipt of SIGTERM signal When activating a signal catcher via the signal() function, the SA_RESTART flag is implicitly set. This means that a pending system call is automatically restarted after the received signal is handled. Instead, the sigaction() system call is used now to activate a signal catcher avoiding system calls to be restarted automatically. commit 78c478a56f4281ce5e2d28d0fa9822ad4b7d6a37 Merge: 46bc6d7 2a6f792 Author: Gerlof Langeveld Date: Thu Feb 23 13:21:03 2017 +0100 Improved activation and deactivation of process accounting When atopacctd is started, it forks itself for proper daemonizing purposes. The first process no longer exits immediately, but is killed by the child process at the moment that atopacctd has finished the initialization phase. commit 46bc6d7da1d47eeb73f55497e562019b59c527f7 Author: Gerlof Langeveld Date: Wed Feb 22 15:52:15 2017 +0100 Script atop.daily located in /usr/share/atop instead of /etc/atop.d M Makefile M atop.cronsysv M atop.init M atop.service M atop.specsystemd M atop.specsysv M man/atop.1 M psaccu_atop commit 0aa208a0af7bb384010f7332b3131c0884edcdd8 Author: Gerlof Langeveld Date: Mon Dec 19 19:17:28 2016 +0100 Implemented polling mode in case NETLINK refuses with error EINVAL. Due to kernel bug 190711, the NETLINK interface gives EINVAL when it is activated. Since atopacctd misses a trigger then to read the process accounting records when processes in the system terminate, a polling loop has to be used to verify the existance of new process accounting records. M README M atopacctd.c commit 51d6285f97b2adf8f0efbea7121f4eb2a4b4f75d Author: Gerlof Langeveld Date: Mon Dec 19 16:05:18 2016 +0100 Retry activation of process accounting if it appears not to work. According to kernel bug 190271 (process accounting sometimes does not work), the kernel sometimes returns SUCCESS to switching on process accounting while it does not work at all. M atopacctd.c commit e743f1b749d3fccb95bcef6028c238560a81d805 Author: Gerlof Langeveld Date: Thu Dec 15 10:13:48 2016 +0100 Modified version numbering. M mkdistr commit 96f0613201da8cb7e8ebd1120dd18f83abc83536 Author: Gerlof Langeveld Date: Thu Dec 15 09:12:15 2016 +0100 Adapt date in man-pages. M man/atop.1 M man/atopacctd.8 M man/atoprc.5 M man/atopsar.1 commit c8e2e3f80fc46463c3e2c798b8a4d2a106ac98a5 Author: Gerlof Langeveld Date: Thu Dec 15 09:11:25 2016 +0100 Improved error handling on the NETLINK interface. M atopacctd.c M netlink.c commit 2b6aab6454c39903a5ead4c3d5d819393ec1cea1 Author: Gerlof Langeveld Date: Wed Nov 16 14:42:49 2016 +0100 Allow xvd... disk drives without a digit at the end of the name. M photosyst.c commit 51b4a83b2babf9ca944da892092e5559d9588594 Author: Gerlof Langeveld Date: Thu Oct 27 22:05:43 2016 +0200 Take care that atopacctd terminates upon receipt of SIGTERM signal. When activating a signal catcher via the signal() function, the SA_RESTART flag is implicitly set. This means that a pending system call is automatically restarted after the received signal is handled. Instead, the sigaction system call is used now to activate a signal catcher avoiding system calls to be restarted automatically. M atopacctd.c commit f0516657b3c7261c336f1b6e869afd9baa43d197 Author: Gerlof Langeveld Date: Mon Oct 24 16:13:46 2016 +0200 Changed 'rotate 1' into 'rotate 0' (no need for another dummy file). M psaccs_atop M psaccu_atop commit 7617354131f9a9bb1503b89b82cc8ca939c0f472 Author: Gerlof Langeveld Date: Mon Oct 24 16:12:35 2016 +0200 Changed 'rotate 1' into 'rotate 0' (no need for another dummy file). M psaccs_atop M psaccu_atop commit 2a6f792ad71410a75ca633ff38cb52a678cc05ed Author: Gerlof Langeveld Date: Fri Oct 14 21:34:08 2016 +0200 Improved activation and deactivation of process accounting. M atopacctd.c commit 6484680418827937064c2aba11619369e189d94d Author: Gerlof Langeveld Date: Sat Oct 8 15:23:43 2016 +0200 Script atop.daily located in /usr/share/atop instead of /etc/atop.d M Makefile M atop.cronsysv M atop.init M atop.service M atop.specsystemd M atop.specsysv M psaccu_atop commit 101c0139e1a703479f7fb779bc258cf199eaa9fb Author: Gerlof Langeveld Date: Sat Oct 8 14:31:52 2016 +0200 Raw logging: Determine features per sample Define per sample whether or not process accounting is active and whether or not disk I/O statitics are maintained. In previous versions, this was determined for the entire log file which implied that it was impossible to append to an existing logfile when one of these features had changed. M atop.h M rawlog.c commit 36b9b09ac15519187717481ac79da25e66bce8eb Author: Gerlof Langeveld Date: Sat Oct 8 14:21:42 2016 +0200 Moved accounting file from /tmp to /var/cache. M acctproc.c M man/atop.1 commit a44bafe1895515e92881225079d56bb04053c9cf Author: Gerlof Langeveld Date: Sat Oct 8 14:18:13 2016 +0200 Added -r y... flag to usage message. M atopsar.c commit 2f7369f6911cc0fe6bb79dfa11ea845ebb036ea0 Author: Gerlof Langeveld Date: Sat Oct 8 14:16:29 2016 +0200 The flag -V has been added to the help-output. M atop.c commit a31b5a516e0dcfa5352e1047defbd6abf3c22444 Author: Gerlof Langeveld Date: Sat Oct 8 14:12:13 2016 +0200 Modified column name SNETBW to BANDWO. Modified column name RNETBW to BANDWI. M showlinux.c M showlinux.h M showprocs.c commit 5b21d88014fe4e53a5ab8f01d03ae00a2de56a18 Author: Gerlof Langeveld Date: Sat Oct 8 14:05:15 2016 +0200 Cosmetic changes in distribution script. M mkdistr commit b96168f473ca8a69884d900464cfb5f641e18d26 Author: Gerlof Langeveld Date: Sat Oct 8 14:03:55 2016 +0200 Cosmetic change. M various.c commit 90a3f939d5db6a41e1352f847f8719a89e5ddf78 Author: Gerlof Langeveld Date: Sat Oct 8 14:03:35 2016 +0200 Recalculate length of nodename when reading raw logfile. M rawlog.c commit 3fd998d0f2e43e57ff8d5d22b747efb14c1da554 Author: Gerlof Langeveld Date: Sat Oct 8 14:03:18 2016 +0200 Remove include of termio.h (not needed at all). M showgeneric.c M showlinux.c M showprocs.c M showsys.c commit 2820b1144ce403c7917cd2e09b05e78d2c9dbc07 Author: Gerlof Langeveld Date: Sun Sep 18 14:36:54 2016 +0200 Moved accounting file from /tmp to /var/cache. M acctproc.c M man/atop.1 commit e5a1be40373ebedf5bffede8968304fd3e0e8a18 Author: Gerlof Langeveld Date: Sat Sep 17 10:12:29 2016 +0200 Raw logging: dDetermine features per sample Define per sample whether or not process accounting is active and whether or not disk I/O statitics are maintained. In previous versions, this was determined for the entire log file which implied that it was impossible to append to an existing logfile when one of these features had changed. M atop.h M rawlog.c commit fec3f38c9b08459dea1a86fcdef56e97d211c1b6 Author: Gerlof Langeveld Date: Tue Sep 13 18:50:31 2016 +0200 Added -r y... flag to usage message. M atopsar.c commit e721b7194acb0f3de893d22e733f96c93172b5b7 Author: Gerlof Langeveld Date: Thu Sep 1 19:06:44 2016 +0200 Improved performance data gathering: All process and thread related data is stored now by function deviattask(), independent if the user wants to view all data. In this way, immediate reaction is garanteed for the 'a' key which allows the user to view all processes/threads or to view only the active processes/threads (previously, the 'a' key was only effective after taking a new sample). Together with this modification, the behaviour of the 'm' key (memory view) has changed by showing automatically all processes instead of only the active processes. After all, when viewing the memory consumption of the processes, it is not relevant whether or not that process has been active in the last interval. M 45atoppm M atop.c M atop.daily M atop.h M atopsar.c M deviate.c M man/atop.1 M parseable.c M parseable.h M photoproc.h M rawlog.c M showgeneric.c M showgeneric.h M showlinux.c commit 9f1bfee3f0babf88e86c8258bad977885eef279e Author: Gerlof Langeveld Date: Thu Aug 11 15:55:50 2016 +0200 The flag -V has been added to the help-output. M atop.c commit ba0cdc1474cebcbdac52b3ee9cc8516b33eeb0e8 Author: Gerlof Langeveld Date: Thu Aug 11 15:55:18 2016 +0200 With 'make clean' also the executable files are removed now. M Makefile commit 057c27d5f7b5e2b9ab06a91bed831d14dd7fe16b Author: Gerlof Langeveld Date: Mon Mar 7 12:16:06 2016 +0100 Modified column name SNETBW to BANDWO. Modified column name RNETBW to BANDWI. M showlinux.c M showlinux.h M showprocs.c commit 835d9a22dd88756709d75104550b206147c4151f Author: Gerlof Langeveld Date: Mon Mar 7 12:15:31 2016 +0100 Cosmetic change in distribution script. M mkdistr commit d600eac843b87cdfb91a6e1807d3aff5915dfdea Author: Gerlof Langeveld Date: Wed Jan 13 08:42:58 2016 +0100 Cosmetic fix. M various.c commit c2370bda4689217cefe60d1760d29fe1397436a4 Author: Gerlof Langeveld Date: Mon Nov 30 15:26:21 2015 +0100 Recalculate length of nodename when reading raw logfile. M rawlog.c commit a2306c0e1c83f5a123ce521a34d9efaa2297c26d Author: Gerlof Langeveld Date: Mon Nov 30 15:24:17 2015 +0100 Remove include of termio.h (not needed at all). M showgeneric.c M showlinux.c M showprocs.c M showsys.c commit 1c72c7dfe0843087440598e4df9dc844c2eff1eb Author: Gerlof Langeveld Date: Tue Nov 24 10:21:49 2015 +0100 The top-3 of CPU, disk and network consuming processes now only shows processes that really used capacity of that resource. Implicitly, a segmentation fault bug has been solved that occurred when less than 3 processes were available anyhow. M atopsar.c commit 1c5cac40d0bec5ea9b9625a8c61a4ad38899aad9 Author: Gerlof Langeveld Date: Tue Nov 24 08:59:37 2015 +0100 Column that show interface speed is shifted to the right, to keep input and output packets for all layers aligned. M showlinux.c commit 29012c89cacd30aa3c0f83e9f4c92b720ceda901 Author: Gerlof Langeveld Date: Tue Aug 4 19:11:36 2015 +0200 Execpath has been changed to /usr/sbin instead of /sbin (wrong directory location). M atopacct.service commit 0f502b2633bb00a340daf8ff0ac3506d486a1e09 Author: Gerlof Langeveld Date: Tue Aug 4 19:08:25 2015 +0200 Bug solution: When starting atop via sudo, atop runs into the stopped state. Caused by earlier modification to make atop a process group leader (needed for systemd). Problem solved by making atop only a process group leader when it doesn't operate interactively. M atop.c commit c0062f3e5a2604b3e8f0723e50c0cea0931d3e01 Author: Gerlof Langeveld Date: Thu Jun 25 12:54:30 2015 +0200 Modified handling of release number. M mkdistr commit 8becf63a08ba68ece7543512426cffa36e5c9c01 Author: Gerlof Langeveld Date: Thu Jun 25 12:53:44 2015 +0200 Modified handling of release number. M atop.specsystemd M atop.specsysv commit c213a40de6884129877b1519400de362a64b1f37 Author: Gerlof Langeveld Date: Thu Jun 25 12:53:14 2015 +0200 Added some blank fields for interfaces. M showlinux.c commit 67f5b44cbd2ef5ad3a59e09a6e192af489300a52 Author: Gerlof Langeveld Date: Tue Jun 23 16:55:30 2015 +0200 Minor bug-fixes. M man/atop.1 M showgeneric.c commit 6f0105972808ffd852b833ed81c222f259bc762a Author: Gerlof Langeveld Date: Tue Jun 23 16:32:16 2015 +0200 New selection possibilities for processes: Key 'I' can be used to specify one or more PIDs of processes to be selected. Key '/' can be used to specify a command line search string for processes to be selected. M man/atop.1 M showgeneric.c M showgeneric.h commit d8f641ecca0ac117c2eacd33cc6517944461a0af Author: Gerlof Langeveld Date: Tue Jun 23 14:44:49 2015 +0200 Bugfix for buffer overflow: snprintf instead of sprintf (credits: Nathan Scott). M showsys.c commit 8b82505a8125cf5b351b6de841cf6cd35740b133 Author: Gerlof Langeveld Date: Tue Jun 9 12:30:36 2015 +0200 Fine-tune statistics about data transfer to/from NFS servers. M atopsar.c M man/atop.1 M man/atopsar.1 commit 7c2b2cb6615a20e7e130a2fe00d4d029e0f5f3fa Author: Gerlof Langeveld Date: Tue Jun 9 11:03:10 2015 +0200 Bug solutions and small modifications for nfs4 mountstats. M atop.h M deviate.c M man/atop.1 M photosyst.c M showlinux.c M showprocs.c M showsys.c M various.c commit e3d0e1f03ac0cc48c5add560377933a3abf8ddbe Author: Gerlof Langeveld Date: Mon Jun 8 17:31:58 2015 +0200 Added statistics per mounted NFS filesystem (label NFM). M atop.c M atop.h M atopsar.c M deviate.c M man/atop.1 M man/atoprc.5 M man/atopsar.1 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 314a64d9c62b27747d23c6f85011411076482f51 Author: Gerlof Langeveld Date: Mon Jun 8 10:01:05 2015 +0200 Solved various small bugs found by clang-analyzer. M atopsar.c M parseable.c M rawlog.c M showlinux.c M various.c commit 9b621bcac274df21012a42a2d131143e5857a47a Author: Gerlof Langeveld Date: Fri May 29 08:42:05 2015 +0200 Added buffers for formatting HTTPSTATS-specific output. M showlinux.c commit 66e4b0326d8663b8cc26cde42c9d1232e1742714 Author: Gerlof Langeveld Date: Fri May 22 09:58:22 2015 +0200 Accept 'xvd[a-z]' disks with a number behind it (they always seem to end with a number). M photosyst.c commit 7d5f789ddbbaea7ae0e4d2c3f78a3f735ca3a36f Author: Gerlof Langeveld Date: Mon May 18 08:58:41 2015 +0200 Rebuild of lost spec file for systemd. M atop.specsystemd commit 94f3da8d2740aaa3abfa7974afa900d985b8a9be Author: Gerlof Langeveld Date: Mon May 18 08:55:18 2015 +0200 Maintain current speed (rate) for wireless interfaces. M atopsar.c M deviate.c M ifprop.c M ifprop.h M man/atop.1 M photosyst.h M showlinux.c M showlinux.h M showsys.c commit 4ae902d49e3207c70153db2bbb8a3eed775c7c4a Author: Gerlof Langeveld Date: Sat May 9 18:01:12 2015 +0200 Support systemV and systemd RPMs. M atop.specsystemd M atop.specsysv M mkdistr commit b7b704f4406c92d9c5cda53a4c72bb37afeea744 Author: Gerlof Langeveld Date: Sat May 9 17:58:00 2015 +0200 Added defined value SPEED_UNKNOWN for older releases. M ifprop.c commit ab95f1a444a5e796641012bf3aa85a70f8056760 Author: Gerlof Langeveld Date: Sat May 9 16:27:17 2015 +0200 Support of systemv and systemd RPMs. M mkdistr commit 0f9e3cfeb31450ced24375631c6130e9fef60ae8 Author: Gerlof Langeveld Date: Sat May 9 16:21:31 2015 +0200 Support for OpenVZ containers. M atop.c M atop.h D atop.spec M deviate.c M man/atop.1 M man/atoprc.5 M parseable.c M photoproc.c M photoproc.h M photosyst.c M photosyst.h M showgeneric.c M showgeneric.h M showlinux.c M showlinux.h M showprocs.c M showsys.c commit b77825747f165a7c3bd76353d8f428676732cedd Author: Gerlof Langeveld Date: Sat May 9 16:20:24 2015 +0200 Separate RPM spec files for SystemV init and systemd. A atop.specsystemd A atop.specsysv commit 8f0148d9946344fe9b8a5eeee5a20588e0b149dd Author: Gerlof Langeveld Date: Tue Apr 7 13:02:58 2015 +0200 Addition of NFS (server/client) statistics on system level. M Makefile M atopsar.c M deviate.c M man/atop.1 M man/atopsar.1 M parseable.c M photosyst.c M photosyst.h M showlinux.c M showlinux.h M showsys.c commit 6e133e74acd987e915d7edeb4dab281ed8a055e2 Author: Gerlof Langeveld Date: Tue Mar 24 15:52:11 2015 +0100 Add NFS client and NFS server statistics. M atopsar.c M deviate.c M man/atop.1 M man/atopacctd.8 M man/atoprc.5 M man/atopsar.1 M parseable.c M photosyst.c M photosyst.h M showlinux.c M showlinux.h M showsys.c commit 6da40d213f14865356956b196475c080be1c79e6 Author: Gerlof Langeveld Date: Tue Mar 24 08:36:51 2015 +0100 Minor modification related to systemd-based install. M Makefile commit 04276882956a196e872fca17fb1dd73289eb3d1f Author: Gerlof Langeveld Date: Wed Feb 25 15:26:55 2015 +0100 Prepare atop and atopacct for use on systemd-based systems. M Makefile M README A atop-pm.sh M atop.service M atopacct.init A atopacct.service M atopacctd.c M atopacctd.h M mkdistr commit 1e2fc1c2275d71114a62fe95ca7363a6d9d1cd8a Author: Gerlof Langeveld Date: Wed Feb 25 15:20:05 2015 +0100 Avoid negative utilization counters for disks and logical volumes. These negative values might cause buffer overflows within atop. M showsys.c M various.c commit 2c5327f1a0a6797383785e6893b46f39d3a67c85 Author: Gerlof Langeveld Date: Tue Feb 24 09:34:52 2015 +0100 Avoid that process accounting is reactivated too frequently (and unnecessary). M atopacctd.c commit cfda21540a2a9b6545259ed612f8afc22b2218b8 Author: Gerlof Langeveld Date: Tue Feb 24 09:32:41 2015 +0100 Added creation of the SBINPATH directory for atopacctd. M Makefile commit 688f446ab5fb81dc6c44c065f956913682d1b03f Author: Gerlof Langeveld Date: Mon Feb 2 08:32:57 2015 +0100 Prepare systemd-based installation. A atop.cronsystemd A atop.cronsysv commit ab8db5f44f1b4edff624c4698849e391588e0cbd Author: Gerlof Langeveld Date: Mon Feb 2 08:31:33 2015 +0100 Prepare systemd-based installation. M Makefile M atop.c D atop.cron M atop.daily M atop.init M atop.service M mkdistr M psaccs_atop M psaccu_atop commit a5e0d6d0c758ce8ecc3ba6f8df2c30df8af64cc2 Author: Gerlof Langeveld Date: Mon Dec 8 09:38:47 2014 +0100 Define proper line speed for network interfaces faster than 1 Gbit/sec. M ifprop.c commit d18f067446deb39933b21ba7b2874ea63cb47e71 Author: Gerlof Langeveld Date: Fri Oct 17 14:31:27 2014 +0200 Minor change. M mkdistr commit 52e9c4a0f05f76ab81d46dc1f42ac69f5e123ae5 Author: Gerlof Langeveld Date: Fri Oct 17 14:28:10 2014 +0200 Minor correction in man-page. M man/atopacctd.8 commit c18d1354898e8871f75dedc8e8427694606b3832 Author: Gerlof Langeveld Date: Thu Aug 28 13:52:57 2014 +0200 Correction of typo's in the man pages, including a wrong counter name in the output of atop ('udpie' for UDP input errors). M Makefile M man/atop.1 M man/atopacctd.8 M man/atoprc.5 M man/atopsar.1 M showsys.c commit 4e739738da3aa5931cc0f66c7d402dea50ca6f6f Author: Gerlof Langeveld Date: Thu Aug 28 11:51:13 2014 +0200 OpenVZ support: virtual environment identifier per process (envID). M photoproc.c M photoproc.h M showlinux.c M showlinux.h M showprocs.c commit 3bd1bab7bd6fb0ec110922afbb169264a335a74f Author: Gerlof Langeveld Date: Fri Jul 25 15:31:42 2014 +0200 Activate atopacctd before activating the atop daemon. M atop.spec commit 0d02d0565b6d0df1c22be3237d145b7e0b7e68eb Author: Gerlof Langeveld Date: Fri Jul 25 14:58:19 2014 +0200 Improved help screen handling: use space bar to get next page. M showgeneric.c commit 5cebf4101c11d4680e57250635c6148b104bf4f9 Author: Gerlof Langeveld Date: Fri Jul 25 13:48:37 2014 +0200 Bug solution: when the screen-width is larger than the total number of columns to be printed, empty columns are added, however one column too many. M showsys.c commit b25ef4ec59240c58e929c93d17d42c91cf70121e Author: Gerlof Langeveld Date: Fri Jul 25 13:48:09 2014 +0200 Removed useless empty column for memory statistics. M showlinux.c commit 38163c1230c5e58890e783dd1cb29e14640e6099 Author: Gerlof Langeveld Date: Fri Jul 25 13:47:36 2014 +0200 Cosmetic change. M atopacctd.c commit 636fa8df11c99b3d6468f4c13c830c29ba79638d Author: Gerlof Langeveld Date: Thu Jul 24 16:07:01 2014 +0200 Detect if process accounting has been switched off by some other program and switch it on again. M atopacctd.c M atopacctd.h commit 268750adfc4e4a00050501d9c70d56436b4bb0a6 Author: Gerlof Langeveld Date: Sat Jun 28 11:15:17 2014 +0200 Add a warning about the aggregation of disk transfer to the parent process for the RDDSK and WRDSK counters. M man/atop.1 commit 1396164f8a5c880dc14658cc69a685babf040739 Author: Gerlof Langeveld Date: Fri Jun 20 14:51:53 2014 +0200 Add automatic start of atopacctd daemon. M Makefile commit 0dcc489d0ded0b2d2241cd9a625fd5206ddb7cd6 Author: Gerlof Langeveld Date: Fri Jun 20 14:06:08 2014 +0200 Add man page of atopacctd. M atop.spec M mkdistr commit 5295539f7b7ba1e725d20caf92eb9d28e1dd87ce Author: Gerlof Langeveld Date: Fri Jun 20 13:52:16 2014 +0200 Add man page for the atopacct daemon. A man/atopacctd.8 commit 027c748ffcb1a4ee926a3c14f2241342a2e6c5bd Author: Gerlof Langeveld Date: Fri Jun 20 13:49:14 2014 +0200 Modify the man pages and installation procedures for the introduction of the atopacctd daemon. M Makefile M atop.spec M atopacctd.c M man/atop.1 M man/atoprc.5 M man/atopsar.1 commit 366622d86d3716661ad36b86bbe833bc9ce29496 Author: Gerlof Langeveld Date: Wed Jun 18 13:24:49 2014 +0200 Introduce the 'G' key to suppress showing/accumulating exited processes in the output. M man/atop.1 M man/atoprc.5 M showgeneric.c M showgeneric.h commit a7668eb60ebda954dd8223e4a501b21afdea4cec Author: Gerlof Langeveld Date: Fri Jun 13 07:55:33 2014 +0200 Support CPU frequencies for systems with Intel P-state driver. Credits: Sjon Hortensius M photosyst.c commit 8e269cc3a8df55852490b8b99148b0f973e3d334 Author: Gerlof Langeveld Date: Fri Jun 13 07:51:55 2014 +0200 Cosmetic change. M atopacctd.c commit f12727d632052e6a82149d6e4804e354f2caae54 Author: Gerlof Langeveld Date: Fri Jun 13 07:50:25 2014 +0200 Remove rc-scripts with old sequence numbers (if any). M Makefile commit 7cec49a8d095e4d520ffe7f21499a7996137fc78 Author: Gerlof Langeveld Date: Sat Jun 7 12:47:29 2014 +0200 Doubled the %-signs to get the proper date string. M atop.service commit 9b699e1c0aea4842609f53ba0df061b568aa6d13 Author: Gerlof Langeveld Date: Sat Jun 7 12:11:52 2014 +0200 Source file netlink.c compiled without -O2 due to a strict-aliasing warning. M Makefile commit c1963ca5c51ccc8dba9866238376d49ffece962a Author: Gerlof Langeveld Date: Sat Jun 7 12:09:34 2014 +0200 Source file netlink.c compiled without -O2 due to a strict-aliasing warning. D atopacctd commit f2f369b2c79117aa03ce393e9cb54eab3bc36009 Author: Gerlof Langeveld Date: Sat Jun 7 11:29:36 2014 +0200 Rename variables to clearly distinghuish between the two semaphore groups. M acctproc.c commit 35ded9cabe93b4f6a126711d31dbe3fdfd3d3ebe Author: Gerlof Langeveld Date: Sat Jun 7 11:28:46 2014 +0200 Add the -R flag to gather PSIZE info in the background. M 45atoppm M atop.service commit d2a545c15bf4e3099d4391f24d20b079a5759872 Author: Gerlof Langeveld Date: Fri Jun 6 08:49:35 2014 +0200 Introduction of new daemon atopacctd. This daemon switches on process accounting and transfers every accounting record to an accounting shadow file. The source accounting file will regularly be truncated, while the shadow files are written with a limited size in a queued way. Non-used shadow files are deleted regularly. A atopacct.init A atopacctd A atopacctd.c A atopacctd.h A netlink.c commit b3909dd3243a7011ee605ed387692dcb0d8e17de Author: Gerlof Langeveld Date: Fri Jun 6 08:44:54 2014 +0200 Introduction of new daemon atopacctd. This daemon switches on process accounting and transfers every accounting record to an accounting shadow file. The source accounting file will regularly be truncated, while the shadow files are written with a limited size in a queued way. Non-used shadow files are deleted regularly. M Makefile M acctproc.c M acctproc.h M atop.c M atop.init M atop.spec M man/atoprc.5 M showgeneric.c commit 65abbee8fe9f4ea4ec7c875e897d1aa3a5b2763d Author: Gerlof Langeveld Date: Thu May 29 13:24:55 2014 +0200 Add the -R flag for monitoring in the background. M atop.service commit 295585730cbbe322d0dd556c45413e2ab0737099 Author: Gerlof Langeveld Date: Wed May 28 16:59:54 2014 +0200 Usage message of atop and atopsar extended with reference to the man-page. M atop.c M atopsar.c commit 7df1f797fa27f5dd53298f7511bb36811dc51e14 Author: Gerlof Langeveld Date: Wed May 28 16:46:00 2014 +0200 Added a function prototype for priline to verify the calling (cause of earlier problems). M atopsar.c commit b495b78b8b120bcf266440f6ed1f0e133573e76b Author: Gerlof Langeveld Date: Wed May 28 14:29:02 2014 +0200 Bug-solution: segmentation fault when one of the process names in the system contains a newline. M photoproc.c commit 216c4ccc9e26d1d195985f8b2c45c4008492a341 Author: Gerlof Langeveld Date: Wed May 28 13:54:36 2014 +0200 Introduce configurable colors: in the atoprc file, colors can be defined for information messages (default green), threads (default yellow), almost critical resources (default cyan) and critical resources (default red). M atop.c M man/atop.1 M man/atoprc.5 M man/atopsar.1 M showgeneric.c M showgeneric.h M showsys.c commit fd2bb81e07dbb1ac97a559e7099e717e05b80642 Author: Gerlof Langeveld Date: Wed May 28 12:17:08 2014 +0200 Cosmetic change to message. M showgeneric.c commit dc1ef5d83b72095536cfabd53adcfcfc8ec37a01 Author: Gerlof Langeveld Date: Wed May 28 12:15:56 2014 +0200 Solve floating point exception in case that the process accouting file was not open. M acctproc.c commit a94a6170476406d1ca85aa018ea71eea6d41f5bd Author: Gerlof Langeveld Date: Wed May 28 11:27:05 2014 +0200 Limit the names of network interfaces to six characters max. M atopsar.c commit 19826d8ae098b21cf733cf4e69bfb1936cddc7dd Author: Gerlof Langeveld Date: Wed May 28 11:01:13 2014 +0200 Modified names for RPM files. M mkdistr commit b71978ea7ec610305a239529345e816e1323a02b Author: Gerlof Langeveld Date: Wed May 28 10:19:16 2014 +0200 Added Requires and BuildRequires. M atop.spec commit f6d0eae38d1e9f093d15fb6fa74d353e59efd05d Author: Gerlof Langeveld Date: Wed May 28 10:18:35 2014 +0200 Cosmetic change. M Makefile commit 318890acda8a7cab6bba829fa3276e774f1bd4e0 Author: Gerlof Langeveld Date: Sun May 25 22:01:54 2014 +0200 Correction for PSIZE calculation: regain and drop root privileges. M photoproc.c commit 01be030273991089b6ded31d6a28855bf874d7be Author: Gerlof Langeveld Date: Sat May 24 14:10:55 2014 +0200 Introduction of proportional memory size (PSIZE) per process. For the resident memory parts used by a process that are shared with other processes, only a proportional part (shared memory part divided by the number of sharers) is accounted to the process. Since the gathering of this value is rather time-consuming (reading the smaps file of every process), it is optional ('R' key or '-R' flag). M atop.c M atop.daily M atop.h M deviate.c M man/atop.1 M parseable.c M photoproc.c M photoproc.h M showgeneric.c M showgeneric.h M showlinux.c M showlinux.h M showprocs.c commit 899cdbd18447ce29f901d43531a1702416ab22ad Author: Gerlof Langeveld Date: Sat May 24 11:02:18 2014 +0200 Increased number of LVMs and disks supported. M photosyst.h commit e2f7fb5bc45510b2ec14269e71a0b8ca7ae5a454 Author: Gerlof Langeveld Date: Fri May 23 23:33:40 2014 +0200 Resize message shows new dimensions. M showgeneric.c commit 0f54b4c1ebca739cda28ae5793475b06e90e0b88 Author: Gerlof Langeveld Date: Fri May 23 15:39:46 2014 +0200 The guest percentage that is shown for CPUs, is not a separate category that should be totalized with the other categories. In fact, it overlaps with the user mode percentage. So if one of the virtual machines executes a looping process, on the KVM hypervisor the user percentage and guest percentage should both show 100% instead of both 50%. M atopsar.c M deviate.c M man/atop.1 M man/atopsar.1 M procdbase.c M showlinux.c commit 3149aa8f4720e615148179ae8cc5146b8c3f5433 Author: Gerlof Langeveld Date: Fri May 23 13:28:20 2014 +0200 Useless buffer formatting removed. M atopsar.c commit e96c1fff1c7a7ca292f3aedaaa28b92d2e7b9629 Author: Gerlof Langeveld Date: Fri May 23 13:19:21 2014 +0200 Removed double disk entry for 'vd...' disks. M photosyst.c commit 239bd26a925d54d184248f00df35586d4d8d441d Author: Gerlof Langeveld Date: Sun Jan 26 15:42:31 2014 +0100 Solve segmentation vioalation with atopser (wrong number of arguments passed to priline function). M atopsar.c commit 3829e7382f348489f61f01b4e19fb4fb12bc36ef Author: Gerlof Langeveld Date: Sun Jan 26 15:37:12 2014 +0100 Solve segmentation violation when making summaries: Extra parameter added to priline-function call. M atopsar.c M man/atop.1 M rawlog.c commit fbce79c76ddb6a38a2bc22b44a95edcf9cf78a36 Author: Gerlof Langeveld Date: Sat Dec 7 12:17:07 2013 +0100 When process accounting is switched on and a child process has been created and terminated, it still might occur that no process accounting record has been written (kernel failure?). This situation resulted in a Floating Point Exception signal. M acctproc.c commit 2c7fe393518d861ff2fac3b38888389dd13c9b67 Author: Gerlof Langeveld Date: Sat Oct 26 13:07:18 2013 +0200 Add a space between two columns, that were show without white space. M parseable.c commit 948581cce702ffdf93d8e632c6ef12aa3ff6a31b Author: Gerlof Langeveld Date: Sat May 11 16:58:05 2013 +0200 Add new counter for memory that is claimed by the vmware balloon driver (to be withdrawn from this virtual machine in favour of other virtual machines). 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 3a82bbeda1627a8a133f64f4434edaeefe413759 Author: Gerlof Langeveld Date: Wed Apr 24 10:47:39 2013 +0200 Support for huge pages (total and in use). M deviate.c M man/atop.1 M photosyst.c M photosyst.h M showlinux.c M showlinux.h M showsys.c commit 22295853af2f10701f6da3243b75f55fc2eb5f6d Author: Gerlof Langeveld Date: Tue Apr 23 14:42:24 2013 +0200 Documentation improvements. M man/atop.1 M showgeneric.c commit 05266573ea93a9866121909b4bd61856103e9a28 Author: Gerlof Langeveld Date: Tue Apr 2 10:59:24 2013 +0200 Documentation improved concerning top-3 of processes (atopsar) and the netatop module (atop). M man/atop.1 M man/atopsar.1 commit 9be21d695f218120e501d459ae1bdf112b4dbba5 Author: Gerlof Langeveld Date: Thu Jan 10 13:54:08 2013 +0100 Cosmetic change: rename some variables to ease future maintenance. M atop.c M deviate.c M photoproc.h commit ffd892d16dc60950a637db45bf2af692a3d2a91e Author: Gerlof Langeveld Date: Wed Dec 19 15:45:40 2012 +0100 Under certain circumstances, the number of exited processes might be less than requested, so correct the counter nrexit. M acctproc.c M atop.c commit ba35522fbfb1c4fdb90d0dc68b0ac50e95cae73f Author: Gerlof Langeveld Date: Tue Dec 11 23:16:36 2012 +0100 Solution for the following bug: When process accounting type 2 is used by the kernel (i.e. no PID is the accounting record), atop crashes when thread view is enabled. Credits: Alex Samorukov M showgeneric.c commit c34bb60f74c25c3da24ab485ff6d41b8435609b1 Author: Gerlof Langeveld Date: Wed Nov 21 21:50:55 2012 +0100 Corrected value 'curproc' in -P report. M atopsar.c commit 321e5288151db22e643569f8b71709d1f5da6bf4 Author: Gerlof Langeveld Date: Mon Nov 19 09:26:32 2012 +0100 Maintain total number of bytes transferred for accumulated per-user/per-program view (key 'u'/'p') to show proper NET-percentage and get proper sorting order. M showgeneric.c commit cc2824f244ae33c3628dc5bc8a96bf1e64088bb7 Author: Gerlof Langeveld Date: Fri Nov 16 22:47:29 2012 +0100 Extended the number of positions for the RNET/SNET counters from 4 to 5, and shrinked SYSCPU/USRCPU from 7 to 6. M showprocs.c M showsys.c M various.c commit 57fb7e206e36e131093c7d0c4cbffe0f07d4bb20 Merge: 55b51fe 8f5f6cc Author: Gerlof Langeveld Date: Fri Nov 16 21:42:32 2012 +0100 Merge branch '2.0.1' Conflicts: mkdistr mkversion version.h commit 8f5f6ccc03b9b8ebaf8b2d65a18d3b56cb58c483 Author: Gerlof Langeveld Date: Fri Nov 16 19:27:04 2012 +0100 Version update M version.h commit 8c17df29c0d6dc82bec807cc2af8c50d69a2fbdb Author: Gerlof Langeveld Date: Fri Nov 16 19:23:20 2012 +0100 Release modification. M version.h commit b5f5f9c05343c0b818b2afef291fd27d35aa690c Author: Gerlof Langeveld Date: Wed Nov 7 08:54:04 2012 +0100 Required modifications for distribution. M atop.spec M mkdistr M mkversion M version.h commit e4f27ff6ba3585b82155af29665c017e146e5c75 Author: Gerlof Langeveld Date: Tue Nov 6 08:19:44 2012 +0100 Remark about netatop in README and solved rendering problem in atoprc.5 M README M man/atoprc.5 commit 41696c91407d65454769d8c0c94d65b410791963 Author: Gerlof Langeveld Date: Fri Nov 2 11:14:52 2012 +0100 Sequence regainprivs-fopen-dropprivs-fread-... does not work for files under /proc, so the /proc/PID/io files could not be accessed when atop is not started by a root-user. Sequence has been changed to regainprivs-fopen-fread-...-dropprivs. M photoproc.c M various.c commit 55b51feda3e2ffa450adb72203ecd9afc3474d30 Author: Gerlof Langeveld Date: Fri Nov 2 11:08:40 2012 +0100 Sequence regainprivs-fopen-dropprivs-fread-... does not work for files under /proc, so the /proc/PID/io files could not be accessed when atop is not started by a root-user. Sequence has been changed to regainprivs-fopen-fread-...-dropprivs. M photoproc.c M various.c commit 8e75554bb8f98269912ebb85a457df3fab35a54f Author: Gerlof Langeveld Date: Sat Oct 27 11:59:24 2012 +0200 Adapt to correct month. M man/atop.1 M man/atoprc.5 M man/atopsar.1 commit 1a256253c472ccca37ee1dd93ac7d6d1f3fd7e48 Author: Gerlof Langeveld Date: Sat Oct 27 11:53:49 2012 +0200 Bug fixes. M mkdistr M mkversion M version.h commit 6f61e0e5dbb3f48fd10d52b34eaac6ca49e19b31 Author: Gerlof Langeveld Date: Thu Oct 25 17:22:39 2012 +0200 Added update-rc.d M Makefile commit 643941fd3ff2055fcdcb979cdeeab62cef5771c8 Author: Gerlof Langeveld Date: Wed Oct 24 13:12:21 2012 +0200 Dynamically switch per sample to show network stats or not. In this way a running atop (e.g. the daily atop running in the background) immediately reacts on loading or unloading of the netatop module. M atop.c M atop.h M deviate.c M man/atop.1 M netatopif.c M photoproc.c M rawlog.c M showgeneric.c M showgeneric.h M showlinux.c commit f36eb4be1d7e26ed233bb101613df1a6363f8891 Author: Gerlof Langeveld Date: Mon Oct 22 09:27:14 2012 +0200 Consider Shmem value in /proc/meminfo. M man/atop.1 M showlinux.c commit fc06911932186159fd190f53379462a1a5b05147 Author: Gerlof Langeveld Date: Mon Oct 22 09:22:42 2012 +0200 Add counter shmem as total shared memory including tmpfs. Som miscellaneous cosmetic changes. M acctproc.c M deviate.c M man/atop.1 M man/atoprc.5 M man/atopsar.1 M photosyst.c M photosyst.h M showlinux.c M showlinux.h M showsys.c commit 1e3c18350475135d11c300801647b5ea8aa6b204 Author: Gerlof Langeveld Date: Sat Oct 20 17:06:33 2012 +0200 Modified formula to determine if memory is critically low: the page cache counter implies the resident shared memory (and that should not be subtracted). M showlinux.c commit 58c0aae74341a337397859854dfcf826b21ca3ef Author: Gerlof Langeveld Date: Sat Oct 20 16:59:30 2012 +0200 Gather and display the value SReclaimable from /proc/meminfo to give more adequate coloring of the MEM-line. 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 213f3e1160046000858edd33c59952be802d5058 Author: Gerlof Langeveld Date: Sun Oct 14 15:07:48 2012 +0200 Get rid of warnings from ignored return values (with (void)) M acctproc.c M atop.c M atop.h M atopsar.c M photoproc.c M photosyst.c M rawlog.c M various.c commit a7a17cfc03f6e4b82840bce4d61bbcdd20db52e0 Author: Gerlof Langeveld Date: Sun Oct 14 13:29:05 2012 +0200 Cosmetic change. M mkdistr commit f683dfb6c76ff6df2d68031e19d37532843509f9 Author: Gerlof Langeveld Date: Sun Oct 14 13:23:01 2012 +0200 Various modifications to cooperate properly with the netatop kernel module and the netatopd daemon. Update of man-page. Simplified the generation of the version number. M Makefile A atopsar M deviate.c M man/atop.1 M mkversion M netatopif.c M photosyst.c M showlinux.c D version.SKEL A version.h commit 6807de7c036f1f375b7f80a33525b6eff02b03f8 Author: Gerlof Langeveld Date: Sat Sep 15 12:15:31 2012 +0200 Boot time is determined now with a high resolution clock to be able to determine the start time of a process more precise (needed to make a better match with process accounting/netatop). M Makefile M atop.c M atop.h M deviate.c M photoproc.c M photosyst.c M procdbase.c M various.c commit 6526ea3da42807c7c94a055c5d90252899f8b059 Author: Gerlof Langeveld Date: Fri Sep 14 23:18:06 2012 +0200 Further cooperation implemented between atop and netatop/netatopd. M Makefile M acctproc.c M atop.c M atop.h D atopnetif.c M atopsar.c M deviate.c A netatopd.h A netatopif.c M parseable.c M photoproc.c M photoproc.h M showgeneric.c M showlinux.c M showprocs.c M various.c commit cc8cd6572d7541dfc82d0df09690b5b93bcdcf25 Author: Gerlof Langeveld Date: Fri Sep 14 23:06:54 2012 +0200 When pid is in the process accounting record, no further check on the btime (begin-time) is required. M procdbase.c commit 129895d44071290750f13ce08df7cf80f534136a Author: Gerlof Langeveld Date: Wed Aug 29 09:03:46 2012 +0200 Remove source code related to the kernel patches. Insert new code to support the kernel module 'netatop'. Add shared memory figures to MEM line. M Makefile M atop.c D atopnet.h M atopnetif.c M atopsar.c M deviate.c M man/atop.1 A netatop.h M parseable.c M photoproc.c M photosyst.c M photosyst.h M showgeneric.c M showlinux.c M showlinux.h M showprocs.c M showsys.c commit 73bffb6f37e02d5272fbfeb64ada43773fd585e6 Author: Gerlof Langeveld Date: Wed Aug 8 16:53:07 2012 +0200 WRDSK is normalized with WCANCEL to determine how much real disk transfer is done per process. M showgeneric.c M showlinux.c M showlinux.h M showprocs.c commit 361f1d2c877d6316b6339239d81c94aadde62617 Author: Gerlof Langeveld Date: Wed Aug 8 16:01:12 2012 +0200 Removed unused counters for raw network sends/receives. M acctproc.c M atopsar.c M deviate.c M parseable.c M photoproc.c M photoproc.h M showgeneric.c M showlinux.c M showlinux.h M showprocs.c commit e11e259fd35c7be4fcab96d48a818ca222b7fa51 Author: Gerlof Langeveld Date: Wed Aug 8 15:49:20 2012 +0200 Remove code for kernel patches and introduce kernel module 'atopnet'. M Makefile M acctproc.c M atop.c M atop.h A atopnet.h A atopnetif.c M atopsar.c M deviate.c M parseable.c M photoproc.c M showgeneric.c M showlinux.c M showlinux.h M showprocs.c commit 8c9de7a781247b2591d00fc9e5c9a4f3674b0491 Author: Gerlof Langeveld Date: Mon Jul 23 11:12:33 2012 +0200 Removed unused variable 'columnprefix'. M Makefile M showlinux.c commit eb5da90ccb0246ba9040c158c82589c9e5fffe39 Author: Gerlof Langeveld Date: Mon Jul 23 11:04:45 2012 +0200 Minor corrections. M Makefile M mkdistr commit 9c0c2287ed60619dc2a688b2e4242c7ded582026 Author: Gerlof Langeveld Date: Sun Jul 22 11:30:51 2012 +0200 Improved RPM handling. M Makefile M mkdistr commit b1bb45f1d9a61fcd81cebf417cccadac68ddde67 Author: Gerlof Langeveld Date: Fri Jul 20 15:19:35 2012 +0200 Add service file for systemd without installing. A atop.service M mkdistr commit 409be5867b31d37f138447110d234b2325902cdf Author: Gerlof Langeveld Date: Fri Jul 20 15:18:10 2012 +0200 Corrected typo in help messages. M showgeneric.c commit 4ea9f1ab0c500d47ae74544f90353c6190b8e317 Author: Gerlof Langeveld Date: Fri Jul 20 12:09:17 2012 +0200 Modified description. M atop.spec M man/atop.1 M man/atopsar.1 commit a98a0d1ad85aaa082fda535cbb9844a0a4591034 Author: Gerlof Langeveld Date: Fri Jul 20 12:02:17 2012 +0200 ChangeLog removed (not needed any more when using git). D ChangeLog commit af0f1fad5438374912c167f284653b87c62a3142 Author: Gerlof Langeveld Date: Fri Jul 20 12:01:06 2012 +0200 Added LSB header. M atop.init commit d5a9b854674ae451636815e539c4c056365708b2 Author: Gerlof Langeveld Date: Fri Jul 20 10:12:31 2012 +0200 Clarified comments about the use of coloring. M showsys.c commit 1b38444596097776f88415091d27efee4f2dee9f Author: Gerlof Langeveld Date: Fri Jul 20 10:01:38 2012 +0200 Solved division-by-zero when maxfreq=0 and more precise coloring of concerning CPU-values when CPU overloaded. M showsys.c commit 826caafb1aaf892e0692d4315a324093ece2da32 Author: Gerlof Langeveld Date: Fri Jul 20 10:00:53 2012 +0200 Correct typo's in description of frequency scaling. M man/atop.1 commit f266aafb596880c8fe8bcf6f4ae662889803b7c3 Author: Gerlof Langeveld Date: Thu Jul 19 08:24:33 2012 +0200 If setuid-root is set for atop, root-privileges are regained when reading /proc/pid/io (nowadays only readable for root) to obtain the disk stats per process. M photoproc.c commit 9e77a3bccfa345eb8a4a7b1a417343f80a5ae792 Author: Gerlof Langeveld Date: Thu Jul 19 07:51:43 2012 +0200 Email address updated in README and ChangeLog added to package. M README M mkdistr commit 1ee760110035966d444f057cdaf2f0784244b4c8 Author: Gerlof Langeveld Date: Wed Jul 18 11:37:29 2012 +0200 Added EMC Power device recognition. M photosyst.c commit 4aa9c986f8bb469ad38e46db46d7bc1766f4cea0 Author: Gerlof Langeveld Date: Wed Jul 18 09:25:42 2012 +0200 Better recognition of version of process accounting file. M acctproc.c commit 9c8dcc365631a38df69ddc98a94b28ca71666679 Author: Gerlof Langeveld Date: Wed Jul 18 09:21:36 2012 +0200 Improved error handling when not enough columns or lines. M man/atop.1 M man/atopsar.1 M showgeneric.c commit ab6f072b5b85df575c40fd68583052833c09bd48 Author: Gerlof Langeveld Date: Tue Jul 17 14:29:08 2012 +0200 Suppress sorting of system resources by key F or flag -F (toggle). M man/atop.1 M man/atoprc.5 M showgeneric.c M showgeneric.h commit 3b0922c3c371ffecab00f6df72bc8b8852ae8e15 Author: Gerlof Langeveld Date: Tue Jul 17 13:29:45 2012 +0200 Give clearer error message if the format of the rawlog is incompatible. M rawlog.c commit 7c17a309ef97a59a8ee1f5a593f48eeac9d46bc8 Author: Gerlof Langeveld Date: Tue Jul 17 12:57:25 2012 +0200 Create unique /tmp name for decompressed raw file. M man/atop.1 M rawlog.c commit 0f693c1f651c02ecbfbedf49bafdc879c2479184 Author: Gerlof Langeveld Date: Tue Jul 17 11:28:20 2012 +0200 Numerous cosmetic changes and man-page updates. M acctproc.c M deviate.c M man/atop.1 M man/atoprc.5 M man/atopsar.1 M photosyst.c M photosyst.h M showlinux.c M showlinux.h M showprocs.c M showsys.c commit 2a637eaa2ba734c1ae2cdc2d6caab8bc66bf7782 Author: Gerlof Langeveld Date: Fri Jun 15 10:41:45 2012 +0200 Improved screen handling. Limited maximum file-size for process accounting file (200 MiB). M acctproc.h M showgeneric.c commit 86e9448c2cd8e0f3bc1b138dfc98b6701f0afa2c Author: Gerlof Langeveld Date: Thu Jun 14 17:09:15 2012 +0200 Improved handling of process accounting: - Per sample not more than 50 MiB are allowed for process accounting records, which means about 72000 processes. This avoids atop to explode in memory when a huge amount of processes died within one sample. - When only one atop-process is busy and it detects that the process accounting file exceeds .5 GiB, it will truncate the accounting file to zero. M acctproc.c M acctproc.h M atop.c M atop.h M atopsar.c M deviate.c M mkdistr M parseable.c M parseable.h M photoproc.h M rawlog.c M showgeneric.c M showgeneric.h M showlinux.c M showlinux.h M showsys.c commit 0178cdeba8f654816c082118c046978c94869343 Author: Gerlof Langeveld Date: Wed Jun 13 15:43:55 2012 +0200 Cosmetical changes. M atop.c M showsys.c commit 428524129548ede14d535a8c2c23ff5e0af2d54c Author: Gerlof Langeveld Date: Wed Jun 13 13:12:39 2012 +0200 New key 'S' to make selections of system resources like logical volumes, disks and network interfaces (regular expression). M man/atop.1 M showgeneric.c M showgeneric.h M showlinux.c commit 3fff5cfc8e01fceb1e69ff067e73a5d86ae12c48 Author: Gerlof Langeveld Date: Wed Jun 13 12:16:54 2012 +0200 Use of arrow-keys and PgUp/PgDown for vertical scroll. Use of -> and <- keys for horizontal scroll of command line. Increment of maximum number of system resources (e.g. MAXCPU). M photoproc.h M photosyst.h M showgeneric.c M showprocs.c commit 7671b76506743c0a9d82f77674788a045ea0a427 Author: Gerlof Langeveld Date: Sat Jun 9 12:28:58 2012 +0200 Improved generation of new version. A atop.spec M mkdistr commit 2c87df01b06c588ce205c1dcdf8bd30889e27b1b Author: Gerlof Langeveld Date: Sat Jun 9 11:07:03 2012 +0200 Support statistics for virtio disks (vd*). M photosyst.c commit c0c9238f3667d4916cad4eeb16baa861de7e4527 Author: Gerlof Langeveld Date: Sat Jun 9 11:04:22 2012 +0200 Uniform handling of failing mallocs. M atop.c M atop.h M atopsar.c M deviate.c M mkdistr M photoproc.h M procdbase.c M rawlog.c M showgeneric.c M various.c commit 0682920a7b41e2007dac1470996d945e55b0fc21 Author: Gerlof Langeveld Date: Tue Jun 5 15:44:04 2012 +0200 Fetching and displaying of individual threads. M acctproc.c M acctproc.h M atop.c M atop.h M atopsar.c M deviate.c M man/atop.1 M parseable.c M parseable.h M photoproc.c M photoproc.h M procdbase.c M rawlog.c M showgeneric.c M showgeneric.h M showlinux.c M showlinux.h M showprocs.c M showsys.c commit 10f54f1caa904b98f270a92d5fdcafe259d88773 Author: Gerlof Langeveld Date: Mon May 28 11:23:43 2012 +0200 Increase maximum number of disks, lvm's, interfaces and CPUs. M photosyst.c M photosyst.h commit 27fe64e140a62220a0e7fee04431be4756c0047d Author: Gerlof Langeveld Date: Mon May 28 11:22:49 2012 +0200 Show message instead of #exits when process accounting could not be switched on. M showsys.c commit 90b7a438c226fd0ce4e8f8680ece4b67ea5a87a8 Author: Gerlof Langeveld Date: Mon May 28 11:21:53 2012 +0200 Proper handling of lock added. M atop.init commit 30165361059b75acbae534b21eee2465727f05f7 Author: Gerlof Langeveld Date: Mon Mar 5 09:06:57 2012 +0100 Add various details about the memory usage of processes, like stack size, data size, shared library size and size used on swap. M acctproc.c M deviate.c M man/atop.1 M parseable.c M photoproc.c M photoproc.h M photosyst.h M showgeneric.c M showlinux.c M showlinux.h M showprocs.c commit 5c65b96129124fcdd9105d90d11bc46a46b0ec9a Author: Gerlof Langeveld Date: Tue Sep 13 10:20:22 2011 +0200 Show new value about swap space usage per process. M acctproc.c M deviate.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 25ffd8313a499b480f38e493eb50bf4c5a8bec1b Author: Gerlof Langeveld Date: Tue Sep 13 07:52:15 2011 +0200 Color vmlim and vmcom adapted. M showsys.c commit eff004b034980224bff10baf14eee598fdd5f470 Author: Gerlof Langeveld Date: Wed Sep 7 15:34:12 2011 +0200 Colors are shown now for separate system-level counters instead of for the entire line with counters. M showgeneric.c M showgeneric.h M showlinux.c M showlinux.h M showsys.c commit 2358e3fe0445973c78226d25aa13da02f1dd61d9 Author: Gerlof Langeveld Date: Tue Sep 6 09:54:42 2011 +0200 Git-based determination of the version of atop. A mkdistr A mkversion A version.SKEL D version.c commit 87852e1b1b2d87b26c222fe7abec024570465a48 Author: Gerlof Langeveld Date: Tue Sep 6 08:59:36 2011 +0200 Enhanced security: improved dropping of root privileges. M acctproc.c M atop.c M atop.h M atopsar.c M deviate.c M rawlog.c M various.c commit 1f0c1bb1b9ad52abfc62147465ccf61e25f5a7f8 Author: Gerlof Langeveld Date: Mon Sep 5 15:59:44 2011 +0200 Avoid error messages during startup of atop about not being able to activate process accounting (e.g. when starting without root privs). The reason of the error will now be displayed instead of the '#exit' counter. M acctproc.c M atop.c M atop.h M man/atop.1 M showsys.c commit fb9ed3f5079344a93cdc29bd415710ef753fcbf8 Author: Gerlof Langeveld Date: Mon Sep 5 14:04:31 2011 +0200 Initial version A 45atoppm A AUTHOR A COPYING A ChangeLog A Makefile A README A acctproc.c A acctproc.h A atop.c A atop.cron A atop.daily A atop.h A atop.init A atopsar.c A deviate.c A ifprop.c A ifprop.h A man/atop.1 A man/atoprc.5 A man/atopsar.1 A netstats.h A parseable.c A parseable.h A photoproc.c A photoproc.h A photosyst.c A photosyst.h A procdbase.c A psaccs_atop A psaccu_atop A rawlog.c A showgeneric.c A showgeneric.h A showlinux.c A showlinux.h A showprocs.c A showsys.c A various.c A version.c atop-2.4.0/45atoppm0000775000203100020310000000224213416466037013373 0ustar gerlofgerlof#!/bin/sh . "${PM_FUNCTIONS}" LOGPATH=/var/log/atop BINPATH=/usr/bin PIDFILE=/var/run/atop.pid INTERVAL=600 # interval 10 minutes CURDAY=`date +%Y%m%d` # current date in same format # If the system suspends, one final sample will be taken for the logfile # suspend_atop() { if [ -e $PIDFILE ] && ps -p `cat $PIDFILE` | grep 'atop$' > /dev/null then kill -USR2 `cat $PIDFILE` # final sample and terminate CNT=0 while ps -p `cat $PIDFILE` > /dev/null do let CNT+=1 if [ $CNT -gt 5 ] then break; fi sleep 1 done fi } # If the system resumes, a new atop will be started (similar to boot) # resume_atop() { # in case atop is running, stop it # if [ -e $PIDFILE ] && ps -p `cat $PIDFILE` | grep 'atop$' > /dev/null then kill -TERM `cat $PIDFILE` rm $PIDFILE sleep 1 fi # start atop # $BINPATH/atop -R -w $LOGPATH/atop_$CURDAY $INTERVAL \ > $LOGPATH/daily.log 2>&1 & echo $! > $PIDFILE # delete logfiles older than four weeks # ( sleep 3; find $LOGPATH -name 'atop_*' -mtime +28 -exec rm {} \; )& exit 0 } case "$1" in hibernate|suspend) suspend_atop ;; thaw|resume) resume_atop ;; *) exit $NA ;; esac atop-2.4.0/atop-pm.sh0000775000203100020310000000022413416466037013706 0ustar gerlofgerlof#!/bin/bash case "$1" in pre) /usr/bin/systemctl stop atop exit 0 ;; post) /usr/bin/systemctl start atop exit 0 ;; *) exit 1 ;; esac atop-2.4.0/Makefile0000664000203100020310000001601113416466037013433 0ustar gerlofgerlof# Makefile for System & Process Monitor ATOP (Linux version) # # Gerlof Langeveld - gerlof.langeveld@atoptool.nl # DESTDIR = BINPATH = /usr/bin SBINPATH = /usr/sbin SCRPATH = /usr/share/atop LOGPATH = /var/log/atop MAN1PATH = /usr/share/man/man1 MAN5PATH = /usr/share/man/man5 MAN8PATH = /usr/share/man/man8 INIPATH = /etc/init.d SYSDPATH = /usr/lib/systemd/system CRNPATH = /etc/cron.d ROTPATH = /etc/logrotate.d PMPATH1 = /usr/lib/pm-utils/sleep.d PMPATH2 = /usr/lib64/pm-utils/sleep.d PMPATHD = /usr/lib/systemd/system-sleep CFLAGS += -O2 -I. -Wall # -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 OBJMOD4 = atopsar.o netatopif.o gpucom.o ALLMODS = $(OBJMOD0) $(OBJMOD1) $(OBJMOD2) $(OBJMOD3) $(OBJMOD4) VERS = $(shell ./atop -V 2>/dev/null| sed -e 's/^[^ ]* //' -e 's/ .*//') all: atop atopsar atopacctd atopconvert atop: atop.o $(ALLMODS) Makefile $(CC) -c version.c $(CC) atop.o $(ALLMODS) -o atop -lncurses -lz -lm -lrt $(LDFLAGS) atopsar: atop ln -sf atop atopsar atopacctd: atopacctd.o netlink.o $(CC) atopacctd.o netlink.o -o atopacctd $(LDFLAGS) atopconvert: atopconvert.o $(CC) atopconvert.o -o atopconvert -lz $(LDFLAGS) netlink.o: netlink.c $(CC) -I. -Wall -c netlink.c clean: rm -f *.o atop atopacctd atopconvert distr: rm -f *.o atop tar czvf /tmp/atop.tar.gz * install: @echo Choose either \'make systemdinstall\' or \'make sysvinstall\' systemdinstall: genericinstall if [ ! -d $(DESTDIR)$(SYSDPATH) ]; \ then mkdir -p $(DESTDIR)$(SYSDPATH); fi if [ ! -d $(DESTDIR)$(PMPATHD) ]; \ then mkdir -p $(DESTDIR)$(PMPATHD); fi # cp atop.service $(DESTDIR)$(SYSDPATH) chmod 0644 $(DESTDIR)$(SYSDPATH)/atop.service cp atopgpu.service $(DESTDIR)$(SYSDPATH) chmod 0644 $(DESTDIR)$(SYSDPATH)/atopgpu.service cp atopacct.service $(DESTDIR)$(SYSDPATH) chmod 0644 $(DESTDIR)$(SYSDPATH)/atopacct.service cp atop.cronsystemd $(DESTDIR)$(CRNPATH)/atop cp atop-pm.sh $(DESTDIR)$(PMPATHD) chmod 0711 $(DESTDIR)$(PMPATHD)/atop-pm.sh # # only when making on target system: # if [ -z "$(DESTDIR)" -a -f /bin/systemctl ]; \ then /bin/systemctl stop atop 2> /dev/null; \ /bin/systemctl disable atop 2> /dev/null; \ /bin/systemctl stop atopacct 2> /dev/null; \ /bin/systemctl disable atopacct 2> /dev/null; \ /bin/systemctl enable atopacct; \ /bin/systemctl start atopacct; \ /bin/systemctl enable atop; \ /bin/systemctl start atop; \ fi sysvinstall: genericinstall if [ ! -d $(DESTDIR)$(INIPATH) ]; \ then mkdir -p $(DESTDIR)$(INIPATH); fi # cp atop.init $(DESTDIR)$(INIPATH)/atop cp atopacct.init $(DESTDIR)$(INIPATH)/atopacct cp atop.cronsysv $(DESTDIR)$(CRNPATH)/atop # if [ -d $(DESTDIR)$(PMPATH1) ]; \ then cp 45atoppm $(DESTDIR)$(PMPATH1); \ chmod 0711 $(DESTDIR)$(PMPATH1)/45atoppm; \ fi if [ -d $(DESTDIR)$(PMPATH2) ]; \ then cp 45atoppm $(DESTDIR)$(PMPATH2); \ chmod 0711 $(DESTDIR)$(PMPATH2)/45atoppm; \ fi # # # only when making on target system: # if [ -z "$(DESTDIR)" -a -f /sbin/chkconfig ]; \ then /sbin/chkconfig --del atop 2> /dev/null; \ /sbin/chkconfig --add atop; \ /sbin/chkconfig --del atopacct 2> /dev/null; \ /sbin/chkconfig --add atopacct; \ fi if [ -z "$(DESTDIR)" -a -f /usr/sbin/update-rc.d ]; \ then update-rc.d atop defaults; \ update-rc.d atopacct defaults; \ fi if [ -z "$(DESTDIR)" -a -f /sbin/service ]; \ then /sbin/service atopacct start; \ sleep 2; \ /sbin/service atop start; \ fi genericinstall: atop atopacctd atopconvert if [ ! -d $(DESTDIR)$(LOGPATH) ]; \ then mkdir -p $(DESTDIR)$(LOGPATH); fi if [ ! -d $(DESTDIR)$(BINPATH) ]; \ then mkdir -p $(DESTDIR)$(BINPATH); fi if [ ! -d $(DESTDIR)$(SBINPATH) ]; \ then mkdir -p $(DESTDIR)$(SBINPATH); fi if [ ! -d $(DESTDIR)$(SCRPATH) ]; \ then mkdir -p $(DESTDIR)$(SCRPATH); fi if [ ! -d $(DESTDIR)$(MAN1PATH) ]; \ then mkdir -p $(DESTDIR)$(MAN1PATH); fi if [ ! -d $(DESTDIR)$(MAN5PATH) ]; \ then mkdir -p $(DESTDIR)$(MAN5PATH); fi if [ ! -d $(DESTDIR)$(MAN8PATH) ]; \ then mkdir -p $(DESTDIR)$(MAN8PATH); fi if [ ! -d $(DESTDIR)$(CRNPATH) ]; \ then mkdir -p $(DESTDIR)$(CRNPATH); fi if [ ! -d $(DESTDIR)$(ROTPATH) ]; \ then mkdir -p $(DESTDIR)$(ROTPATH); fi # cp atop $(DESTDIR)$(BINPATH)/atop chown root $(DESTDIR)$(BINPATH)/atop chmod 04711 $(DESTDIR)$(BINPATH)/atop ln -sf atop $(DESTDIR)$(BINPATH)/atopsar cp atopacctd $(DESTDIR)$(SBINPATH)/atopacctd chown root $(DESTDIR)$(SBINPATH)/atopacctd chmod 0700 $(DESTDIR)$(SBINPATH)/atopacctd cp atopgpud $(DESTDIR)$(SBINPATH)/atopgpud chown root $(DESTDIR)$(SBINPATH)/atopgpud chmod 0700 $(DESTDIR)$(SBINPATH)/atopgpud cp atop $(DESTDIR)$(BINPATH)/atop-$(VERS) ln -sf atop-$(VERS) $(DESTDIR)$(BINPATH)/atopsar-$(VERS) cp atopconvert $(DESTDIR)$(BINPATH)/atopconvert chown root $(DESTDIR)$(BINPATH)/atopconvert chmod 0711 $(DESTDIR)$(BINPATH)/atopconvert cp atop.daily $(DESTDIR)$(SCRPATH) chmod 0711 $(DESTDIR)$(SCRPATH)/atop.daily cp man/atop.1 $(DESTDIR)$(MAN1PATH) cp man/atopsar.1 $(DESTDIR)$(MAN1PATH) cp man/atopconvert.1 $(DESTDIR)$(MAN1PATH) cp man/atoprc.5 $(DESTDIR)$(MAN5PATH) cp man/atopacctd.8 $(DESTDIR)$(MAN8PATH) cp man/atopgpud.8 $(DESTDIR)$(MAN8PATH) cp psaccs_atop $(DESTDIR)$(ROTPATH)/psaccs_atop cp psaccu_atop $(DESTDIR)$(ROTPATH)/psaccu_atop touch $(DESTDIR)$(LOGPATH)/dummy_before touch $(DESTDIR)$(LOGPATH)/dummy_after ########################################################################## versdate.h: ./mkdate atop.o: atop.h photoproc.h photosyst.h acctproc.h showgeneric.h atopsar.o: atop.h photoproc.h photosyst.h rawlog.o: atop.h photoproc.h photosyst.h showgeneric.h various.o: atop.h acctproc.h ifprop.o: atop.h photosyst.h ifprop.h parseable.o: atop.h photoproc.h photosyst.h parseable.h deviate.o: atop.h photoproc.h photosyst.h procdbase.o: atop.h photoproc.h acctproc.o: atop.h photoproc.h atopacctd.h acctproc.h netatop.h netatopif.o: atop.h photoproc.h netatopd.h netatop.h photoproc.o: atop.h photoproc.h photosyst.o: atop.h photosyst.h showgeneric.o: atop.h photoproc.h photosyst.h showgeneric.h showlinux.h 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 version.o: version.c version.h versdate.h gpucom.o: atop.h photoproc.h photosyst.h atopacctd.o: atop.h photoproc.h acctproc.h atopacctd.h version.h versdate.h atopconvert.o: atop.h photoproc.h photosyst.h atop-2.4.0/README0000664000203100020310000000442213416466037012656 0ustar gerlofgerlofDEPENDENCIES Install the following packages to be able to build atop: * zlib-devel or libz-dev (depending on the distribution) * ncurses-devel or libncurses5-dev (depending on the distribution) Install the following packages to be able to run atop: * zlib * ncurses INSTALLING AND USING ATOP For interactive use, it is sufficient to install ATOP with the command (as root): make systemdinstall or make sysvinstall For automatic logging in compressed binary format, see the description in the manual-page. The kernel module 'netatop' can be downloaded and installed separately from www.atoptool.nl/downloadnetatop.php This module is optional and can be used to gather network statistics per process/thread as described in www.atoptool.nl/netatop.php KERNEL ISSUES WITH PROCESS ACCOUNTING ------------------------------------- Newer upstream kernels (e.g. 4.8 and 4.9)have two issuess with process accounting: 1) Sometimes process accounting does not work at all¹. Atopacctd tries to work around this issue, by retrying to initialize process accounting several times. 2) When using the NETLINK inface, the command TASKSTATS_CMD_GET consequently returns -EINVAL². Atopacctd needs NETLINK to be able to be triggered that some process in the system has finished. In this way, atopacctd can be in a blocking state as long as no processes terminate. When atopacctd detects that NETLINK fails, it switches into a polling mode to periodically try if it can read process accounting records as a workaround. This issue has to do with cpumasks and you can work-around it by building a kernel that has CONFIG_NR_CPUS configured to exactly the amount of CPUs (logical CPUs) in the system the kernel runs on. You can find this kernel option under "Processor type and features" --> "Maximum number of CPUs". [1] Bug 190271 - process accounting sometimes does not work https://bugzilla.kernel.org/show_bug.cgi?id=190271 [2] Bug 190711 - Process accounting: Using the NETLINK interface, the command TASKSTATS_CMD_GET returns -EINVAL https://bugzilla.kernel.org/show_bug.cgi?id=190711 Linux kernel mailing list thread: [REGRESSION] Two issues that prevent process accounting (taskstats) from working correctly https://lkml.org/lkml/2016/12/19/182 Gerlof Langeveld gerlof.langeveld@atoptool.nl atop-2.4.0/AUTHOR0000644000203100020310000000006013416466037012713 0ustar gerlofgerlofGerlof Langeveld atop-2.4.0/COPYING0000644000203100020310000004313113416466037013027 0ustar gerlofgerlof GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 of the License, 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 Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. atop-2.4.0/atopacct.init0000775000203100020310000000324013416466037014461 0ustar gerlofgerlof#!/bin/sh # # atopacctd Startup script for the atopacctd daemon # # chkconfig: 2345 91 9 # description: Process accounting control # ### BEGIN INIT INFO # Provides: atopacct # Required-Start: $local_fs # Required-Stop: $local_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: This daemon switches on process accounting and # transfers the process accounting records 'realtime' # to small shadow files to avoid huge disk space usage # Description: Process accounting control ### END INIT INFO # Check existance of binaries [ -f /usr/sbin/atopacctd ] || exit 0 RETVAL=0 # See how we were called. case "$1" in start) # Check if process accounting already in use via psacct # for PACCTFILE in /var/account/pacct /var/log/pacct do if [ -f "$PACCTFILE" ] # file exists? then BEFORSIZE=$(ls -lL "$PACCTFILE" | awk '{print $5}') AFTERSIZE=$(ls -lL "$PACCTFILE" | awk '{print $5}') # verify if accounting file grows, so is in use # if [ $BEFORSIZE -lt $AFTERSIZE ] then echo Process accounting already used by psacct! >&2 exit $RETVAL # do not start atopacctd fi fi done # Check if atopacctd runs already # if ps -e | grep -q atopacctd$ then : else # Start atopacctd rm -rf /var/run/pacct_shadow.d 2> /dev/null /usr/sbin/atopacctd fi touch /var/lock/subsys/atopacctd ;; stop) # Check if atopacctd runs # if ps -e | grep -q atopacctd$ then kill $(ps -e | grep atopacctd$ | sed 's/^ *//' | cut -d' ' -f1) fi rm /var/lock/subsys/atopacctd ;; status) ;; reload) ;; restart) ;; *) echo "Usage: $0 [start|stop]" exit 1 esac exit $RETVAL atop-2.4.0/atopacct.service0000664000203100020310000000041513416466037015154 0ustar gerlofgerlof[Unit] Description=Atop process accounting daemon Documentation=man:atopacctd(8) Conflicts=psacct.service After=syslog.target Before=atop.service [Service] Type=forking PIDFile=/var/run/atopacctd.pid ExecStart=/usr/sbin/atopacctd [Install] WantedBy=multi-user.target atop-2.4.0/atopgpu.service0000644000203100020310000000033613416466037015035 0ustar gerlofgerlof[Unit] Description=Atop GPU stats daemon Documentation=man:atopgpud(8) After=syslog.target Before=atop.service [Service] ExecStart=/usr/sbin/atopgpud Type=oneshot RemainAfterExit=yes [Install] WantedBy=multi-user.target atop-2.4.0/atop.cronsysv0000664000203100020310000000011713416466037014546 0ustar gerlofgerlof# daily restart of atop at midnight 0 0 * * * root /usr/share/atop/atop.daily& atop-2.4.0/atop.cronsystemd0000664000203100020310000000011213416466037015225 0ustar gerlofgerlof# daily restart of atop at midnight 0 0 * * * root systemctl restart atop atop-2.4.0/atop.daily0000775000203100020310000000257413416466037013776 0ustar gerlofgerlof#!/bin/bash LOGOPTS="-R" # default options LOGINTERVAL=600 # default interval in seconds LOGGENERATIONS=28 # default number of days # allow administrator to overrule the variables # defined above # DEFAULTSFILE=/etc/default/atop # possibility to overrule vars if [ -e "$DEFAULTSFILE" ] then . "$DEFAULTSFILE" # validate overruled variables # (LOGOPTS and LOGINTERVAL are implicitly by atop) # case "$LOGGENERATIONS" in ''|*[!0-9]*) echo non-numerical value for LOGGENERATIONS >&2 exit 1;; esac fi CURDAY=`date +%Y%m%d` LOGPATH=/var/log/atop BINPATH=/usr/bin PIDFILE=/var/run/atop.pid # verify if atop still runs for daily logging # if [ -e "$PIDFILE" ] && ps -p `cat "$PIDFILE"` | grep 'atop$' > /dev/null then kill -USR2 `cat "$PIDFILE"` # final sample and terminate CNT=0 while ps -p `cat "$PIDFILE"` > /dev/null do let CNT+=1 if [ $CNT -gt 5 ] then break; fi sleep 1 done rm "$PIDFILE" fi # delete logfiles older than N days (configurable) # start a child shell that activates another child shell in # the background to avoid a zombie # ( (sleep 3; find "$LOGPATH" -name 'atop_*' -mtime +"$LOGGENERATIONS" -exec rm {} \;)& ) # activate atop with an interval of S seconds (configurable), # replacing the current shell # echo $$ > $PIDFILE exec $BINPATH/atop $LOGOPTS -w "$LOGPATH"/atop_"$CURDAY" "$LOGINTERVAL" > "$LOGPATH/daily.log" 2>&1 atop-2.4.0/atop.init0000775000203100020310000000251413416466037013631 0ustar gerlofgerlof#!/bin/bash # # atop Startup script for the Atop process logging in background # # chkconfig: 2345 96 4 # description: Advanced system and process activity monitor # ### BEGIN INIT INFO # Provides: atop # Required-Start: $local_fs # Required-Stop: $local_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Advanced system and process activity monitor # Description: Advanced system and process activity monitor ### END INIT INFO # Check existance of binaries [ -f /usr/bin/atop ] || exit 0 PIDFILE=/var/run/atop.pid RETVAL=0 # See how we were called. case "$1" in start) # Check if atop runs already # if [ -e $PIDFILE ] && ps -p `cat $PIDFILE` | grep 'atop$' > /dev/null then : else # Start atop /usr/share/atop/atop.daily& fi touch /var/lock/subsys/atop ;; stop) # Check if atop runs # if [ -e $PIDFILE ] && ps -p `cat $PIDFILE` | grep 'atop$' > /dev/null then kill -USR2 `cat $PIDFILE` # final sample and terminate CNT=0 while ps -p `cat $PIDFILE` > /dev/null do let CNT+=1 if [ $CNT -gt 5 ] then break; fi sleep 1 done rm $PIDFILE fi rm /var/lock/subsys/atop ;; status) ;; reload) /usr/share/atop/atop.daily& ;; restart) /usr/share/atop/atop.daily& ;; *) echo "Usage: $0 [start|stop|status|reload|restart]" exit 1 esac exit $RETVAL atop-2.4.0/atop.service0000664000203100020310000000034313416466037014321 0ustar gerlofgerlof[Unit] Description=Atop advanced performance monitor Documentation=man:atop(1) [Service] Type=simple ExecStart=/usr/share/atop/atop.daily KillSignal=SIGUSR2 #ExecStopPost=/usr/bin/sleep 3 [Install] WantedBy=multi-user.target atop-2.4.0/psaccs_atop0000664000203100020310000000175713416466037014230 0ustar gerlofgerlof# Logrotate file to take action before psacct is rotated /var/log/atop/dummy_before { missingok daily rotate 0 ifempty create 0600 root root postrotate # check if process accounting is installed # if [ -e /etc/logrotate.d/psacct ] then # check if process accounting is actually in use # ACCTFILE=`awk '$2 == "{" {print $1}' /etc/logrotate.d/psacct` if [ -f "$ACCTFILE" ] then ACCTSIZE1=`ls -l "$ACCTFILE" | awk '{print $5}'` ACCTSIZE2=`ls -l "$ACCTFILE" | awk '{print $5}'` if [ $ACCTSIZE1 -lt $ACCTSIZE2 ] then # stop atop daemon before accounting file # is rotated # PIDFILE=/var/run/atop.pid if [ -e $PIDFILE ] && \ ps -p `cat $PIDFILE` | grep 'atop$' > /dev/null then kill -USR2 `cat $PIDFILE` # take final sample rm $PIDFILE sleep 1 fi fi fi fi endscript } atop-2.4.0/psaccu_atop0000664000203100020310000000100713416466037014216 0ustar gerlofgerlof# Logrotate file to take action after psacct is rotated /var/log/atop/dummy_after { missingok daily rotate 0 ifempty create 0600 root root postrotate if [ -e /etc/logrotate.d/psacct ] then # if the atop daemon does not run, restart it after # accounting file is rotated PIDFILE=/var/run/atop.pid if [ -e $PIDFILE ] && \ ps -p `cat $PIDFILE` | grep 'atop$' > /dev/null then : else /usr/share/atop/atop.daily& fi fi endscript } atop-2.4.0/atopgpud0000755000203100020310000004427313416466037013555 0ustar gerlofgerlof#!/usr/bin/python -Es # ============================================================== # Daemon that gathers statistical information from all # Nvidia GPUs in the current system. Every second, it gathers # the statistics of every GPU and maintains cumulative counters, # globally and per process. # # Client processes can connect to this daemon on TCP port 59123. # Clients can send requests of two bytes, consisting of one byte # request code followed by one byte integer version number. # The request code can be 'T' to obtain the GPU types or 'S' to # obtain all statistical counters. # The response of the daemon starts with a 4-byte integer. The # first byte is the version of the response format and the # subsequent three bytes indicate the length (big endian) of the # response string that follows. See the formatters for the layout # of the response string, later on in this source code. # # Dependencies: pip/pip3 install nvidia-ml-py # # This program can be executed by python2 or python3 (just change # the first line of this source file). # -------------------------------------------------------------- # Author: Gerlof Langeveld # Date: July 2018 (initial) # ============================================================== import os import sys import time import socket import struct import logging import logging.handlers as loghand import threading GPUDPORT = 59123 # TCP port number server COMPUTE = 1 # task support bit value ACCOUNT = 2 # task support bit value # ================================= # GPU related bookkeeping # ================================= gpulist = [] # list with per-GPU bookkeeping cliterm = {} # dict with one entry per client (client # socket as key), that contains a dict with # the terminated per-process bookkeepings # that still have to be received by this client # (pid of terminated process as key) gpulock = threading.Lock() # mutex for access to gpulist/cliterm # ================================= # per-GPU class # ================================= class Stats(object): pass # generic statistics container class GpuProp(object): ############################### # initialization method to setup # properties ############################### def __init__(self, num): gpuhandle = pynvml.nvmlDeviceGetHandleByIndex(num) pciInfo = pynvml.nvmlDeviceGetPciInfo(gpuhandle) 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.tasksupport = 0 # process stats support try: procinfo = pynvml.nvmlDeviceGetComputeRunningProcesses(gpuhandle) self.stats.tasksupport |= COMPUTE # compute support except Exception: pass # no compute support try: pynvml.nvmlDeviceSetAccountingMode(gpuhandle, True) pynvml.nvmlDeviceSetPersistenceMode(gpuhandle, True) # NVIDIA advise self.stats.tasksupport |= ACCOUNT # account support except Exception as e: pass self.stats.gpupercnow = 0 # perc of time that GPU was busy self.stats.mempercnow = 0 # perc of time that memory was rd/wr self.stats.memtotalnow = 0 # in Kb self.stats.memusednow = 0 # in Kb self.stats.gpusamples = 0 self.stats.gpuperccum = 0 # perc of time that GPU was busy self.stats.memperccum = 0 # perc of time that memory was rd/wr self.stats.memusedcum = 0 # in KiB self.stats.procstats = {} # stats of active processes (key = pid) ############################### # method to fetch counters and values ############################### def readstats(self): self.stats.gpusamples += 1 # ----------------------------- # get rates (utilization percentages) # ----------------------------- try: rates = pynvml.nvmlDeviceGetUtilizationRates(self.gpuhandle) self.stats.gpupercnow = rates.gpu self.stats.mempercnow = rates.memory self.stats.gpuperccum += rates.gpu self.stats.memperccum += rates.memory except pynvml.NVMLError as err: self.stats.gpupercnow = -1 self.stats.mempercnow = -1 self.stats.gpuperccum = -1 self.stats.memperccum = -1 # ----------------------------- # get memory occupation GPU-wide # ----------------------------- try: meminfo = pynvml.nvmlDeviceGetMemoryInfo(self.gpuhandle) self.stats.memtotalnow = meminfo.total // 1024 self.stats.memusednow = meminfo.used // 1024 self.stats.memusedcum += meminfo.used // 1024 # in KiB except pynvml.NVMLError as err: pass # ----------------------------- # get per-process statistics # ----------------------------- try: procinfo = pynvml.nvmlDeviceGetComputeRunningProcesses( self.gpuhandle) # ------------------------- # build list with pids from # the previous interval # ------------------------- actprocs = list(self.stats.procstats.keys()) # ------------------------- # handle proc stats of this # interval # ------------------------- for proc in procinfo: pid = proc.pid # --------------------- # new process? # create new stats # --------------------- if pid not in actprocs: self.stats.procstats[pid] = Stats() self.stats.procstats[pid].memnow = 0 # in KiB self.stats.procstats[pid].memcum = 0 # in KiB self.stats.procstats[pid].sample = 0 self.stats.procstats[pid].gpubusy = -1 self.stats.procstats[pid].membusy = -1 self.stats.procstats[pid].timems = -1 else: actprocs.remove(pid) # --------------------- # maintain proc stats # --------------------- if proc.usedGpuMemory: self.stats.procstats[pid].memnow = proc.usedGpuMemory//1024 self.stats.procstats[pid].memcum += proc.usedGpuMemory//1024 self.stats.procstats[pid].sample += 1 if self.stats.tasksupport & ACCOUNT: try: stats = pynvml.nvmlDeviceGetAccountingStats(self.gpuhandle, pid) self.stats.procstats[pid].gpubusy = stats.gpuUtilization self.stats.procstats[pid].membusy = stats.memoryUtilization self.stats.procstats[pid].timems = stats.time except Exception: pass # ------------------------- # determine which processes # have terminated since # previous sample # ------------------------- for pid in actprocs: for client in cliterm: cliterm[client][pid] = self.stats.procstats[pid] del self.stats.procstats[pid] except pynvml.NVMLError as err: pass ############################### # obtain current statistics ############################### def getstats(self): return self.stats # ================================= # Main function # ================================= def main(): # ----------------------------- # initialize GPU access, # specifically to detect of it # succeeds # ----------------------------- try: pynvml.nvmlInit() except Exception: logging.error("Shared lib 'libnvidia-ml' probably not installed!") sys.exit() # ----------------------------- # open IPv6 stream socket # ----------------------------- try: mysock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM, 0) except Exception as sockex: try: mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) except Exception as sockex: logging.error("Socket creation fails") sys.exit(1) # ----------------------------- # bind to local port and # make socket passive # ----------------------------- try: mysock.bind( ("", GPUDPORT) ) mysock.listen(32) except Exception as sockex: logging.error("Socket binding to port %d fails", GPUDPORT) sys.exit(1) # ----------------------------- # release parent process # (daemonize) # ----------------------------- try: if os.fork(): sys.exit(0) # parent process exits; child continues... except Exception: logging.error("Failed to fork child") # ----------------------------- # initialize GPU access for the # child process # ----------------------------- try: pynvml.nvmlInit() except Exception: pass # ----------------------------- # determine number of GPUs in # this system # ----------------------------- gpunum = pynvml.nvmlDeviceGetCount() logging.info("Number of GPUs: %d", gpunum) if gpunum == 0: logging.info("Terminated (no GPUs available)") sys.exit() # ----------------------------- # initialize per-GPU bookkeeping # ----------------------------- for i in range(gpunum): gpulist.append( GpuProp(i) ) # ----------------------------- # kick off new thread to fetch # statistics periodically # ----------------------------- t = threading.Thread(target=gpuscanner, args=(1,)) t.daemon = True t.start() logging.info("Initialization succeeded") # ----------------------------- # main thread: # await connect of client # ----------------------------- while True: newsock, peeraddr = mysock.accept() # ------------------------- # create new thread to # serve this client # ------------------------- t = threading.Thread(target=serveclient, args=(newsock, peeraddr)) t.daemon = True t.start() # =========================================== # Thread start function: # Serve new client that has just # connected. # # ------------------------------------------- # Protocol between client and server: # # - client transmits request # consisting of two bytes # # byte 0: type of request # 'S' get statistical counters # 'T' get type of each GPU # # byte 1: integer version number # response layout might change # so the client asks for a # specific response version # # - server transmits response # consisting of a four bytes integer # in big endian byte order # # byte 0: version number, preferably # as requested by the client # # byte 1-3: length of the response string # that follows # # followed by the response string that is # version specific (see gpuformatters) # =========================================== def serveclient(sock, peer): # ----------------------------- # create per client bookkeeping # for terminated processes # ----------------------------- with gpulock: cliterm[sock] = {} # ----------------------------- # main loop # ----------------------------- while True: # ------------------------- # wait for request # ------------------------- try: rcvbuf = sock.recv(20) except Exception as sockex: logging.error("Receive error: %s", sockex) sock.close() break # ------------------------- # connection closed by peer? # ------------------------- if not rcvbuf: sock.close() break logging.debug("Received: %s", rcvbuf) # ------------------------- # request has wrong length? # ------------------------- if len(rcvbuf) != 2: logging.error('Wrong request length: %d', len(rcvbuf)) sock.close() break # ------------------------- # valid request: # get statistical counters? # ------------------------- try: command = chr(rcvbuf[0]) # Python3 version = rcvbuf[1] except Exception: command = rcvbuf[0] # Python2 version = ord(rcvbuf[1]) if command == 'S': if version == 0 or version >= len(gpuformatters): version = len(gpuformatters)-1 xmitbuf = gpuformatters[version](sock).encode('ascii', errors='replace') # ------------------------- # valid request: # get GPU types? # ------------------------- elif command == 'T': if version == 0 or version >= len(gpudevnames): version = len(gpudevnames)-1 xmitbuf = gpudevnames[version]().encode('ascii', errors='replace') # ------------------------- # invalid request! # ------------------------- else: logging.error('Wrong request from client: %s', command) sock.close() break # ------------------------- # transmit GPU statistics # as bytes # ------------------------- logging.debug("Send: %s", xmitbuf) prelude = struct.pack(">I", (version << 24) + len(xmitbuf)) try: sock.send(prelude) sock.send(xmitbuf) except Exception as sockex: logging.error("Send error: %s", sockex) sock.close() break # ----------------------------- # delete per client bookkeeping # of terminated processes # ----------------------------- with gpulock: del cliterm[sock] # ----------------------------- # END OF CLIENT THREAD # ----------------------------- # ================================= # Generate sequence of device names # ================================= def gpudevname_v1(): # ----------------------------- # main loop: # - get device name of every GPU # - convert into one string # with format: # numgpus@busid devname tasksupport@busid devname tasksupport@... # ----------------------------- strbuf = str( len(gpulist) ) with gpulock: for i, gpu in enumerate(gpulist): s = gpu.getstats() strbuf += "@{:s} {:s} {:d}".format( s.busid, s.devname, s.tasksupport) return strbuf gpudevnames = [None, gpudevname_v1] # ================================= # Convert statistics of all GPUs # into parseable string # ================================= def gpuformatter_v1(clisock): # ----------------------------- # main loop: # - get statistics for every GPU # - convert stats to one string # with format: # numgpus@gpu0 stats#pid stats#pid stats@gpu1 stats#pid stats@.... # ----------------------------- strbuf = "" with gpulock: for i, gpu in enumerate(gpulist): s = gpu.getstats() # --------------------- # generic GPU stats # --------------------- strbuf += "@{:d} {:d} {:d} {:d} {:d} {:d} {:d} {:d}".format( s.gpupercnow, s.mempercnow, s.memtotalnow, s.memusednow, s.gpusamples, s.gpuperccum, s.memperccum, s.memusedcum); # --------------------- # active processes for # this GPU # --------------------- for pid, stat in s.procstats.items(): strbuf += "#A {:d} {:d} {:d} {:d} {:d} {:d} {:d}".format(pid, stat.gpubusy, stat.membusy, stat.timems, stat.memnow, stat.memcum, stat.sample) # --------------------- # terminated processes # for this GPU # --------------------- for pid, stat in cliterm[clisock].items(): strbuf += "#E {:d} {:d} {:d} {:d} {:d} {:d} {:d}".format(pid, stat.gpubusy, stat.membusy, stat.timems, stat.memnow, stat.memcum, stat.sample) cliterm[clisock].clear() return strbuf gpuformatters = [None, gpuformatter_v1] # ================================= # Thread start function: # Scan all GPUs with a particular # interval to obtain their stats # ================================= def gpuscanner(scaninterval): # ----------------------------- # main loop: # - get statistics for every GPU # - sleep for interval # ----------------------------- while True: with gpulock: for gpu in gpulist: gpu.readstats() time.sleep(scaninterval) # ========================================================================== # ----------------------------- # initialize logging # ----------------------------- if '-v' in sys.argv: loglevel = logging.DEBUG else: loglevel = logging.INFO fm = logging.Formatter('atopgpud %(levelname)s: %(message)s') fh = loghand.SysLogHandler('/dev/log', facility=loghand.SysLogHandler.LOG_DAEMON) fh.setFormatter(fm) fh.setLevel(loglevel) lg = logging.getLogger() # root logger lg.addHandler(fh) lg.setLevel(loglevel) # ----------------------------- # load module pynvml # ----------------------------- try: import pynvml except Exception: logging.error("Python module 'pynvml' not installed!") sys.exit(1) try: # ----------------------------- # call main function # ----------------------------- main() finally: # ----------------------------- # shutdown GPU access # ----------------------------- try: pynvml.nvmlShutdown() except Exception: pass atop-2.4.0/prev/0000775000203100020310000000000013416466037012750 5ustar gerlofgerlofatop-2.4.0/prev/photoproc_20.h0000664000203100020310000000661113416466037015443 0ustar gerlofgerlof/* ** structure containing only relevant process-info extracted ** from kernel's process-administration */ struct tstat_20 { /* GENERAL TASK INFO */ struct gen_20 { 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 ifuture[4]; /* reserved */ } gen; /* CPU STATISTICS */ struct cpu_20 { 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 ifuture[4]; /* reserved for future use */ count_t cfuture[4]; /* reserved for future use */ } cpu; /* DISK STATISTICS */ struct dsk_20 { 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_20 { 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 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) */ } mem; /* NETWORK STATISTICS */ struct net_20 { 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; }; atop-2.4.0/prev/photoproc_21.h0000664000203100020310000000701613416466037015444 0ustar gerlofgerlof/* ** structure containing only relevant process-info extracted ** from kernel's process-administration */ struct tstat_21 { /* GENERAL TASK INFO */ struct gen_21 { 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 envid; /* OpenVZ support */ int ifuture[4]; /* reserved */ } gen; /* CPU STATISTICS */ struct cpu_21 { 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 ifuture[4]; /* reserved for future use */ count_t cfuture[4]; /* reserved for future use */ } cpu; /* DISK STATISTICS */ struct dsk_21 { 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_21 { 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 cfuture[4]; /* reserved for future use */ } mem; /* NETWORK STATISTICS */ struct net_21 { 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; }; atop-2.4.0/prev/photoproc_22.h0000664000203100020310000000707313416466037015450 0ustar gerlofgerlof/* ** structure containing only relevant process-info extracted ** from kernel's process-administration */ struct tstat_22 { /* GENERAL TASK INFO */ struct gen_22 { 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 ifuture[5]; /* reserved */ } gen; /* CPU STATISTICS */ struct cpu_22 { 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 ifuture[4]; /* reserved for future use */ count_t cfuture[4]; /* reserved for future use */ } cpu; /* DISK STATISTICS */ struct dsk_22 { 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_22 { 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 cfuture[4]; /* reserved for future use */ } mem; /* NETWORK STATISTICS */ struct net_22 { 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; }; atop-2.4.0/prev/photoproc_23.h0000664000203100020310000000715413416466037015451 0ustar gerlofgerlof/* ** structure containing only relevant process-info extracted ** from kernel's process-administration */ struct tstat_23 { /* GENERAL TASK INFO */ struct gen_23 { 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) */ } gen; /* CPU STATISTICS */ struct cpu_23 { 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 ifuture[4]; /* reserved for future use */ count_t cfuture[4]; /* reserved for future use */ } cpu; /* DISK STATISTICS */ struct dsk_23 { 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_23 { 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 cfuture[4]; /* reserved for future use */ } mem; /* NETWORK STATISTICS */ struct net_23 { 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; }; atop-2.4.0/prev/photosyst_20.h0000664000203100020310000001345213416466037015503 0ustar gerlofgerlof#define MAXCPU_20 2048 #define MAXDSK_20 512 #define MAXLVM_20 1024 #define MAXMDD_20 256 #define MAXINTF_20 128 /************************************************************************/ struct memstat_20 { 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 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) }; /************************************************************************/ struct netstat_20 { 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_20 { 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 actul freq */ }; struct percpu_20 { 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_20 freqcnt;/* frequency scaling info */ count_t cfuture[1]; /* reserved for future use */ }; struct cpustat_20 { 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_20 all; struct percpu_20 cpu[MAXCPU_20]; }; /************************************************************************/ struct perdsk_20 { char name[MAXDKNAM]; /* 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 cfuture[4]; /* reserved for future use */ }; struct dskstat_20 { int ndsk; /* number of physical disks */ int nmdd; /* number of md volumes */ int nlvm; /* number of logical volumes */ struct perdsk_20 dsk[MAXDSK_20]; struct perdsk_20 mdd[MAXMDD_20]; struct perdsk_20 lvm[MAXLVM_20]; }; /************************************************************************/ struct perintf_20 { 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 */ long speed; /* interface speed in megabits/second */ char duplex; /* full duplex (boolean) */ count_t cfuture[4]; /* reserved for future use */ }; struct intfstat_20 { int nrintf; struct perintf_20 intf[MAXINTF_20]; }; /************************************************************************/ /* ** experimental stuff for access to local HTTP daemons */ struct wwwstat_20 { 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 sstat_20 { struct cpustat_20 cpu; struct memstat_20 mem; struct netstat_20 net; struct intfstat_20 intf; struct dskstat_20 dsk; struct wwwstat_20 www; }; atop-2.4.0/prev/photosyst_21.h0000664000203100020310000001410513416466037015500 0ustar gerlofgerlof#define MAXCPU_21 2048 #define MAXDSK_21 1024 #define MAXLVM_21 2048 #define MAXMDD_21 256 #define MAXINTF_21 128 #define MAXDKNAM 32 /************************************************************************/ struct memstat_21 { 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 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 cfuture[8]; // reserved for future use }; /************************************************************************/ struct netstat_21 { 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_21 { 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 actul freq */ }; struct percpu_21 { 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_21 freqcnt;/* frequency scaling info */ count_t cfuture[4]; /* reserved for future use */ }; struct cpustat_21 { 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_21 all; struct percpu_21 cpu[MAXCPU_21]; }; /************************************************************************/ struct perdsk_21 { char name[MAXDKNAM]; /* 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 cfuture[4]; /* reserved for future use */ }; struct dskstat_21 { int ndsk; /* number of physical disks */ int nmdd; /* number of md volumes */ int nlvm; /* number of logical volumes */ struct perdsk_21 dsk[MAXDSK_21]; struct perdsk_21 mdd[MAXMDD_21]; struct perdsk_21 lvm[MAXLVM_21]; }; /************************************************************************/ struct perintf_21 { 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 */ long speed; /* interface speed in megabits/second */ char duplex; /* full duplex (boolean) */ count_t cfuture[4]; /* reserved for future use */ }; struct intfstat_21 { int nrintf; struct perintf_21 intf[MAXINTF_21]; }; /************************************************************************/ /* ** experimental stuff for access to local HTTP daemons */ struct wwwstat_21 { 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 sstat_21 { struct cpustat_21 cpu; struct memstat_21 mem; struct netstat_21 net; struct intfstat_21 intf; struct dskstat_21 dsk; struct wwwstat_21 www; }; atop-2.4.0/prev/photosyst_22.h0000664000203100020310000002011313416466037015475 0ustar gerlofgerlof#define MAXCPU_22 2048 #define MAXDSK_22 1024 #define MAXLVM_22 2048 #define MAXMDD_22 256 #define MAXINTF_22 128 #define MAXCONTAINER_22 128 #define MAXNFSMOUNT_22 64 #define MAXDKNAM 32 /************************************************************************/ struct memstat_22 { 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 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 cfuture[8]; // reserved for future use }; /************************************************************************/ struct netstat_22 { 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_22 { 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 actul freq */ }; struct percpu_22 { 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_22 freqcnt;/* frequency scaling info */ count_t cfuture[4]; /* reserved for future use */ }; struct cpustat_22 { 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_22 all; struct percpu_22 cpu[MAXCPU_22]; }; /************************************************************************/ struct perdsk_22 { char name[MAXDKNAM]; /* 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 cfuture[4]; /* reserved for future use */ }; struct dskstat_22 { int ndsk; /* number of physical disks */ int nmdd; /* number of md volumes */ int nlvm; /* number of logical volumes */ struct perdsk_22 dsk[MAXDSK_22]; struct perdsk_22 mdd[MAXMDD_22]; struct perdsk_22 lvm[MAXLVM_22]; }; /************************************************************************/ struct perintf_22 { 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'/'?') */ 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_22 { int nrintf; struct perintf_22 intf[MAXINTF_22]; }; /************************************************************************/ struct pernfsmount_22 { 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_22 { 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_22 nfsmnt[MAXNFSMOUNT_22]; } nfsmounts; }; /************************************************************************/ struct percontainer_22 { 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_22 { int nrcontainer; struct percontainer_22 cont[MAXCONTAINER_22]; }; /************************************************************************/ /* ** experimental stuff for access to local HTTP daemons */ struct wwwstat_22 { 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 sstat_22 { struct cpustat_22 cpu; struct memstat_22 mem; struct netstat_22 net; struct intfstat_22 intf; struct dskstat_22 dsk; struct nfsstat_22 nfs; struct contstat_22 cfs; struct wwwstat_22 www; }; atop-2.4.0/prev/photosyst_23.h0000664000203100020310000002011013416466037015473 0ustar gerlofgerlof#define MAXCPU_23 2048 #define MAXDSK_23 1024 #define MAXLVM_23 2048 #define MAXMDD_23 256 #define MAXINTF_23 128 #define MAXCONTAINER_23 128 #define MAXNFSMOUNT_23 64 #define MAXDKNAM 32 /************************************************************************/ struct memstat_23 { 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 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 cfuture[8]; // reserved for future use }; /************************************************************************/ struct netstat_23 { 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_23 { 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 actul freq */ }; struct percpu_23 { 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_23 freqcnt;/* frequency scaling info */ count_t cfuture[4]; /* reserved for future use */ }; struct cpustat_23 { 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_23 all; struct percpu_23 cpu[MAXCPU_23]; }; /************************************************************************/ struct perdsk_23 { char name[MAXDKNAM]; /* 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 cfuture[4]; /* reserved for future use */ }; struct dskstat_23 { int ndsk; /* number of physical disks */ int nmdd; /* number of md volumes */ int nlvm; /* number of logical volumes */ struct perdsk_23 dsk[MAXDSK_23]; struct perdsk_23 mdd[MAXMDD_23]; struct perdsk_23 lvm[MAXLVM_23]; }; /************************************************************************/ struct perintf_23 { 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'/'?') */ 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_23 { int nrintf; struct perintf_23 intf[MAXINTF_23]; }; /************************************************************************/ struct pernfsmount_23 { 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_23 { 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_23 nfsmnt[MAXNFSMOUNT_23]; } nfsmounts; }; /************************************************************************/ struct percontainer_23 { 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_23 { int nrcontainer; struct percontainer_23 cont[MAXCONTAINER_23]; }; /************************************************************************/ /* ** experimental stuff for access to local HTTP daemons */ struct wwwstat_23 { 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 sstat_23 { struct cpustat_23 cpu; struct memstat_23 mem; struct netstat_23 net; struct intfstat_23 intf; struct dskstat_23 dsk; struct nfsstat_23 nfs; struct contstat_23 cfs; struct wwwstat_23 www; }; atop-2.4.0/prev/photoproc_24.h0000664000203100020310000001032613416466037015445 0ustar gerlofgerlof/* ** structure containing only relevant process-info extracted ** from kernel's process-administration */ struct tstat_24 { /* GENERAL TASK INFO */ struct gen_24 { 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) */ } gen; /* CPU STATISTICS */ struct cpu_24 { 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 ifuture[4]; /* reserved for future use */ count_t cfuture[4]; /* reserved for future use */ } cpu; /* DISK STATISTICS */ struct dsk_24 { 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_24 { 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 cfuture[4]; /* reserved for future use */ } mem; /* NETWORK STATISTICS */ struct net_24 { 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_24 { 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; }; atop-2.4.0/prev/photosyst_24.h0000664000203100020310000002464313416466037015513 0ustar gerlofgerlof#define MAXCPU_24 2048 #define MAXDSK_24 1024 #define MAXLVM_24 2048 #define MAXMDD_24 256 #define MAXINTF_24 128 #define MAXCONTAINER_24 128 #define MAXNFSMOUNT_24 64 #define MAXIBPORT_24 32 #define MAXGPU_24 32 /************************************************************************/ struct memstat_24 { 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 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 cfuture[8]; // reserved for future use }; /************************************************************************/ struct netstat_24 { 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_24 { 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 actul freq */ }; struct percpu_24 { 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_24 freqcnt;/* frequency scaling info */ count_t instr; /* CPU instructions */ count_t cycle; /* CPU cycles */ count_t cfuture[2]; /* reserved for future use */ }; struct cpustat_24 { 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_24 all; struct percpu_24 cpu[MAXCPU_24]; }; /************************************************************************/ struct perdsk_24 { char name[MAXDKNAM]; /* 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 cfuture[4]; /* reserved for future use */ }; struct dskstat_24 { int ndsk; /* number of physical disks */ int nmdd; /* number of md volumes */ int nlvm; /* number of logical volumes */ struct perdsk_24 dsk[MAXDSK_24]; struct perdsk_24 mdd[MAXMDD_24]; struct perdsk_24 lvm[MAXLVM_24]; }; /************************************************************************/ struct perintf_24 { 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'/'?') */ 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_24 { int nrintf; struct perintf_24 intf[MAXINTF_24]; }; /************************************************************************/ struct pernfsmount_24 { 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_24 { 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_24 nfsmnt[MAXNFSMOUNT_24]; } nfsmounts; }; /************************************************************************/ struct psi_24 { 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_24 { char present; /* pressure stats supported? */ char future[3]; struct psi_24 cpusome; /* pressure stall info 'some' */ struct psi_24 memsome; /* pressure stall info 'some' */ struct psi_24 memfull; /* pressure stall info 'full' */ struct psi_24 iosome; /* pressure stall info 'some' */ struct psi_24 iofull; /* pressure stall info 'full' */ }; /************************************************************************/ struct percontainer_24 { 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_24 { int nrcontainer; struct percontainer_24 cont[MAXCONTAINER_24]; }; /************************************************************************/ /* ** experimental stuff for access to local HTTP daemons */ struct wwwstat_24 { 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_24 { char taskstats; // GPU task statistics supported? unsigned char nrprocs; // number of processes using GPU char type[MAXGPUTYPE+1]; // GPU type char busid[MAXGPUBUS+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_24 { int nrgpus; // total number of GPUs struct pergpu_24 gpu[MAXGPU_24]; }; /************************************************************************/ struct perifb_24 { char ibname[MAXIBNAME]; // 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_24 { int nrports; // total number of IB ports struct perifb_24 ifb[MAXIBPORT_24]; }; /************************************************************************/ struct sstat_24 { struct cpustat_24 cpu; struct memstat_24 mem; struct netstat_24 net; struct intfstat_24 intf; struct dskstat_24 dsk; struct nfsstat_24 nfs; struct contstat_24 cfs; struct pressure_24 psi; struct gpustat_24 gpu; struct ifbstat_24 ifb; struct wwwstat_24 www; }; atop-2.4.0/man/0000755000203100020310000000000013416466037012545 5ustar gerlofgerlofatop-2.4.0/man/atopacctd.80000664000203100020310000001046213416466037014605 0ustar gerlofgerlof.TH ATOPACCTD 8 "June 2018" "Linux" .SH NAME .B atopacctd - process accounting daemon .SH SYNOPSIS .P .B atopacctd [-v | topdirectory] .P .SH DESCRIPTION The .I atopacctd daemon switches on the process accounting feature in the kernel and let the process accounting records be written to a file, called the source file from now. After process accounting is activated, the .I atopacctd daemon transfers every process accounting record that is available in the source file to a shadow file. Client processes (like .I atop processes) will read the shadow files instead of the process accounting source file. .br In this way, the .I atopacctd daemon operates as a 'layer' between the process accounting file that is written by the kernel and the shadow accounting files that are read by .I atop processes. .PP This approach has the following advantages: .PP .TP 3 .B o The .I atopacctd daemon takes care that the source file is kept to a limited size. As soon as its maximum size is reached, it is truncated to a size of zero again (this is not noticed by the .I atop processes). .PP .TP 3 .B o The .I atopacct daemon takes care that a shadow file is kept to a limited size. As soon as the current shadow file reaches this maximum size, the .I atopacctd daemon creates a new (subsequent) shadow file. While client processes still have the possibility to read the previous shadow file(s), the .I atopacctd daemon continues writing accounting records to the newest (current) shadow file. For this reason, the name of a shadow file consists of a 10-digit sequence number followed by the extension '.paf' (process acounting file). Old shadow files that are not used by client processes any more, are automatically removed by the garbage collector in the .I atopacctd daemon. .PP .TP 3 .B o When no client processes are active (any more), all shadow files will be deleted and no records will be transferred to a shadow file any more. As soon as at least one client is activate again, the .I atopacctd daemon continues writing shadow files. .PP The directory .B /var/run is used as the default topdirectory. Below this top-directory, the source file .B pacct_source is created to which the kernel writes the process accounting records. .br Furthermore, the subdirectory .B pacct_shadow.d is created as a 'container' for the shadow files. Apart from the shadow files, also the file .B current is maintained in this subdirectory, containing the sequence number of the current (newest) shadow file and the maximum number of records that will be written in each shadow file. .PP An alternative topdirectory can be specified as command line argument. When an alternative topdirectory is defined, also modify the configuration file .B /etc/atoprc to inform .I atop clients about this alternative location (see the .B atoprc man page). Such alternative topdirectory should be owned by root and may not be writable for the group or others (security reasons). .PP Notice that the kernel suspends writing process accounting records when the free space of the filesystem on which the process accounting file resides drops below 2%. Writing is resumed when the free space is 4% or more. These lowwater and highwater percentages can be configured via the .B /proc/sys/kernel/acct pseudo-file. .br The .I atopacctd daemon suspends transferring process accounting records to shadow files when the free space of the filesystem on which the process accounting file resides drops below 5%. Transfer is resumed when the free space is 5% or more. Log messages are generated via syslog when writing to the current shadow file is suspended or resumed. .PP The .B -v flag can be used to verify the version of the .I atopacctd daemon. .PP .SH FILES .PP .TP 5 .B /var/run/pacct_source Regular file to which the kernel writes the process accounting records. This file will be regularly truncated. .PP .TP 5 .B /var/run/pacct_shadow.d/current Regular file containing the sequence number of the current shadow file and the maximum number of records per shadow file. .PP .TP 5 .B /var/run/pacct_shadow.d/N.paf Regular files containing the process accounting records that have been copied transparently from the source file (N represents a 10-digit sequence number). .SH SEE ALSO .B atop(1), .B atopsar(1), .B atoprc(5), .B netatop(4), .B netatopd(8) .br .B https://www.atoptool.nl .SH AUTHOR Gerlof Langeveld (gerlof.langeveld@atoptool.nl) atop-2.4.0/man/atoprc.50000664000203100020310000002550413416466037014133 0ustar gerlofgerlof.TH ATOPRC 5 "January 2019" "Linux" .SH NAME .B atoprc - atop/atopsar related rcfile .SH DESCRIPTION This manual page documents the rcfile of the .I atop and .I atopsar commands. These commands can be used to monitor the system and process load on a Linux system. .PP The atoprc file contains the default settings. These settings are read during startup, first from the system-wide rcfile .I /etc/atoprc and after that from the user-specific rcfile .I ~/.atoprc (so system-wide settings can be overruled by an individual user). The options in both rcfiles are identical. .PP .SH OPTIONS .PP The rcfile contains keyword-value pairs, one on every line (blank lines and lines starting with a #-sign are ignored). .br The following keywords can be specified: .PP .TP 4 .B flags 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', \&'a', 'y', 'f', 'F', 'G', 'R', '1', 'e', 'E' and 'x'. .PP .TP 4 .B interval The default interval value in seconds. .PP .TP 4 .B linelen The length of a screen line when sending output to a file or pipe (default 80). .PP .TP 4 .B username The default regular expression for the users for which active processes will be shown. .PP .TP 4 .B procname The default regular expression for the process names to be shown. .PP .TP 4 .B maxlinecpu The maximum number of active CPUs that will be shown. .PP .TP 4 .B maxlinegpu The maximum number of active GPUs that will be shown. .PP .TP 4 .B maxlinelvm The maximum number of active logical volumes that will be shown. .PP .TP 4 .B maxlinemdd The maximum number of active multiple devices that will be shown. .PP .TP 4 .B maxlinedisk The maximum number of active disks that will be shown. .PP .TP 4 .B maxlinenfsm The maximum number of NFS mounts that will be shown on an NFS client. .PP .TP 4 .B maxlineintf The maximum number of active network interfaces that will be shown. .PP .TP 4 .B maxlinecont The maximum number of active containers that will be shown. .PP .TP 4 .B cpucritperc The busy percentage considered critical for a processor (see section COLORS in the man-page of the .I atop command). This percentage is used to determine a weighted percentage for line coloring and sorting of active processes. When this value is zero, no line coloring or automatic sorting is performed for this resource. .PP .TP 4 .B dskcritperc The busy percentage considered critical for a disk (see section COLORS in the man-page of the .I atop command). This percentage is used to determine a weighted percentage for line coloring and sorting of active processes. When this value is zero, no line coloring or automatic sorting is performed for this resource. .PP .TP 4 .B netcritperc The busy percentage considered critical for a network interface (see section COLORS in the man-page of the .I atop command). This percentage is used to determine a weighted percentage for line coloring and sorting of active processes. When this value is zero, no line coloring or automatic sorting is performed for this resource. .PP .TP 4 .B memcritperc The percentage considered critical for memory utilization (see section COLORS in the man-page of the .I atop command). This percentage is used to determine a weighted percentage for line coloring and sorting of active processes. When this value is zero, no line coloring or automatic sorting is performed for this resource. .PP .TP 4 .B swpcritperc The occupation percentage considered critical for swap space (see section COLORS in the man-page of the .I atop command). This percentage is used to determine a weighted percentage for line coloring and sorting of active processes. When this value is zero, no line coloring or automatic sorting is performed for this resource. .PP .TP 4 .B swoutcritsec The number of pages swapped out per second considered critical for for memory utilization (see section COLORS in the man-page of the .I atop command). This threshold is used in combination with 'memcritperc' to determine a weighted percentage for line coloring and sorting of active processes. When this value is zero, no line coloring or automatic sorting is performed for this resource. .PP .TP 4 .B almostcrit A percentage of the critical percentage to determine if the resource is almost critical (see section COLORS in the man-page of the .I atop command). When this value is zero, no line coloring for `almost critical' is performed. .PP .TP 4 .B colorinfo Definition of color name for information messages (default: green). .br Allowed colors are: red green yellow blue magenta cyan black white. .PP .TP 4 .B colorthread Definition of color name for thread-specific lines when using the 'y' option (default: yellow). .br Allowed colors are: red green yellow blue magenta cyan black white. .PP .TP 4 .B coloralmost Definition of color name for almost critical resources (default: cyan). .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). .br Allowed colors are: red green yellow blue magenta cyan black white. .PP .TP 4 .B atopsarflags A list of default flags for .B atopsar can be defined here. The flags that are allowed are 'S', 'x', 'C', 'M', 'H', 'a', 'A' and the flags to select one or more specific reports. .PP .TP 4 .B pacctdir The name of the topdirectory used by the .B atopacctd daemon. In this directory, the daemon creates a subdirectory .B pacct_shadow.d in which files will be written containing the process accounting records. The default topdirectory is .B /var/run and this option only has to be specified when the .B atopacctd daemon is started with an alternative topdirectory as command line argument. .br This option can only be specified in the .B /etc/atoprc file (on system level)! .PP An example of the .B /etc/atoprc or .B ~/.atoprc file: .TP 8 \ .br flags\ \ \ \ \ \ \ \ \ Aaf .br interval\ \ \ \ \ \ 5 .br username .br procname .br maxlinecpu\ \ \ \ 4 .br maxlinedisk\ \ \ 10 .br maxlineintf\ \ \ 5 .br cpucritperc\ \ \ 80 .br almostcrit\ \ \ \ 90 .br atopsarflags\ \ CMH .br ownprocline\ \ \ PID:50 VGROW:40 RGROW:45 COMMAND-LINE:50 .br ownpagline\ \ \ \ PAGSCAN:3 BLANKBOX:0 PAGSWIN:3 PAGSWOUT:7 .PP The keywords 'ownprocline' and 'ownpagline' are explained in the subsequent section. .SH OWN DEFINITION OF OUTPUT LINE Via the rcfile it is possible to define the layout of the output lines yourself, i.e. you can define the layout of one line with process information with the keyword 'ownprocline' (to be selected with the key 'o' or the flag \-o) and you can redefine all lines with system information. .PP The layout of an output-line can be defined as follows (notice that this should be specified as one line in the rcfile): .PP \ \ \ keyword\ \ \ : [: ...] .PP The .B columnid is the symbolic name of a column that should shown at this position in the output line. .br The .B prio is a positive integer value that determines which columns have precedence whenever not all specified columns fit into the current screen-width. The higher value, the higher priority. .br The column-specifications should be separated by a space. The order in which columns have been specified is the order in which they will be shown, with respect to their priority (columns that do not fit, will be dropped dynamically). .PP A special columnid for system lines is 'BLANKBOX'. This indicates that an empty column is required at this position. Also this special columnid is followed by a priority (usually low). .PP The following definition can be specified for process information: .PP .TP 4 .B ownprocline The columnids are the names of the columns that are shown in the normal output of the process-related lines that are shown by .I atop such as 'PID', 'CMD', 'S', .... The only exception is the special columnid 'SORTITEM' that is used to show one of the columns CPU%/DSK%/MEM%/NET%, depending on the chosen sort-criterium. .br An example of a user-defined process line: .PP .TP 8 \ ownprocline\ \ \ PID:20 PPID:10 SYSCPU:15 USRCPU:15 VGROW:14 VSIZE:12 RGROW:14 RSIZE:12 ST:8 EXC:7 S:11 SORTITEM:18 CMD:20 .PP The following definitions are used internally by .I atop as the default system lines (you can redefine each of them in the rcfile as one line): .PP .TP 4 .B ownsysprcline Redefinition of line labeled with 'PRC': .PP .TP 8 \ ownsysprcline\ \ \ PRCSYS:8 PRCUSER:8 BLANKBOX:0 PRCNPROC:7 PRCNZOMBIE:5 PRCCLONES:4 BLANKBOX:0 PRCNNEXIT:6 .PP .TP 4 .B ownallcpuline Redefinition of line labeled with 'CPU' for total CPU-utilization: .PP .TP 8 \ ownallcpuline\ \ \ CPUSYS:8 CPUUSER:7 CPUIRQ:4 BLANKBOX:0 CPUIDLE:5 CPUWAIT:6 BLANKBOX:0 CPUSTEAL:1 CPUGUEST:3 .PP .TP 4 .B ownonecpuline Redefinition of line labeled with 'CPU' for utilization of one CPU: .PP .TP 8 \ ownonecpuline\ \ \ CPUISYS:8 CPUIUSER:7 CPUIIRQ:4 BLANKBOX:0 CPUIIDLE:5 CPUIWAIT:6 BLANKBOX:0 CPUISTEAL:1 CPUIGUEST:3 .PP .TP 4 .B owncplline Redefinition of line labeled with 'CPL': .PP .TP 8 \ owncplline\ \ \ CPLAVG1:4 CPLAVG5:3 CPLAVG15:2 BLANKBOX:0 CPLCSW:6 CPLINTR:5 BLANKBOX:0 CPLNUMCPU:1 .PP .TP 4 .B ownmemline Redefinition of line labeled with 'MEM': .PP .TP 8 \ ownmemline\ \ \ MEMTOT:2 MEMFREE:5 MEMCACHE:3 MEMDIRTY:1 MEMBUFFER:3 MEMSLAB:3 BLANKBOX:0 BLANKBOX:0 BLANKBOX:0 BLANKBOX:0 .PP .TP 4 .B ownswpline Redefinition of line labeled with 'SWP': .PP .TP 8 \ ownswpline\ \ \ SWPTOT:3 SWPFREE:4 BLANKBOX:0 BLANKBOX:0 BLANKBOX:0 BLANKBOX:0 BLANKBOX:0 BLANKBOX:0 SWPCOMMITTED:5 SWPCOMMITLIM:6 .PP .TP 4 .B ownpagline Redefinition of line labeled with 'PAG': .PP .TP 8 \ ownpagline\ \ \ PAGSCAN:3 PAGSTALL:1 BLANKBOX:0 PAGSWIN:4 PAGSWOUT:3 .PP .TP 4 .B owndskline Redefinition of lines labeled with 'LVM', 'MDD' and 'DSK': .PP .TP 8 \ owndskline\ \ \ DSKNAME:8 DSKBUSY:7 DSKNREAD:6 DSKNWRITE:6 DSKKBPERRD:4 DSKKBPERWR:4 DSKMBPERSECRD:5 DSKMBPERSECWR:5 DSKAVQUEUE:1 DSKAVIO:5 .PP .TP 4 .B ownnettrline Redefinition of line labeled with 'NET' for transport: .PP .TP 8 \ ownnettrline\ \ \ NETTRANSPORT:9 NETTCPI:8 NETTCPO:8 NETUDPI:8 NETUDPO:8 NETTCPACTOPEN:6 NETTCPPASVOPEN:5 NETTCPRETRANS:4 NETTCPINERR:3 NETTCPORESET:20 NETUDPNOPORT:1 NETUDPINERR:3 .PP .TP 4 .B ownnetnetline Redefinition of line labeled with 'NET' for network: .PP .TP 8 \ ownnetnetline\ \ \ NETNETWORK:5 NETIPI:4 NETIPO:4 NETIPFRW:4 NETIPDELIV:4 BLANKBOX:0 BLANKBOX:0 BLANKBOX:0 NETICMPIN:1 NETICMPOUT:1 .PP .TP 4 .B ownnetifline Redefinition of line labeled with 'NET' for interfaces: .PP .TP 8 \ ownnetifline\ \ \ NETNAME:8 NETPCKI:7 NETPCKO:7 NETSPEEDIN:6 NETSPEEDOUT:6 NETCOLLIS:3 NETMULTICASTIN:2 NETRCVERR:5 NETSNDERR:5 NETRCVDROP:4 NETSNDDROP:4 .PP The lines above are shown in the order as shown by .I atop in combination with the .B -f flag (in a very wide window you should be able to see all of the columns). .SH SEE ALSO .B atop(1), .B atopsar(1), .B atopacctd(8), .B netatop(4), .B netatopd(8), .B logrotate(8) .br .B https://www.atoptool.nl .SH AUTHOR Gerlof Langeveld (gerlof.langeveld@atoptool.nl) .br JC van Winkel atop-2.4.0/man/atopgpud.80000644000203100020310000001001013416466037014451 0ustar gerlofgerlof.TH ATOPGPUD 8 "January 2019" "Linux" .SH NAME .B atopgpud - GPU statistics daemon .SH SYNOPSIS .P .B atopgpud [-v] .PP .SH DESCRIPTION The .I atopgpud daemon gathers statistical information from all Nvidia GPUs in the current system. With a sampling rate of one second, it maintains the statistics of every GPU, globally (system level) and per process. When .I atopgpud is active on the target system, .I atop connects to this daemon via a TCP socket and obtains all GPU statistics with every interval. .PP The approach to gather all GPU statistics in a separate daemon is required, because the Nvidia driver only offers the GPU busy percentage of the last second. Suppose that .I atop runs with a 10-minute interval and would fetch the GPU busy percentage directly from the Nvidia driver, it would reflect the busy percentage of the last second instead of the average busy percentage during 600 seconds. Therefore, the .I atopgpud daemon fetches the GPU busy percentage every second and accumulates this into a counter that can be retrieved by .I atop regularly. The same approach applies to other GPU statistics. .PP When the .I atopgpud daemon runs with root privileges, more process level counters (i.e. GPU busy and GPU memory busy per process) are provided that are otherwise not applicable. .PP Notice that certain GPU statistics are only delivered for specific GPU types. For older or less sophisticated GPUs, the value -1 is returned for counters that are not maintained. In the output of .I atop these counters are shown as 'N/A'. .PP When no (Nvidia) GPUs can be found in the target system, .I atopgpud immediately terminates with exit code 0. .PP Log messages are written via the .I rsyslogd daemon with facility 'daemon'. With the -v flag (verbose), .I atopgpud also logs debug messages. .PP .SH INSTALLATION The .I atopgpud daemon is written in Python, so a Python interpreter should be installed on the target system. This can either be Python version 2 or Python version 3 (the code of .I atopgpud is written in a generic way). Take care that the first line of the .I atopgpud script contains the proper command name to activate a Python interpreter that is installed on the target system! .PP The .I atopgpud daemon depends on the Python module .I pynvml to interface with the Nvidia driver. This module can be installed by the .I pip or .I pip3 command and is usually packaged under the name .I nvidia-ml-py .br Finally, the .I pynvml module is a Python wrapper around the .I libnvidia-ml shared library that needs to be installed as well. .PP After installing the .I atop package, the .I atopgpud is not automatically started, nor will the service be enabed by default. When you want to activate this service (permanently), enter the following commands (as root): .PP .B \ systemctl enable atopgpu .br .B \ systemctl start atopgpu .PP .SH INTERFACE DESCRIPTION Client processes can connect to the .I atopgpud daemon on TCP port 59123. Subsequently, such client can send a request of two bytes, consisting of one byte request code followed by one byte integer being the API version number. .br The request code in the first byte can be 'T' to obtain information about the GPU types installed in this system (usually only requested once). .br The request code can be 'S' to obtain all statistical counter values (requested for every interval). .PP The response of the daemon starts with a 4-byte integer. The first byte is the API version number that determines the response format while the subsequent three bytes indicate the length (big endian order) of the response string that follows. .br In the reponse strings the character '@' introduces system level information of one specific GPU and the character '#' introduces process level information related to that GPU. .br For further details about the meaning of the counters in a response string, please consult the source code. .PP .SH SEE ALSO .B atop(1), .B atopsar(1), .B atoprc(5), .B netatop(4), .B netatopd(8), .B atopacctd(8) .br .B https://www.atoptool.nl .SH AUTHOR Gerlof Langeveld (gerlof.langeveld@atoptool.nl) atop-2.4.0/man/atopsar.10000664000203100020310000007726113416466037014317 0ustar gerlofgerlof.TH ATOPSAR 1 "January 2019" "Linux" .SH NAME .B atopsar - Advanced System Activity Report (atop related) .SH SYNOPSIS .P .B atopsar [\-flags...] [\-r .I file|date ] [\-R .I cnt ] [\-b .I hh:mm ] [\-e .I hh:mm ] .br .B atopsar [\-flags...] .I interval [ .I samples ] .P .SH DESCRIPTION The program .I atopsar can be used to report statistics on system level. .PP In the first synopsis line (no sampling interval specified), .I atopsar extracts data from a raw logfile that has been recorded previously by the program .I atop (option .B -w of the .I atop program). .br You can specify the name of the logfile with the .B -r option of the .I atopsar program. When a daily logfile of .I atop is used, named .B /var/log/atop/atop_YYYYMMDD (where YYYYMMDD reflects the date), the required date of the form YYYYMMDD can be specified with the .B -r option instead of the filename, or the symbolic name 'y' can be used for yesterday's daily logfile (this can be repeated so 'yyyy' indicates the logfile of four days ago). If the .B -r option is not specified at all, today's daily logfile is used by default. .br The starting and ending times of the report can be defined using the options .B -b and .B -e followed by a time argument of the form hh:mm. .PP In the second synopsis line, .B atopsar reads actual activity counters from the kernel with the specified .I interval (in seconds) and the specified number of .I samples (optionally). When .B atopsar is activated in this way it immediately sends the output for every requested report to standard output. If only one type of report is requested, the header is printed once and after every .I interval seconds the statistical counters are shown for that period. If several reports are requested, a header is printed per sample followed by the statistical counters for that period. .PP Some generic flags can be specified to influence the behaviour of the .B atopsar program: .PP .TP 5 .B -S By default the timestamp at the beginning of a line is suppressed if more lines are shown for one interval. With this flag a timestamp is given for every output-line (easier for post-processing). .PP .TP 5 .B -a By default certain resources as disks and network interfaces are only shown when they were active during the interval. With this flag all resources of a given type are shown, even if they were inactive during the interval. .PP .TP 5 .B -x By default .B atopsar only uses colors if output is directed to a terminal (window). These colors might indicate that a critical occupation percentage has been reached (red) or has been almost reached (cyan) for a particular resource. See the man-page of .B atop for a detailed description of this feature (section COLORS). .br With the flag .B -x the use of colors is suppressed unconditionally. .PP .TP 5 .B -C By default .B atopsar only uses colors if output is directed to a terminal (window). These colors might indicate that a critical occupation percentage has been reached (red) or has been almost reached (cyan) for a particular resource. See the man-page of .B atop for a detailed description of this feature (section COLORS). .br With the flag .B -C colors will always be used, even if output is not directed to a terminal. .PP .TP 5 .B -M Use markers at the end of a line to indicate that a critical occupation percentage has been reached ('*') or has been almost reached ('+') for particular resources. The marker '*' is similar to the color red and the marker '+' to the color cyan. See the man-page of .B atop for a detailed description of these colors (section COLORS). .PP .TP 5 .B -H Repeat the header line within a report for every .I N detail lines. The value of .I N is determined dynamically in case of output to a tty/window (depending on the number of lines); for output to a file or pipe this value is 23. .PP .TP 5 .B -R Summarize .I cnt samples into one sample. When the logfile contains e.g. samples of 10 minutes, the use of the flag '\-R 6' shows a report with one sample for every hour. .PP Other flags are used to define which reports are required: .PP .TP 5 .B -A Show all possible reports. .PP .TP 5 .B -c Report about CPU utilization (in total and per cpu). .PP .TP 5 .B -g Report about GPU utilization (per GPU). .PP .TP 5 .B -p Report about processor-related matters, like load-averages and hardware interrupts. .PP .TP 5 .B -P Report about processes. .PP .TP 5 .B -m Current memory- and swap-occupation. .PP .TP 5 .B -s Report about paging- and swapping-activity, and overcommitment. .PP .TP 5 .B -B Report about Pressure Stall Information (PSI). .PP .TP 5 .B -l Report about utilization of logical volumes. .PP .TP 5 .B -f Report about utilization of multiple devices. .PP .TP 5 .B -d Report about utilization of disks. .PP .TP 5 .B -n Report about NFS mounted filesystems on NFS client. .PP .TP 5 .B -j Report about NFS client activity. .PP .TP 5 .B -J Report about NFS server activity. .PP .TP 5 .B -i Report about the network interfaces. .PP .TP 5 .B -I Report about errors for network-interfaces. .PP .TP 5 .B -w Report about IP version 4 network traffic. .PP .TP 5 .B -W Report about errors for IP version 4 traffic. .PP .TP 5 .B -y General report about ICMP version 4 layer activity. .PP .TP 5 .B -Y Per-type report about ICMP version 4 layer activity. .PP .TP 5 .B -u Report about UDP version 4 network traffic. .PP .TP 5 .B -z Report about IP version 6 network traffic. .PP .TP 5 .B -Z Report about errors for IP version 6 traffic. .PP .TP 5 .B -k General report about ICMP version 6 layer activity. .PP .TP 5 .B -K Per-type report about ICMP version 6 layer activity. .PP .TP 5 .B -U Report about UDP version 6 network traffic. .PP .TP 5 .B -t Report about TCP network traffic. .PP .TP 5 .B -T Report about errors for TCP-traffic. .PP .TP 5 .B -h Report about Infiniband utilization. .PP .TP 5 .B -O Report about top-3 processes consuming most processor capacity. This report is only available when using a log file (not when specifying an interval). .PP .TP 5 .B -G Report about top-3 processes consuming most resident memory. This report is only available when using a log file (not when specifying an interval). .PP .TP 5 .B -D Report about top-3 processes issueing most disk transfers. This report is only available when using a log file (not when specifying an interval). .PP .TP 5 .B -N Report about top-3 processes issueing most IPv4/IPv6 socket transfers. This report is only available when using a log file (not when specifying an interval). .SH OUTPUT DESCRIPTION Depending on the requested report, a number of columns with output values are produced. The values are mostly presented as a number of events per second. .PP The output for the flag .B -c contains the following columns per cpu: .TP 12 .B usr% Percentage of cpu-time consumed in user mode (program text) for all active processes running with a nice value of zero (default) or a negative nice value (which means a higher priority than usual). The cpu consumption in user mode of processes with a nice value larger than zero (lower priority) is indicated in the nice%-column. .TP 12 .B nice% Percentage of cpu time consumed in user mode (i.e. program text) for all processes running witn a nice value larger than zero (which means with a lower priority than average). .TP 12 .B sys% Percentage of cpu time consumed in system mode (kernel text) for all active processes. A high percentage usually indicates a lot of system calls being issued. .TP 12 .B irq% Percentage of cpu time consumed for handling of device interrupts. .TP 12 .B softirq% Percentage of cpu time consumed for soft interrupt handling. .TP 12 .B steal% Percentage of cpu time stolen by other virtual machines running on the same hardware. .TP 12 .B guest% Percentage of cpu time used by other virtual machines running on the same hardware (overlaps with usr%/nice%). .TP 12 .B wait% Percentage of unused cpu time while at least one of the processes in wait-state awaits completion of disk I/O. .TP 12 .B idle% Percentage of unused cpu time because all processes are in a wait-state but not waiting for disk-I/O. .PP The output for the flag .B -g contains the following columns per GPU: .TP 12 .B busaddr GPU number and bus-ID (separated by '/'). .TP 12 .B gpubusy GPU busy percentage during interval. .TP 12 .B membusy GPU memory busy percentage during interval, i.e. time to issue read and write accesses on memory. .TP 12 .B memocc Percentage of memory occupation at this moment. .TP 12 .B memtot Total memory available. .TP 12 .B memuse Used GPU memory at this moment. .TP 12 .B gputype Type of GPU. .PP The output for the flag .B -p contains the following values: .TP 12 .B pswch/s Number of process switches (also called context switches) per second on this cpu. A process switch occurs at the moment that an active thread (i.e. the thread using a cpu) enters a wait state or has used its time slice completely; another thread will then be chosen to use the cpu. .TP 12 .B devintr/s Number of hardware interrupts handled per second on this cpu. .TP 12 .B clones/s The number of new threads started per second. .TP 12 .B loadavg1 Load average reflecting the average number of threads in the runqueue or in non-interruptible wait state (usually waiting for disk or tape I/O) during the last minute. .TP 12 .B loadavg5 Load average reflecting the average number of threads in the runqueue or in non-interruptible wait state (usually waiting for disk or tape I/O) during the last 5 minutes. .TP 12 .B loadavg15 Load average reflecting the average number of threads in the runqueue or in non-interruptible wait state (usually waiting for disk or tape I/O) during the last 15 minutes. .PP The output for the flag .B -P contains information about the processes and threads: .TP 12 .B clones/s The number of new threads started per second. .TP 12 .B pexit/s .TP 12 .B curproc Total number of processes present in the system. .TP 12 .B curzomb Number of zombie processes present in the system. .TP 12 .B thrrun Total number of threads present in the system in state 'running'. .TP 12 .B thrslpi Total number of threads present in the system in state 'interruptible sleeping'. .TP 12 .B thrslpu Total number of threads present in the system in state 'uninterruptible sleeping'. .PP The output for the flag .B -m contains information about the memory- and swap-utilization: .TP 12 .B memtotal Total usable main memory size. .TP 12 .B memfree Available main memory size at this moment (snapshot). .TP 12 .B buffers Main memory used at this moment to cache metadata-blocks (snapshot). .TP 12 .B cached Main memory used at this moment to cache data-blocks (snapshot). .TP 12 .B dirty Amount of memory in the page cache that still has to be flushed to disk at this moment (snapshot). .TP 12 .B slabmem Main memory used at this moment for dynamically allocated memory by the kernel (snapshot). .TP 12 .B swptotal Total swap space size at this moment (snapshot). .TP 12 .B swpfree Available swap space at this moment (snapshot). .PP The output for the flag .B -s contains information about the frequency of swapping: .TP 12 .B pagescan/s Number of scanned pages per second due to the fact that free memory drops below a particular threshold. .TP 12 .B swapin/s The number of memory-pages the system read from the swap-device per second. .TP 12 .B swapout/s The number of memory-pages the system wrote to the swap-device per second. .TP 12 .B commitspc The committed virtual memory space i.e. the reserved virtual space for all allocations of private memory space for processes. .TP 12 .B commitlim The maximum limit for the committed space, which is by default swap size plus 50% of memory size. The kernel only verifies whether the committed space exceeds the limit if strict overcommit handling is configured (vm.overcommit_memory is 2). .PP The output for the flag .B -B contains the Pressure Stall Information (PSI): .TP 12 .B cs_10_60_300 Average pressure percentage over the last 10, 60 and 300 seconds for the category 'CPU some'. .TP 12 .B ms_10_60_300 Average pressure percentage over the last 10, 60 and 300 seconds for the category 'memory some'. .TP 12 .B mf_10_60_300 Average pressure percentage over the last 10, 60 and 300 seconds for the category 'memory full'. .TP 12 .B is_10_60_300 Average pressure percentage over the last 10, 60 and 300 seconds for the category 'I/O some'. .TP 12 .B if_10_60_300 Average pressure percentage over the last 10, 60 and 300 seconds for the category 'I/O full'. .PP The output for the flags .B -l (LVM), .B -f (MD), and .B -d (hard disk) contains the following columns per active unit: .TP 12 .B disk Name. .TP 12 .B busy Busy-percentage of the unit (i.e. the portion of time that the device was busy handling requests). .TP 12 .B read/s Number of read-requests issued per second on this unit. .TP 12 .B KB/read Average number of Kbytes transferred per read-request for this unit. .TP 12 .B writ/s Number of write-requests issued per second on this unit. .TP 12 .B KB/writ Average number of Kbytes transferred per write-request for this unit. .TP 12 .B avque Average number of requests outstanding in the queue during the time that the unit is busy. .TP 12 .B avserv Average number of milliseconds needed by a request on this unit (seek, latency and data-transfer). .PP The output for the flag .B -n contains information about activity on NFS mounted filesystems (client): .TP 12 .B mounted_device Mounted device containing server name and server directory being mounted. .TP 12 .B physread/s Kilobytes data physically read from the NFS server by processes running on the NFS client. .TP 12 .B KBwrite/s Kilobytes data physically written to the NFS server by processes running on the NFS client. .br When the NFS filesystem was mounted during the interval, the state 'M' is shown. .PP The output for the flag .B -j contains information about NFS client activity: .TP 12 .B rpc/s Number of RPC calls per second issued to NFS server(s). .TP 12 .B rpcread/s Number of read RPC calls per second issued to NFS server(s). .TP 12 .B rpcwrite/s Number of write RPC calls per second issued to NFS server(s). .TP 12 .B retrans/s Number of retransmitted RPC calls per second. .TP 12 .B autrefresh/s Number of authorization refreshes per second. .PP The output for the flag .B -J contains information about NFS server activity: .TP 12 .B rpc/s Number of RPC calls per second received from NFS client(s). .TP 12 .B rpcread/s Number of read RPC calls per second received from NFS client(s). .TP 12 .B rpcwrite/s Number of write RPC calls per second received from NFS client(s). .TP 12 .B MBcr/s Number of Megabytes per second returned to read requests by clients. .TP 12 .B MBcw/s Number of Megabytes per second passed in write requests by clients. .TP 12 .B nettcp/s Number of requests per second handled via TCP. .TP 12 .B netudp/s Number of requests per second handled via UDP. .PP The output for the flag .B -i provides information about utilization of network interfaces: .TP 12 .B interf Name of interface. .TP 12 .B busy Busy percentage for this interface. If the linespeed of this interface could not be determined (for virtual interfaces or in case that .B atop or .B atopsar had no root-privileges), a question mark is shown. .TP 12 .B ipack/s Number of packets received from this interface per second. .TP 12 .B opack/s Number of packets transmitted to this interface per second. .TP 12 .B iKbyte/s Number of Kbytes received from this interface per second. .TP 12 .B oKbyte/s Number of Kbytes transmitted via this interface per second. .TP 12 .B imbps/s Effective number of megabits received per second. .TP 12 .B ombps/s Effective number of megabits transmitted per second. .TP 12 .B maxmbps/s Linespeed as number of megabits per second. If the linespeed could not be determined (for virtual interfaces or in case that .B atop or .B atopsar had no root-privileges), value 0 is shown. .br The linespeed is followed by the indication 'f' (full duplex) or 'h' (half duplex). .PP The output for the flag .B -I provides information about the failures that were detected for network interfaces: .TP 12 .B interf Name of interface. .TP 12 .B ierr/s Number of bad packets received from this interface per second. .TP 12 .B oerr/s Number of times that packet transmission to this interface failed per second. .TP 12 .B coll/s Number of collisions encountered per second while transmitting packets. .TP 12 .B idrop/s Number of received packets dropped per second due to lack of buffer-space in the local system. .TP 12 .B odrop/s Number of transmitted packets dropped per second due to lack of buffer-space in the local system. .TP 12 .B iframe/s Number of frame alignment-errors encountered per second on received packets. .TP 12 .B ocarrier/s Number of carrier-errors encountered per second on transmitted packets. .PP The output for the flag .B -w provides information about the utilization of the IPv4-layer (formal SNMP-names between brackets): .TP 12 .B inrecv/s Number of IP datagrams received from interfaces per second, including those received in error (ipInReceives). .TP 12 .B outreq/s Number of IP datagrams that local higher-layer protocols supplied to IP in requests for transmission per second (ipOutRequests). .TP 12 .B indeliver/s Number of received IP datagrams that have been successfully delivered to higher protocol-layers per second (ipInDelivers). .TP 12 .B forward/s Number of received IP datagrams per second for which this entity was not their final IP destination, as a result of which an attempt was made to forward (ipForwDatagrams). .TP 12 .B reasmok/s Number of IP datagrams successfully reassembled per second (ipReasmOKs). .TP 12 .B fragcreat/s Number of IP datagram fragments generated per second at this entity (ipFragCreates). .PP The output for the flag .B -W provides information about the failures that were detected in the IPv4-layer (formal SNMP-names between brackets): .TP 12 .B in: dsc/s Number of input IP datagrams per second for which no problems were encountered to prevent their continued processing but that were discarded, e.g. for lack of buffer space (ipInDiscards). .TP 12 .B in: hder/s Number of input IP datagrams per second discarded due to errors in the IP header (ipInHdrErrors). .TP 12 .B in: ader/s Number of input IP datagrams per second discarded because the IP address in the destination field was not valid to be received by this entity (ipInAddrErrors). .TP 12 .B in: unkp/s Number of inbound packets per second that were discarded because of an unknown or unsupported protocol (ipInUnknownProtos). .TP 12 .B in: ratim/s Number of timeout-situations per second while other fragments were expected for successful reassembly (ipReasmTimeout). .TP 12 .B in: rfail/s Number of failures detected per second by the IP reassembly algorithm (ipReasmFails). .TP 12 .B out: dsc/s Number of output IP datagrams per second for which no problems were encountered to prevent their continued processing but that were discarded, e.g. for lack of buffer space (ipOutDiscards). .TP 12 .B out: nrt/s Number of IP datagrams per second discarded because no route could be found (ipOutNoRoutes). .PP The output for the flag .B -y provides information about the general utilization of the ICMPv4-layer and some information per type of ICMP-message (formal SNMP-names between brackets): .TP 12 .B intot/s Number of ICMP messages (any type) received per second at this entity (icmpInMsgs). .TP 12 .B outtot/s Number of ICMP messages (any type) transmitted per second from this entity (icmpOutMsgs). .TP 12 .B inecho/s Number of ICMP Echo (request) messages received per second (icmpInEchos). .TP 12 .B inerep/s Number of ICMP Echo-Reply messages received per second (icmpInEchoReps). .TP 12 .B otecho/s Number of ICMP Echo (request) messages transmitted per second (icmpOutEchos). .TP 12 .B oterep/s Number of ICMP Echo-Reply messages transmitted per second (icmpOutEchoReps). .PP The output for the flag .B -Y provides information about other types of ICMPv4-messages (formal SNMP-names between brackets): .TP 12 .B ierr/s Number of ICMP messages received per second but determined to have ICMP-specific errors (icmpInErrors). .TP 12 .B isq/s Number of ICMP Source Quench messages received per second (icmpInSrcQuenchs). .TP 12 .B ird/s Number of ICMP Redirect messages received per second (icmpInRedirects). .TP 12 .B idu/s Number of ICMP Destination Unreachable messages received per second (icmpInDestUnreachs). .TP 12 .B ite/s Number of ICMP Time Exceeded messages received per second (icmpOutTimeExcds). .TP 12 .B oerr/s Number of ICMP messages transmitted per second but determined to have ICMP-specific errors (icmpOutErrors). .TP 12 .B osq/s Number of ICMP Source Quench messages transmitted per second (icmpOutSrcQuenchs). .TP 12 .B ord/s Number of ICMP Redirect messages transmitted per second (icmpOutRedirects). .TP 12 .B odu/s Number of ICMP Destination Unreachable messages transmitted per second (icmpOutDestUnreachs). .TP 12 .B ote/s Number of ICMP Time Exceeded messages transmitted per second (icmpOutTimeExcds). .PP The output for the flag .B -u provides information about the utilization of the UDPv4-layer (formal SNMP-names between brackets): .TP 12 .B indgram/s Number of UDP datagrams per second delivered to UDP users (udpInDatagrams). .TP 12 .B outdgram/s Number of UDP datagrams transmitted per second from this entity (udpOutDatagrams). .TP 12 .B inerr/s Number of received UDP datagrams per second that could not be delivered for reasons other than the lack of an application at the destination port (udpInErrors). .TP 12 .B noport/s Number of received UDP datagrams per second for which there was no application at the destination port (udpNoPorts). .PP The output for the flag .B -z provides information about the utilization of the IPv6-layer (formal SNMP-names between brackets): .TP 12 .B inrecv/s Number of input IPv6-datagrams received from interfaces per second, including those received in error (ipv6IfStatsInReceives). .TP 12 .B outreq/s Number of IPv6-datagrams per second that local higher-layer protocols supplied to IP in requests for transmission (ipv6IfStatsOutRequests). This counter does not include any forwarded datagrams. .TP 12 .B inmc/s Number of multicast packets per second that have been received by the interface (ipv6IfStatsInMcastPkts). .TP 12 .B outmc/s Number of multicast packets per second that have been transmitted to the interface (ipv6IfStatsOutMcastPkts). .TP 12 .B indeliv/s Number of IP datagrams successfully delivered per second to IPv6 user-protocols, including ICMP (ipv6IfStatsInDelivers). .TP 12 .B reasmok/s Number of IPv6 datagrams successfully reassembled per second (ipv6IfStatsReasmOKs). .TP 12 .B fragcre/s Number of IPv6 datagram fragments generated per second at this entity (ipv6IfStatsOutFragCreates). .PP The output for the flag .B -Z provides information about the failures that were detected in the IPv6-layer (formal SNMP-names between brackets): .TP 12 .B in: dsc/s Number of input IPv6 datagrams per second for which no problems were encountered to prevent their continued processing but that were discarded, e.g. for lack of buffer space (ipv6IfStatsInDiscards). .TP 12 .B in: hder/s Number of input datagrams per second discarded due to errors in the IPv6 header (ipv6IfStatsInHdrErrors). .TP 12 .B in: ader/s Number of input datagrams per second discarded because the IPv6 address in the destination field was not valid to be received by this entity (ipv6IfStatsInAddrErrors). .TP 12 .B in: unkp/s Number of locally-addressed datagrams per second that were discarded because of an unknown or unsupported protocol (ipv6IfStatsInUnknownProtos). .TP 12 .B in: ratim/s Number of timeout-situations per second while other IPv6 fragments were expected for successful reassembly (ipv6ReasmTimeout). .TP 12 .B in: rfail/s Number of failures detected per second by the IPv6 reassembly-algorithm (ipv6IfStatsReasmFails). .TP 12 .B out: dsc/s Number of output IPv6 datagrams per second for which no problems were encountered to prevent their continued processing but that were discarded, e.g. for lack of buffer space (ipv6IfStatsOutDiscards). .TP 12 .B out: nrt/s Number of IPv6 datagrams per second discarded because no route could be found (ipv6IfStatsInNoRoutes). .PP The output for the flag .B -k provides information about the general utilization of the ICMPv6-layer and some information per type of ICMP-message (formal SNMP-names between brackets): .TP 12 .B intot/s Number of ICMPv6 messages (any type) received per second at the interface (ipv6IfIcmpInMsgs). .TP 12 .B outtot/s Number of ICMPv6 messages (any type) transmitted per second from this entity (ipv6IfIcmpOutMsgs). .TP 12 .B inerr/s Number of ICMPv6 messages received per second that had ICMP-specific errors, such as bad ICMP checksums, bad length, etc (ipv6IfIcmpInErrors). .TP 12 .B innsol/s Number of ICMP Neighbor Solicit messages received per second (ipv6IfIcmpInNeighborSolicits). .TP 12 .B innadv/s Number of ICMP Neighbor Advertisement messages received per second (ipv6IfIcmpInNeighborAdvertisements). .TP 12 .B otnsol/s Number of ICMP Neighbor Solicit messages transmitted per second (ipv6IfIcmpOutNeighborSolicits). .TP 12 .B otnadv/s Number of ICMP Neighbor Advertisement messages transmitted per second (ipv6IfIcmpOutNeighborAdvertisements). .PP The output for the flag .B -K provides information about other types of ICMPv6-messages (formal SNMP-names between brackets): .TP 12 .B iecho/s Number of ICMP Echo (request) messages received per second (ipv6IfIcmpInEchos). .TP 12 .B ierep/s Number of ICMP Echo-Reply messages received per second (ipv6IfIcmpInEchoReplies). .TP 12 .B oerep/s Number of ICMP Echo-Reply messages transmitted per second (ipv6IfIcmpOutEchoReplies). .TP 12 .B idu/s Number of ICMP Destination Unreachable messages received per second (ipv6IfIcmpInDestUnreachs). .TP 12 .B odu/s Number of ICMP Destination Unreachable messages transmitted per second (ipv6IfIcmpOutDestUnreachs). .TP 12 .B ird/s Number of ICMP Redirect messages received per second (ipv6IfIcmpInRedirects). .TP 12 .B ord/s Number of ICMP Redirect messages transmitted per second (ipv6IfIcmpOutRedirect). .TP 12 .B ite/s Number of ICMP Time Exceeded messages received per second (ipv6IfIcmpInTimeExcds). .TP 12 .B ote/s Number of ICMP Time Exceeded messages transmitted per second (ipv6IfIcmpOutTimeExcds). .PP The output for the flag .B -U provides information about the utilization of the UDPv6-layer (formal SNMP-names between brackets): .TP 12 .B indgram/s Number of UDPv6 datagrams per second delivered to UDP users (udpInDatagrams), .TP 12 .B outdgram/s Number of UDPv6 datagrams transmitted per second from this entity (udpOutDatagrams), .TP 12 .B inerr/s Number of received UDPv6 datagrams per second that could not be delivered for reasons other than the lack of an application at the destination port (udpInErrors). .TP 12 .B noport/s Number of received UDPv6 datagrams per second for which there was no application at the destination port (udpNoPorts). .PP The output for the flag .B -t provides information about the utilization of the TCP-layer (formal SNMP-names between brackets): .TP 12 .B insegs/s Number of received segments per second, including those received in error (tcpInSegs). .TP 12 .B outsegs/s Number of transmitted segments per second, excluding those containing only retransmitted octets (tcpOutSegs). .TP 12 .B actopen/s Number of active opens per second that have been supported by this entity (tcpActiveOpens). .TP 12 .B pasopen/s Number of passive opens per second that have been supported by this entity (tcpPassiveOpens). .TP 12 .B nowopen Number of connections currently open (snapshot), for which the state is either ESTABLISHED or CLOSE-WAIT (tcpCurrEstab). .PP The output for the flag .B -T provides information about the failures that were detected in the TCP-layer (formal SNMP-names between brackets): .TP 12 .B inerr/s Number of received segments per second received in error (tcpInErrs). .TP 12 .B retrans/s Number of retransmitted segments per second (tcpRetransSegs). .TP 12 .B attfail/s Number of failed connection attempts per second that have occurred at this entity (tcpAttemptFails). .TP 12 .B estabreset/s Number of resets per second that have occurred at this entity (tcpEstabResets). .TP 12 .B outreset/s Number of transmitted segments per second containing the RST flag (tcpOutRsts). .PP The output for the flag .B -h provides information about utilization of Infiniband ports: .TP 12 .B controller Name of controller. .TP 12 .B port Controller port. .TP 12 .B busy Busy percentage for this port. .TP 12 .B ipack/s Number of packets received from this port per second. .TP 12 .B opack/s Number of packets transmitted to this port per second. .TP 12 .B igbps/s Effective number of gigabits received per second. .TP 12 .B ogbps/s Effective number of gigabits transmitted per second. .TP 12 .B maxgbps/s Maximum rate as number of gigabits per second. .TP 12 .B lanes Number of lanes. .PP The output for the flag .B -O provides information about the top-3 of processes with the highest processor consumption: .TP 12 .B pid Process-id (if zero, the process has exited while the pid could not be determined). .TP 12 .B command The name of the process. .TP 12 .B cpu% The percentage of cpu-capacity being consumed. This value can exceed 100% for a multithreaded process running on a multiprocessor machine. .PP The output for the flag .B -G provides information about the top-3 of processes with the highest memory consumption: .TP 12 .B pid Process-id (if zero, the process has exited while the pid could not be determined). .TP 12 .B command The name of the process. .TP 12 .B mem% The percentage of resident memory-utilization by this process. .PP The output for the flag .B -D provides information about the top-3 of processes that issue the most read and write accesses to disk: .TP 12 .B pid Process-id (if zero, the process has exited while the pid could not be determined). .TP 12 .B command The name of the process. .TP 12 .B dsk% The percentage of read and write accesses related to the total number of read and write accesses issued on disk by all processes, so a high percentage does not imply a high disk load on system level. .PP The output for the flag .B -N provides information about the top-3 of processes that issue the most socket transfers for IPv4/IPv6: .TP 12 .B pid Process-id (if zero, the process has exited while the pid could not be determined). .TP 12 .B command The name of the process. .TP 12 .B net% The percentage of socket transfers related to the total number of transfers issued by all processes, so a high percentage does not imply a high network load on system level. .SH EXAMPLES To see today's cpu-activity so far (supposed that .B atop is logging in the background): .PP .TP 12 .B \ atopsar .PP To see the memory occupation for June 5, 2018 between 10:00 and 12:30 (supposed that .B atop has been logging daily in the background): .PP .TP 12 .B \ atopsar -m -r /var/log/atop_20180605 -b 10:00 -e 12:30 .br \ .br or .TP 12 .B \ atopsar -m -r 20180605 -b 10:00 -e 12:30 .br \ .br or, suppose it is June 8, 2018 at this moment .TP 12 .B \ atopsar -m -r yyy -b 10:00 -e 12:30 .PP Write a logfile with .B atop to record the system behaviour for 30 minutes (30 samples of one minute) and produce all available reports afterwards: .PP .TP 12 .B \ atop -w /tmp/atoplog 60 30 .TP 12 .B \ atopsar -A -r /tmp/atoplog .PP To watch TCP activity evolve for ten minutes (10 samples with sixty seconds interval): .PP .TP 12 .B \ atopsar -t 60 10 .PP To watch the header-lines ('_' as last character) of all reports with only the detail-lines showing critical resource consumption (marker '*' or '+' as last character): .PP .TP 12 .B \ atopsar -AM | grep '[_*+]$' .PP .SH FILES .PP .TP 5 .B /etc/atoprc Configuration file containing system-wide default values (mainly flags). See related man-page. .PP .TP 5 .B ~/.atoprc Configuration file containing personal default values (mainly flags). See related man-page. .PP .TP 5 .BI /var/log/atop/atop_ YYYYMMDD Daily data file, where .I YYYYMMDD are digits representing the date. .SH SEE ALSO .B atop(1), .B atopconvert(1), .B atoprc(5), .B atopacctd(8), .B netatop(4), .B netatopd(8) .br .B https://www.atoptool.nl .SH AUTHOR Gerlof Langeveld (gerlof.langeveld@atoptool.nl) atop-2.4.0/man/atop.10000664000203100020310000023574613416466037013615 0ustar gerlofgerlof.TH ATOP 1 "January 2019" "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] [\-C|\-M|\-D|\-N|\-A] [\-afFG1xR] [\-L linelen] [\-Plabel[,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 hh:mm ] [\-e .I hh:mm ] [\-g|\-m|\-d|\-n|\-u|\-p|\-s|\-c|\-v|\-o|\-y] [\-C|\-M|\-D|\-N|\-A] [\-fFG1xR] [\-L linelen] [\-Plabel[,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 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 are not shown, unless the key 'a' has been pressed or unless sorting on memory occupation is done). 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 The intervals are repeated till the number of .I samples (specified as command argument) is reached, or till the key 'q' is pressed in interactive mode. .PP When .I atop 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. .PP In interactive mode, the output of .I atop scales dynamically to the current dimensions of the screen/window. .br If the window is resized horizontally, columns will be added or removed automatically. For this purpose, every column has a particular weight. The columns with the highest weights that fit within the current width will be shown. .br 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 .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 be modified again interactively. Specifying such key as flag is especially useful when running .I atop with output to a pipe or file (non-interactively). These flags are the same as the keys that can be pressed in interactive mode (see section INTERACTIVE COMMANDS). .br Additional flags are available to support storage of atop-data in raw format (see section RAW DATA STORAGE). .SH PROCESS ACCOUNTING With every interval, .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. These processes might have consumed system resources during this interval as well before they terminated. Therefor, .I atop tries to read the process accounting records that contain the accounting information of terminated processes and report these processes too. Only when the process accounting mechanism in the kernel is activated, the kernel writes such process accounting record to a file for every process that terminates. .PP There are various ways for .I atop to get access to the process accounting records (tried in this order): .PP .TP 4 1. When the environment variable ATOPACCT is set, it specifies the name of the process accounting file. In that case, process accounting for this file should have been activated on beforehand. Before opening this file for reading, .I atop drops its root privileges (if any). .br When this environment variable is present but its contents is empty, process accounting will not be used at all. .PP .TP 4 2. .B This is the preferred way of handling process accounting records! .br When the .I atopacctd daemon is active, it has activated the process accounting mechanism in the kernel and transfers to original accounting records to shadow files. In that case, .I atop drops its root privileges and opens the current shadow file for reading. .br This way is preferred, because the .I atopacctd daemon maintains full control of the sizes of the original process accounting file (written by the kernel) and the shadow files (read by the .I atop processes). For further information, refer to the .B atopacctd man page. .PP .TP 4 3. When the .I atopacctd daemon is not active, .I atop verifies if the process accounting mechanism has been switched on via the separate .B psacct package. In that case, the file .B /var/account/pacct is in use as process accounting file and .I atop opens this file for reading. .PP .TP 4 4. As a last possibility, .I atop itself tries to activate the process accounting mechanism (requires root privileges) using the file .B /var/cache/atop.d/atop.acct (to be written by the kernel, to be read by .I atop itself). Process accounting remains active as long as at least one .I atop process is alive. Whenever the last .I atop process stops (either by pressing `q' or by `kill \-15'), it deactivates the process accounting mechanism again. Therefor you should never terminate .I atop 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 To avoid that the process accounting file consumes too much disk space, .I atop verifies at the end of every sample if the size of the process accounting file exceeds 200 MiB and if this .I atop process is the only one that is currently using the file. In that case the file is truncated to a size of zero. Notice that root-privileges are required to switch on/off process accounting in the kernel. You can start .I atop as a root user or specify setuid-root privileges to the executable file. In the latter case, .I atop switches on process accounting and drops the root-privileges again. .br If .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 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, .I atop will never read more than 50 MiB with process information from the process accounting file per interval (approx. 70000 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. 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 percentage of 90%. .br Currently .I atop uses the following default values to calculate a weighted percentage per resource: .PP .TP 5 .B \ Processor A busy percentage of 90% or higher is considered `critical'. .TP 5 .B \ Disk A busy percentage of 70% 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'. .TP 5 .B \ Memory 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'. .br 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. .PP These default values can be modified in the configuration file (see separate man-page of atoprc). .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 (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). .br The default colors red and cyan can be modified in the configuration file as well (see separate man-page of atoprc). .PP With the key 'x' (or flag \-x), the use of colors can be suppressed. .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. .br When .I atop gathers counters for a new interval, it verifies if the .I netatop module is currently active. If so, .I atop 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. .br When the .I netatopd daemon is running as well, .I atop also reads the network counters of exited processes that are logged by this daemon (comparable with process accounting). .PP More information about the optional .I netatop kernel module and the .I netatopd daemon can be found in the concerning man-pages and on the website mentioned at the end of this manual page. .SH GPU STATISTICS GATHERING GPU statistics can be gathered by .I atopgpud which is a separate data collection daemon process. It gathers cumulative utilization counters of every Nvidia GPU in the system, as well as utilization counters of every process that uses a GPU. When .I atop notices that the daemon is active, it reads these GPU utilization counters with every interval. 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. 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 .I pip might be exchanged by .I pip3 in case of Python3): .PP .B \ pip install nvidia-ml-py .PP The .I atopgpud daemon is installed by default as part of the .B atop package, but it is .I not automatically enabled. The daemon can be enabled and started now by running the following commands (as root): .PP .B \ systemctl enable atopgpu .br .B \ systemctl start atopgpu .PP Find a description about the utilization counters in the section OUTPUT DESCRIPTION. .SH INTERACTIVE COMMANDS When running .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. .PP .TP 5 .B g Show generic output (default). Per process the following fields are shown in case of a window-width of 80 positions: 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. .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. When more than 80 positions are available, other information is added. .PP .TP 5 .B m Show memory related output. 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 process size, total resident process size, virtual and resident growth during last interval, memory occupation percentage and process name. When more than 80 positions are available, other information is added. For memory consumption, always all processes are shown (also the processes that were not active during the interval). .PP .TP 5 .B d Show disk-related output. When "storage accounting" is active in the kernel, 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. .PP .TP 5 .B n Show network related output. 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, total bandwidth for sent packets, number of received TCP packets with the average size per packet (in bytes), number of sent TCP packets with the average size per packet (in bytes), number of received UDP packets with the average size per packet (in bytes), 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. When more than 80 positions are available, other information is added. .PP .TP 5 .B s Show scheduling characteristics. 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), number of threads in state 'interruptible sleeping' (S), number of threads in state 'uninterruptible sleeping' (D), scheduling policy (normal timesharing, realtime round-robin, realtime fifo), nice value, priority, realtime priority, current processor, status, exit code, state, the occupation percentage for the chosen resource and the process name. When more than 80 positions are available, other information is added. .PP .TP 5 .B v Show various process characteristics. 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), state, the occupation percentage for the chosen resource and the process name. When more than 80 positions are available, other information is added. .PP .TP 5 .B c Show the command line of the process. Per process the following fields are shown: process-id, the occupation percentage for the chosen resource and the command line including arguments. .PP .TP 5 .B e Show GPU utilization. Per process at least the following fields are shown: process-id, range of GPU numbers on which the process currently runs, GPU busy percentage on all GPUs, memory busy percentage (i.e. read and write accesses on memory) on all GPUs, memory occupation at the moment of the sample, average memory occupation during the sample, and GPU percentage. When the .I atopgpud daemon does not run with root privileges, the GPU busy percentage and the memory busy percentage are not available on process level. In that case, the GPU percentage on process level reflects the GPU memory occupation instead of the GPU busy percentage (which is preferred). .PP .TP 5 .B o Show the user-defined line of the process. In the configuration file the keyword .I ownprocline can be specified with the description of a user-defined output-line. .br Refer to the man-page of .B atoprc for a detailed description. .PP .TP 5 .B y Show the individual threads within a process (toggle). Single-threaded processes are still shown as one line. .br For multi-threaded processes, one line represents the process while additional lines show the activity per individual thread (in a different color). Depending on the option 'a' (all or active toggle), all threads are shown or only the threads that were active during the last interval. .br Whether this key is active or not can be seen in the header line. .PP .TP 5 .B u 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, the current virtual and resident memory space consumed by active processes (or all processes of the user if combined with command `a'). .br When "storage accounting" is active in the kernel, 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. .br The last columns contain the accumulated occupation percentage for the 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, the current virtual and resident memory space consumed by active processes (or all processes of the user if combined with command `a'). .br When "storage accounting" is active in the kernel, 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. .br The last columns contain the accumulated occupation percentage for the 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, the current virtual and resident memory space consumed by active processes (or all processes of the user if combined with command `a'). .br When "storage accounting" is active in the kernel, 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. .br The last columns contain the accumulated occupation percentage for the 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''. .PP .TP 5 .B E Sort the current list in the order of GPU utilization (preferred, but only applicable when the .I atopgpud daemon runs under root privileges) or the order of GPU memory occupation). 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 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''. .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''. .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 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 the section COLORS. .br 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' is loaded. .PP Miscellaneous interactive commands: .PP .TP 5 .B ? Request for help information (also the key 'h' can be pressed). .PP .TP 5 .B V Request for version information (version number and date). .PP .TP 5 .B R Gather and calculate the proportional set size of processes (toggle). Gathering of all values that are needed to calculate the PSIZE of a process is a relatively time-consuming task, so this key should only be active when analyzing the resident memory consumption of processes. .PP .TP 5 .B x Suppress colors to highlight critical resources (toggle). .br Whether this key is active or not can be seen in the header line. .PP .TP 5 .B z The pause key can be used to freeze the current situation in order to investigate the output on the screen. While .I atop is paused, the keys described above can be pressed to show other information about the current list of processes. Whenever the pause key is pressed again, atop will continue with a next sample. .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'. .PP .TP 5 .B t Trigger a new sample manually. This key can be pressed if the current sample should be finished before the timer has exceeded, or if no timer is set at all (interval timer defined as 0). In the latter case .I atop 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. When viewing the contents of a raw file, this key can be used to show the next sample from the file. .PP .TP 5 .B T When viewing the contents of a raw file, this key can be used to show the previous sample from the file. .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). .PP .TP 5 .B r Reset all counters to zero to see the system and process activity since boot again. When viewing the contents of a raw file, this key can be used to rewind to the beginning of the file again. .PP .TP 5 .B U Specify a search string for specific user names as a regular expression. From now on, only (active) processes will be shown from a user which matches the regular expression. The system statistics are still system wide. If the Enter-key is pressed without specifying a name, (active) processes of all users will be shown again. .br Whether this key is active or not can be seen in the header line. .PP .TP 5 .B I Specify a list with one or more PIDs to be selected. From now on, only processes will be shown with a PID which matches one of the given list. The system statistics are still system wide. If the Enter-key is pressed without specifying a PID, all (active) processes will be shown again. .br Whether this key is active or not can be seen in the header line. .PP .TP 5 .B P Specify a search string for specific process names as a regular expression. From now on, only processes will be shown with a name which matches the regular expression. The system statistics are still system wide. If the Enter-key is pressed without specifying a name, all (active) processes will be shown again. .br Whether this key is active or not can be seen in the header line. .PP .TP 5 .B / Specify a specific command line search string as a regular expression. From now on, only processes will be shown with a command line which matches the regular expression. The system statistics are still system wide. If the Enter-key is pressed without specifying a string, all (active) processes will be shown again. .br Whether this key is active or not can be seen in the header line. .PP .TP 5 .B J Specify a Docker container id of 12 (hexadecimal) characters. From now on, only processes will be shown that run in that specific Docker container (CID). The system statistics are still system wide. If the Enter-key is pressed without specifying a container id, all (active) processes will be shown again. .br Whether this key is active or not can be seen in the header line. .PP .TP 5 .B S Specify search strings for specific logical volume names, specific disk names and specific network interface names. All search strings are interpreted as a regular expressions. From now on, only those system resources are shown that match the concerning regular expression. If the Enter-key is pressed without specifying a search string, all (active) system resources of that type will be shown again. .br Whether this key is active or not can be seen in the header line. .PP .TP 5 .B a 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 Whether this key is active or not can be seen in the header line. .PP .TP 5 .B G By default, .I atop shows/accumulates the processes that are alive and the processes that are exited during the last interval. With this key (toggle), showing/accumulating the processes that are exited can be suppressed. .br Whether this key is active or not can be seen in the header line. .PP .TP 5 .B f Show a fixed (maximum) number of header lines for system resources (toggle). By default only the lines are shown about system resources (CPUs, paging, logical volumes, disks, network interfaces) that really have been active during the last interval. With this key you can force .I atop to show lines of inactive resources as well. .br Whether this key is active or not can be seen in the header line. .PP .TP 5 .B F Suppress sorting of system resources (toggle). By default system resources (CPUs, logical volumes, disks, network interfaces) are sorted on utilization. .br Whether this key is active or not can be seen in the header line. .PP .TP 5 .B 1 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. .PP .TP 5 .B l Limit the number of system level lines for the counters per-cpu, the active disks and the network interfaces. By default lines are shown of all CPUs, disks and network interfaces which have been active during the last interval. Limiting these lines can be useful on systems with huge number CPUs, disks or interfaces in order to be able to run .I atop on a screen/window with e.g. only 24 lines. .br For all mentioned resources the maximum number of lines can be specified interactively. When using the flag .B -l the maximum number of per-cpu lines is set to 0, the maximum number of disk lines to 5 and the maximum number of interface lines to 3. These values can be modified again in interactive mode. .PP .TP 5 .B k Send a signal to an active process (a.k.a. kill a process). .PP .TP 5 .B q Quit the program. .PP .TP 5 .B PgDn Show the next page of the process/thread list. .br With the arrow-down key the list can be scrolled downwards with single lines. .PP .TP 5 .B ^F Show the next page of the process/thread list (forward). .br With the arrow-down key the list can be scrolled downwards with single lines. .PP .TP 5 .B PgUp Show the previous page of the process/thread list. .br With the arrow-up key the list can be scrolled upwards with single lines. .PP .TP 5 .B ^B Show the previous page of the process/thread list (backward). .br With the arrow-up key the list can be scrolled upwards with single lines. .PP .TP 5 .B ^L Redraw the screen. .SH RAW DATA STORAGE In order to store system and process level statistics for long-term analysis (e.g. to check the system load and the active processes running yesterday between 3:00 and 4:00 PM), .I atop can store the system and process level statistics in compressed binary format in a raw file with the flag .B -w followed by the filename. 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. .br All information about processes and threads 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 .B -S can be used to indicate that .I atop should finish anyhow before midnight. .PP A raw file can be read and visualized again with the flag .B -r followed by the filename. If no filename is specified, the file .BI /var/log/atop/atop_ YYYYMMDD is opened for input (where .I YYYYMMDD are digits representing the current date). If a filename is specified in the format YYYYMMDD (representing any valid date), the file .BI /var/log/atop/atop_ YYYYMMDD is opened. If a filename with the symbolic name .BI y is specified, yesterday's daily logfile is opened (this can be repeated so 'yyyy' indicates the logfile of four days ago). .br 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. .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 .B -L followed by an alternate line length, more (or less) columns will be shown. .br With the flag .B -b (begin time) and/or .B -e (end time) followed by a time argument of the form HH:MM, a certain time period within the raw file can be selected. .PP When .B atop is installed, the script .B atop.daily is stored in the .I /usr/share/atop directory. This scripts takes care that .B atop is activated every day at midnight to write compressed binary data to the file .BI /var/log/atop/atop_ YYYYMMDD with an interval of 10 minutes by default. The .B -R flag is passed by default to gather information about the proportional set size of every process. .br Furthermore the script removes all raw files which are by default older than 28 days. .br The mentioned default values can be overruled by creating the file .B /etc/default/atop that might contain other values for .B LOGOPTS (by default the .B -R flag), .B LOGINTERVAL (in seconds, by default 600), and .B LOGGENERATIONS (in days, by default 28). .PP The .B atop.daily script is activated via the .B cron daemon using the file .I /etc/cron.d/atop with the contents .br .B \ \ \ \ \ \ \ \ 0 0 * * * root /usr/share/atop/atop.daily .PP When the package .B psacct is installed, the process accounting is automatically restarted via the .B logrotate mechanism. The file .B /etc/logrotate.d/psaccs_atop takes care that .B atop is finished just before the rotation of the process accounting file and the file .B /etc/logrotate.d/psaccu_atop takes care that .B atop is restarted again after the rotation. When the package .B psacct is not installed, these logrotate-files have no effect. .PP 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. Therefore, the program .B atopconvert is installed to convert a raw file created by an older version of .B atop to a raw file that can be read by a newer version of .B atop (see the man page of .B atopconvert for more details). .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. .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 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' (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, ...). 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: .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 the number of processes that ended during the interval (`#exit') when process accounting is used. Instead of `#exit` the last column may indicate that process accounting could not be activated (`no procacct`). .br If the screen-width does not allow all of these counters, only a relevant subset is shown. .PP .TP 5 .B CPU CPU utilization. .br 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), sorted on activity. Inactive CPUs will not be shown by default. 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 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'). .br 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 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 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. The first sample always shows the value 'initial', because the counters are just activated at the moment that .I atop is started. .br When the .I CPU busy percentage is high and the IPC is less than 1.0, it is likely that the CPU is frequently waiting for memory access during instruction execution (larger CPU caches or faster memory might be helpful to improve performance). When the .I CPU busy percentage is high and the IPC is greater than 1.0, 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. 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. .br Notice that the .I average instructions per cycle and number of cycles is shown in the CPU line for all CPUs. .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 issueing `modprobe cpufreq_stats'), the .I average frequency (`avgf') and the .I average scaling percentage (`avgscal') is shown. Otherwise the .I current frequency (`curf') and the .I current scaling percentage (`curscal') is shown at the moment that the sample is taken. Notice that .I average values for frequency and scaling are shown in the CPU line for every CPU. .br Frequency scaling statistics are only gathered for systems with maximum 8 CPUs, since gathering of these values per CPU is very time consuming. If the screen-width does not allow all of these counters, only a relevant subset is shown. .PP .TP 5 .B CPL CPU load information. .br 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. .br 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. .PP .TP 5 .B GPU GPU utilization (Nvidia). .br Read the section GPU STATISTICS GATHERING in this document to find the details about the activation of the .I atopgpud daemon. 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 the type of GPU. If the screen-width does not allow all of these counters, only a relevant subset is shown. .br The number of lines showing the GPUs can be limited. .PP .TP 5 .B MEM Memory occupation. .br This line contains the total amount of physical memory (`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 claimed by vmware's balloon driver (`vmbal`), the amount of memory that is claimed for huge pages (`hptot`), and the amount of huge page memory that is really in use (`hpuse`). If the screen-width does not allow all of these counters, only a relevant subset is shown. .PP .TP 5 .B SWP Swap occupation and overcommit info. .br This line contains the total amount of swap space on disk (`tot') and the amount of free swap space (`free'). .br 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 committed space exceeds the limit if strict overcommit handling is configured (vm.overcommit_memory is 2). .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 and the number times that the kernel tries to reclaim pages due to an urgent need (`stall'). .br Also the number of memory pages the system read from swap space (`swin') and the number of memory pages the system wrote to swap space (`swout') are shown. .PP .TP 5 .B PSI Pressure Stall Information. .br This line contains three percentages per category: average pressure percentage over the last 10, 60 and 300 seconds (separated by slashes). .br The categories are: CPU for 'some' (`cs'), memory for 'some' (`ms'), memory for 'full' (`mf'), I/O for 'some' (`is'), and I/O for 'full' (`if'). .PP .TP 5 .B LVM/MDD/DSK Logical volume/multiple device/disk utilization. .br 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 busy percentage i.e. the portion of time that the unit was busy handling requests (`busy'), the number of read requests issued (`read'), the number of write requests issued (`write'), the number of KiBytes per read (`KiB/r'), the number of KiBytes per write (`KiB/w'), the number of MiBytes per second throughput for reads (`MBr/s'), the number of MiBytes per second throughput for writes (`MBw/s'), the average queue depth (`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, only a relevant subset is shown. The number of lines showing the units can be limited per class (LVM, MDD or DSK) with the 'l' key or statically (see separate man-page of atoprc). By specifying the value 0 for a particular class, no lines will be shown any more for that class. .PP .TP 5 .B NFM 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'). 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'). .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'). .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'). 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'). .PP .TP 5 .B NET Network utilization (TCP/IP). .br One line is shown for activity of the transport layer (TCP and UDP), one line for the IP layer and one line per active interface. .br For the transport layer, counters are shown concerning the number of received TCP segments 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'). .br If the screen-width does not allow all of these counters, only a relevant subset is shown. .br 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'), 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'). .br If the screen-width does not allow all of these counters, only a relevant subset is shown. .br These counters are related to IPv4 and IPv6 combined. For every active network interface one line is shown, sorted on the interface activity. Such line shows the name of the interface and its busy percentage in the first column. The busy percentage for half duplex is determined by comparing the interface speed with the number of bits transmitted and received 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. .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'). .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 network interfaces can be limited. .PP .TP 5 .B IFB Infiniband utilization. .br For every active Infiniband port one line is shown, sorted on activity. Such line shows the name of the port and its busy percentage in the first column. The busy percentage is determined by taking the highest of either the transmitted or the received bits during the interval, multiplying that value by the number of lanes and comparing it against the 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'). .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 resource utilization has changed during the last interval. These processes might have used cpu time or 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 Per process the following fields may be shown (in alphabetical order), depending on the current output mode as described in the section INTERACTIVE COMMANDS and depending on the current width of your window: .PP .TP 9 .B AVGRSZ The average size of one read-action on disk. .PP .TP 9 .B AVGWSZ The average size of one write-action on disk. .PP .TP 9 .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' on interface level (used bandwidth per interface). .br 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' on interface level (used bandwidth per interface). .br This information will only be shown when the kernel module `netatop' is loaded. .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 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 interval. .br 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 .B COMMAND-LINE The full command line of the process (including arguments). If the length of 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 and the total number of pages of the process/thread list are shown. .PP .TP 9 .B CPU The occupation percentage of this process related to the available capacity for this resource on system level. .PP .TP 9 .B CPUNR The identification of the CPU the (main) thread is running on or has recently been running on. .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 the standard process accounting record. .PP .TP 9 .B DSK The occupation percentage of this process related to the total load that is produced by all processes (i.e. total disk accesses by all processes during the last interval). .br This information is shown when per process "storage accounting" is active in the kernel. .PP .TP 9 .B EGID Effective group-id under which this process executes. .PP .TP 9 .B ENDATE Date that the process has been finished. If the process is still running, 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'. .PP .TP 9 .B ENVID Virtual environment identified (OpenVZ only). .PP .TP 9 .B EUID Effective user-id under which this process executes. .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). .PP .TP 9 .B FSGID Filesystem group-id under which this process executes. .PP .TP 9 .B FSUID Filesystem user-id under which this process executes. .PP .TP 9 .B GPU When the .I atopgpud daemon does not run with root privileges, the GPU percentage reflects the GPU memory occupation percentage (memory of all GPUs is 100%). .br When the .I atopgpud daemon runs with root privileges, the GPU percentage reflects the GPU busy percentage. .PP .TP 9 .B GPUBUSY Busy percentage on all GPUs (one GPU is 100%). .br When the .I atopgpud daemon does not run with root privileges, this value is not available. .PP .TP 9 .B GPUNUMS Comma-separated list of GPUs used by the process during the interval. When the comma-separated list exceeds the width of the column, a hexadecimal value is shown. .PP .TP 9 .B MAJFLT The number of page faults issued by this process that have been solved by creating/loading the requested memory page. .PP .TP 9 .B MEM The occupation percentage of this process related to the available capacity for this resource on system level. .PP .TP 9 .B MEMAVG Average memory occupation during the interval on all used GPUs. .PP .TP 9 .B MEMBUSY Busy percentage of memory on all GPUs (one GPU is 100%), i.e. the time needed for read and write accesses on memory. .br When the .I atopgpud daemon does not run with root privileges, this value is not available. .PP .TP 9 .B MEMNOW Memory occupation at the moment of the sample on all used GPUs. .PP .TP 9 .B MINFLT The number of page faults issued by this process that have been solved by reclaiming the requested memory page from the free list of pages. .PP .TP 9 .B NET The occupation percentage of this process related to the total load that 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. .PP .TP 9 .B NICE The more or less static priority that can be given to a process on a scale from -20 (high priority) to +19 (low priority). .PP .TP 9 .B NPROCS The number of active and terminated processes accumulated for this user or program. .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 the standard process accounting record. .PP .TP 9 .B POLI The policies 'norm' (normal, which is SCHED_OTHER), 'btch' (batch) and 'idle' refer to timesharing processes. The policies 'fifo' (SCHED_FIFO) and 'rr' (round robin, which is SCHED_RR) refer to realtime processes. .PP .TP 9 .B PPID Parent process-id. If a process has been started and finished during the last interval, value 0 is shown because the parent process-id is not part of the standard process accounting record. .PP .TP 9 .B PRI The process' priority ranges from 0 (highest priority) to 139 (lowest priority). Priority 0 to 99 are used for realtime processes (fixed priority independent of their behavior) and priority 100 to 139 for timesharing processes (variable priority depending on their recent CPU consumption and the nice value). .PP .TP 9 .B PSIZE The proportional memory size of this process (or user). .br Every process shares resident memory with other processes. E.g. when a particular program is started several times, the code pages (text) are only loaded once in memory and shared by all incarnations. Also the code of shared libraries is shared by all processes using that shared library, as well as shared memory and memory-mapped files. For the PSIZE calculation of a process, the resident memory of a process that is shared with other processes is divided by the number of sharers. This means, that every process is accounted for a proportional part of that memory. Accumulating the PSIZE values of all processes in the system gives a reliable impression of the total resident memory consumed by all processes. .br Since gathering of all values that are needed to calculate the PSIZE is a relatively time-consuming task, the 'R' key (or '-R' flag) should be active. Gathering these values also requires superuser privileges (otherwise '?K' is shown in the output). .br If a process has finished during the last interval, no value is shown since the proportional memory size is not part of the standard process accounting record. .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 Unfortunately, the kernel aggregates the data tranfer of a process to the data transfer of its parent process when terminating, so you might see transfers for (parent) processes like cron, bash or init, that are not really issued by them. .PP .TP 9 .B RGID The real group-id under which the process executes. .PP .TP 9 .B RGROW The amount of resident memory that the process has grown during the last interval. A resident growth can be caused by touching memory pages which were not physically created/loaded before (load-on-demand). Note that a resident growth can also be negative e.g. when part of the process is paged out due to lack of memory or when the process frees dynamically allocated memory. For a process which started during the last interval, the resident growth reflects the total resident size of the process at that moment. .br If a process has finished during the last interval, no value is shown since resident memory occupation is not part of the standard process accounting record. .PP .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. .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. .PP .TP 9 .B RSIZE The total resident memory usage consumed by this process (or user). Notice that the RSIZE of a process includes all resident memory used by that process, even if certain memory parts are shared with other processes (see also the explanation of PSIZE). .br If a process has finished during the last interval, no value is shown since resident memory occupation is not part of the standard process accounting record. .PP .TP 9 .B RTPR Realtime priority according the POSIX standard. Value can be 0 for a timesharing process (policy 'norm', 'btch' or 'idle') or ranges from 1 (lowest) till 99 (highest) for a realtime process (policy 'rr' or 'fifo'). .PP .TP 9 .B RUID The real user-id under which the process executes. .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. .PP .TP 9 .B SGID The saved group-id of the process. .PP .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' is loaded. .PP .TP 9 .B ST The status of a process. .br The first position indicates if the process has been started during the last interval (the value .I N means 'new process'). The second position indicates if the process has been finished during the last interval. .br The value .I E means 'exit' on the process' own initiative; the exit code is displayed 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'. .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'. .PP .TP 9 .B STDATE The start date of the process. .PP .TP 9 .B STTIME The start time of the process. .PP .TP 9 .B SUID The saved user-id of the process. .PP .TP 9 .B SWAPSZ The swap space consumed by this process (or user). .PP .TP 9 .B SYSCPU CPU time consumption of this process in system mode (kernel mode), usually due to system call handling. .PP .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' 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' 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' 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' is loaded. .PP .TP 9 .B THR Total number of threads within this process. All related threads are contained in a thread group, represented by .I atop as one line or as a separate line when the 'y' key (or -y flag) is active. On Linux 2.4 systems it is hardly possible to determine which threads (i.e. processes) are related to the same thread group. Every thread is represented by .I atop as a separate line. .PP .TP 9 .B TID Thread-id. All threads within a process run with the same PID but with a different TID. This value is shown for individual threads in multi-threaded processes (when using the key 'y'). .PP .TP 9 .B TRUN Number of threads within this process that are in the state 'running' (R). .PP .TP 9 .B TSLPI Number of threads within this process that are in the state 'interruptible sleeping' (S). .PP .TP 9 .B TSLPU Number of threads within this process that are in the state 'uninterruptible sleeping' (D). .PP .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' 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' 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' 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' is loaded. .PP .TP 9 .B USRCPU CPU time consumption of this process in user mode, due to processing the own program text. .PP .TP 9 .B VDATA The virtual memory size of the private data used by this process (including heap and shared library data). .PP .TP 9 .B VGROW The amount of virtual memory that the process has grown during the last interval. A virtual growth can be caused by e.g. issueing a malloc() or attaching a shared memory segment. Note that a virtual growth can also be negative by e.g. issueing a free() or detaching a shared memory segment. For a process which started during the last interval, the virtual growth reflects the total virtual size of the process at that moment. .br If a process has finished during the last interval, no value is shown since virtual memory occupation is not part of the standard process accounting record. .PP .TP 9 .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 the standard process accounting record. .PP .TP 9 .B VSIZE The total virtual memory usage consumed by this process (or user). .br If a process has finished during the last interval, no value is shown since virtual memory occupation is not part of the standard process accounting record. .PP .TP 9 .B VSLIBS The virtual memory size of the (shared) text of all shared libraries used by this process. .PP .TP 9 .B VSTACK The virtual memory size of the (private) stack used by this process .PP .TP 9 .B VSTEXT The virtual memory size of the (shared) text of the executable program. .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 data to the cache (assuming that this data is physically transferred to disk later on). Notice that disk I/O needed for swapping is not taken into account. .br Unfortunately, the kernel aggregates the data tranfer of a process to the data transfer of its parent process when terminating, so you might see transfers for (parent) processes like cron, bash or init, that are not really issued by them. .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 again before the cache buffers have been flushed to disk. 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 With the flag .B -P followed by a list of one or more labels (comma-separated), parseable 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: "CPU", "cpu", "CPL", "GPU", "MEM", "SWP", "PAG", "PSI", "LVM", "MDD", "DSK", "NFM", "NFC", "NFS", "NET" and "IFB". .br For process-level statistics special labels are introduced: "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 For every interval all requested lines are shown whereafter .B atop shows a line just containing the label "SEP" as a separator before the lines for the next sample are generated. .br When a sample contains the values since boot, .B atop shows a line just containing the label "RESET" before the lines for this sample are generated. .PP The first part of each output-line consists of the following six fields: .B label (the name of the label), .B host (the name of this machine), .B epoch (the time of this interval as number of seconds since 1-1-1970), .B date (date of this interval in format YYYY/MM/DD), .B time (time of this interval in format HH:MM:SS), and .B interval (number of seconds elapsed for this interval). .PP The subsequent fields of each output-line depend on the label: .PP .TP 9 .B CPU Subsequent fields: total number of clock-ticks per second for this machine, number of processors, consumption for all CPUs in system mode (clock-ticks), consumption for all CPUs in user mode (clock-ticks), consumption for all CPUs in user mode for niced processes (clock-ticks), consumption for all CPUs in idle mode (clock-ticks), consumption for all CPUs in wait mode (clock-ticks), consumption for all CPUs in irq mode (clock-ticks), consumption for all CPUs in softirq mode (clock-ticks), consumption for all CPUs in steal mode (clock-ticks), consumption for all CPUs in guest mode (clock-ticks) overlapping user mode, frequency of all CPUs, frequency percentage of all CPUs, instructions executed by all CPUs and cycles for all CPUs. .TP 9 .B cpu Subsequent fields: total number of clock-ticks per second for this machine, processor-number, consumption for this CPU in system mode (clock-ticks), consumption for this CPU in user mode (clock-ticks), consumption for this CPU in user mode for niced processes (clock-ticks), consumption for this CPU in idle mode (clock-ticks), consumption for this CPU in wait mode (clock-ticks), consumption for this CPU in irq mode (clock-ticks), consumption for this CPU in softirq mode (clock-ticks), consumption for this CPU in steal mode (clock-ticks), consumption for this CPU in guest mode (clock-ticks) overlapping user mode, frequency of this CPU, frequency percentage of this CPU, instructions executed by this CPU and cycles for this CPU. .TP 9 .B CPL Subsequent fields: number of processors, load average for last minute, load average for last five minutes, load average for last fifteen minutes, number of context-switches, and number of device interrupts. .TP 9 .B GPU Subsequent fields: GPU number, bus-id string, type of GPU string, GPU busy percentage during last second (-1 if not available), memory busy percentage during last second (-1 if not available), total memory size (KiB), used memory (KiB) at this moment, number of samples taken during interval, cumulative GPU busy percentage during the interval (to be divided by the number of samples for the average busy percentage, -1 if not available), cumulative memory busy percentage during the interval (to be divided by the number of samples for the average busy percentage, -1 if not available), and cumulative memory occupation during the interval (to be divided by the number of samples for the average occupation). .TP 9 .B MEM Subsequent fields: page size for this machine (in bytes), size of physical memory (pages), size of free memory (pages), size of page cache (pages), size of buffer cache (pages), size of slab (pages), dirty pages in cache (pages), reclaimable part of slab (pages), total size of vmware's balloon pages (pages), total size of shared memory (pages), size of resident shared memory (pages), size of swapped shared memory (pages), huge page size (in bytes), total size of huge pages (huge pages), and size of free huge pages (huge pages). .TP 9 .B SWP Subsequent fields: page size for this machine (in bytes), size of swap (pages), size of free swap (pages), 0 (future use), size of committed space (pages), and limit for committed space (pages). .TP 9 .B PAG Subsequent fields: page size for this machine (in bytes), number of page scans, number of allocstalls, 0 (future use), number of swapins, and number of swapouts. .TP 9 .B PSI Subsequent fields: PSI statistics present on this system (n or y), CPU some avg10, CPU some avg60, CPU some avg300, CPU some accumulated microseconds during interval, memory some avg10, memory some avg60, memory some avg300, memory some accumulated microseconds during interval, memory full avg10, memory full avg60, memory full avg300, memory full accumulated microseconds during interval, I/O some avg10, I/O some avg60, I/O some avg300, I/O some accumulated microseconds during interval, I/O full avg10, I/O full avg60, I/O full avg300, and I/O full accumulated microseconds during interval. .TP 9 .B LVM/MDD/DSK For every logical volume/multiple device/hard disk one line is shown. .br Subsequent fields: name, number of milliseconds spent for I/O, number of reads issued, number of sectors transferred for reads, number of writes issued, and number of sectors transferred for write. .TP 9 .B NFM Subsequent fields: mounted NFS filesystem, total number of bytes read, total number of bytes written, number of bytes read by normal system calls, number of bytes written by normal system calls, number of bytes read by direct I/O, number of bytes written by direct I/O, number of pages read by memory-mapped I/O, and number of pages written by memory-mapped I/O. .TP 9 .B NFC Subsequent fields: number of transmitted RPCs, number of transmitted read RPCs, number of transmitted write RPCs, number of RPC retransmissions, and number of authorization refreshes. .TP 9 .B NFS Subsequent fields: number of handled RPCs, number of received read RPCs, number of received write RPCs, number of bytes read by clients, number of bytes written by clients, number of RPCs with bad format, number of RPCs with bad authorization, number of RPCs from bad client, total number of handled network requests, number of handled network requests via TCP, number of handled network requests via UDP, number of handled TCP connections, number of hits on reply cache, number of misses on reply cache, and number of uncached requests. .TP 9 .B NET First one line is produced for the upper layers of the TCP/IP stack. .br Subsequent fields: the verb "upper", number of packets received by TCP, number of packets transmitted by TCP, number of packets received by UDP, number of packets transmitted by UDP, number of packets received by IP, number of packets transmitted by IP, number of packets delivered to higher layers by IP, and number of packets forwarded by IP. Next one line is shown for every interface. .br Subsequent fields: name of the interface, number of packets received by the interface, number of bytes received by the interface, number of packets transmitted by the interface, number of bytes transmitted by the interface, interface speed, and duplex mode (0=half, 1=full). .TP 9 .B IFB Subsequent fields: name of the InfiniBand interface, port number, number of lanes, maximum rate (Mbps), number of bytes received, number of bytes transmitted, number of packets received, and number of packets transmitted. .TP 9 .B PRG For every process one line is shown. .br Subsequent fields: PID (unique ID of task), name (between brackets), state, real uid, real gid, TGID (group number of related tasks/threads), total number of threads, exit code (in case of fatal signal: signal number + 256), start time (epoch), full command line (between brackets), PPID, number of threads in state 'running' (R), number of threads in state 'interruptible sleeping' (S), number of threads in state 'uninterruptible sleeping' (D), effective uid, effective gid, saved uid, saved gid, filesystem uid, filesystem gid, elapsed time (hertz), is_process (y/n), OpenVZ virtual pid (VPID), OpenVZ container id (CTID) and Docker container id (CID). .TP 9 .B PRC For every process one line is shown. .br Subsequent fields: PID, name (between brackets), state, total number of clock-ticks per second for this machine, CPU-consumption in user mode (clockticks), CPU-consumption in system mode (clockticks), nice value, priority, realtime priority, scheduling policy, current CPU, sleep average, TGID (group number of related tasks/threads) and is_process (y/n). .TP 9 .B PRE For every process one line is shown. .br Subsequent fields: PID, name (between brackets), process state, GPU state (A for active, E for exited, N for no GPU user), number of GPUs used by this process, bitlist reflecting used GPUs, GPU busy percentage during interval, memory busy percentage during interval, memory occupation (KiB) at this moment cumulative memory occupation (KiB) during interval, and number of samples taken during interval. .TP 9 .B PRM For every process one line is shown. .br Subsequent fields: PID, name (between brackets), state, page size for this machine (in bytes), virtual memory size (Kbytes), resident memory size (Kbytes), shared text memory size (Kbytes), virtual memory growth (Kbytes), resident memory growth (Kbytes), number of minor page faults, number of major page faults, virtual library exec size (Kbytes), virtual data size (Kbytes), virtual stack size (Kbytes), swap space used (Kbytes), TGID (group number of related tasks/threads), is_process (y/n) and proportional set size (Kbytes) if in 'R' option is specified. .TP 9 .B PRD For every process one line is shown. .br Subsequent fields: PID, name (between brackets), state, obsoleted kernel patch installed ('n'), standard io statistics used ('y' or 'n'), number of reads on disk, cumulative number of sectors read, number of writes on disk, cumulative number of sectors written, cancelled number of written sectors, TGID (group number of related tasks/threads) 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. .br Subsequent fields: PID, name (between brackets), state, kernel module 'netatop' loaded ('y' or 'n'), number of TCP-packets transmitted, cumulative size of TCP-packets transmitted, number of TCP-packets received, cumulative size of TCP-packets received, number of UDP-packets transmitted, cumulative size of UDP-packets transmitted, number of UDP-packets received, cumulative size of UDP-packets transmitted, number of raw packets transmitted (obsolete, always 0), number of raw packets received (obsolete, always 0), TGID (group number of related tasks/threads) and is_process (y/n). .br If the kernel module is not active, the network I/O counters per process are not relevant. .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 in an interactive session. .PP By sending the SIGUSR2 signal to .I atop a final sample will be forced after which .I atop will terminate. .SH EXAMPLES To monitor the current system load interactively with an interval of 5 seconds: .PP .TP 12 .B \ atop 5 .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 Store information about the system and process activity in binary compressed form to a file with an interval of ten minutes during an hour: .PP .TP 12 .B \ atop -w /tmp/atop.raw 600 6 .PP View the contents of this file interactively: .PP .B \ atop -r /tmp/atop.raw .PP View the processor and disk utilization of this file in parseable format: .PP .B \ atop -PCPU,DSK -r /tmp/atop.raw .PP View the contents of today's standard logfile interactively: .PP .B \ atop -r .PP View the contents of the standard logfile of the day before yesterday interactively: .PP .B \ atop -r yy .PP View the contents of the standard logfile of 2014, June 7 from 02:00 PM onwards interactively: .PP .B \ atop -r 20140607 -b 14:00 .PP .SH FILES .PP .TP 5 .B /var/run/pacct_shadow.d/ Directory containing the process accounting shadow files that are used by .I atop when the .I atopacctd daemon is active. .PP .TP 5 .B /var/cache/atop.d/atop.acct File in which the kernel writes the accounting records when .I atop itself has activated the process accounting mechanism. .PP .TP 5 .B /etc/atoprc Configuration file containing system-wide default values. See related man-page. .PP .TP 5 .B ~/.atoprc Configuration file containing personal default values. See related man-page. .PP .TP 5 .B /etc/default/atop Configuration file to overrule the settings of .I atop that runs in the background to create the daily logfile. This file is not created or overwritten when .I atop is installed, so it has to be created manually to override the default settings. The default settings are: .TP 8 \ .br LOGOPTS="-R" .br LOGINTERVAL=600 .br LOGGENERATIONS=28 .PP .TP 5 .BI /var/log/atop/atop_ YYYYMMDD Raw file, where .I YYYYMMDD are digits representing the current date. This name is used by the script .B atop.daily as default name for the output file, and by .B atop as default name for the input file when using the .B -r flag. .br All binary system and process level data in this file has been stored in compressed format. .PP .TP 5 .BI /var/run/netatop.log File that contains the netpertask structs containing the network counters of exited processes. These structs are written by the .I netatopd daemon and read by .I atop after reading the standard process accounting records. .SH SEE ALSO .B atopsar(1), .B atopconvert(1), .B atoprc(5), .B atopacctd(8), .B netatop(4), .B netatopd(8), .B atopgpud(8), .B logrotate(8) .br .B https://www.atoptool.nl .SH AUTHOR Gerlof Langeveld (gerlof.langeveld@atoptool.nl) .br JC van Winkel atop-2.4.0/man/atopconvert.10000664000203100020310000000207713416466037015203 0ustar gerlofgerlof.TH ATOPCONVERT 1 "January 2019" "Linux" .SH NAME .B atopconvert - convert raw log file to newer version .SH SYNOPSIS .P .B atopconvert [\-t .I version ] rawinput rawoutput .P .SH DESCRIPTION The program .I atopconvert can be used to convert the layout of a raw log file to a newer version. The only mandatory arguments are the name of the raw input file to be converted and the name of the raw output file. The program .I atopconvert verifies the version of the input file and converts it (by default) to the format used by the newest version of .I atop and writes to the output file. With the .B -t option, an alternative target version can be specified for the output file (instead of the newest version) in the format .I major.minor (example: 2.3). .br After the conversion is finished, the output file can be read by the newer version of .I atop or can even be extended by that .I atop version. .PP The raw input file should be at least of version 2.0! .SH SEE ALSO .B atop(1), .B atopsar(1) .br .B https://www.atoptool.nl .SH AUTHOR Gerlof Langeveld (gerlof.langeveld@atoptool.nl)