diff --git a/Makefile b/Makefile index a7200352..7d7a350e 100644 --- a/Makefile +++ b/Makefile @@ -28,12 +28,18 @@ OBJMOD3 = showgeneric.o showlinux.o showsys.o showprocs.o OBJMOD4 = atopsar.o netatopif.o gpucom.o ALLMODS = $(OBJMOD0) $(OBJMOD1) $(OBJMOD2) $(OBJMOD3) $(OBJMOD4) +ifneq ($(ATOP_BPF_SUPPORT),) + ALLMODS += photobpf.o + ATOP_BPF_LDFLAGS = -lbpf + CFLAGS += -DATOP_BPF_SUPPORT +endif + VERS = $(shell ./atop -V 2>/dev/null| sed -e 's/^[^ ]* //' -e 's/ .*//') all: atop atopsar atopacctd atopconvert atopcat atop: atop.o $(ALLMODS) Makefile - $(CC) atop.o $(ALLMODS) -o atop -lncursesw -lz -lm -lrt $(LDFLAGS) + $(CC) atop.o $(ALLMODS) -o atop -lncursesw -lz -lm -lrt $(ATOP_BPF_LDFLAGS) $(LDFLAGS) atopsar: atop ln -sf atop atopsar @@ -187,7 +193,7 @@ versdate.h: ./mkdate atop.o: atop.h photoproc.h photosyst.h acctproc.h showgeneric.h -atopsar.o: atop.h photoproc.h photosyst.h +atopsar.o: atop.h photoproc.h photosyst.h rawlog.o: atop.h photoproc.h photosyst.h rawlog.h showgeneric.h various.o: atop.h acctproc.h ifprop.o: atop.h photosyst.h ifprop.h @@ -200,7 +206,7 @@ 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 +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 diff --git a/atop.c b/atop.c index 8bac6723..3e1c4027 100644 --- a/atop.c +++ b/atop.c @@ -1,11 +1,11 @@ /* ** ATOP - System & Process Monitor ** -** The program 'atop' offers the possibility to view the activity of +** 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. +** 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 @@ -35,7 +35,7 @@ ** -------------------------------------------------------------------------- ** ** After initialization, the main-function calls the ENGINE. -** For every cycle (so after another interval) the ENGINE calls various +** For every cycle (so after another interval) the ENGINE calls various ** functions as shown below: ** ** +---------------------------------------------------------------------+ @@ -48,15 +48,15 @@ ** | | ^ | ^ | ^ | ^ | | | ** +---|-----|--------|-----|--------|----|--------|----|--------|----|--+ ** | | | | | | | | | | -** +--V-----|--+ +--V-----|--+ +--V----|--+ +--V----|--+ +--V----|-+ +** +--V-----|--+ +--V-----|--+ +--V----|--+ +--V----|--+ +--V----|-+ ** | | | | | | | | | | ** | photosyst | | photoproc | | acct | | deviate | | print | ** | | | | |photoproc | | ...syst | | | ** | | | | | | | ...proc | | | -** +-----------+ +-----------+ +----------+ +----------+ +---------+ +** +-----------+ +-----------+ +----------+ +----------+ +---------+ ** ^ ^ ^ ^ | ** | | | | | -** | | | V V +** | | | V V ** ______ _________ __________ ________ _________ ** / \ / \ / \ / \ / \ ** /proc /proc accounting task screen or @@ -84,8 +84,8 @@ ** 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). +** 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 @@ -98,7 +98,7 @@ ** 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 +** 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 @@ -112,7 +112,7 @@ ** 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. +** at runtime. ** ** $Log: atop.c,v $ ** Revision 1.49 2010/10/23 14:01:00 gerlof @@ -296,6 +296,7 @@ #include "showgeneric.h" #include "parseable.h" #include "gpucom.h" +#include "photobpf.h" #define allflags "ab:cde:fghijklmnopqrstuvwxyz1ABCDEFGHIJKL:MNOP:QRSTUVWXYZ" #define MAXFL 64 /* maximum number of command-line flags */ @@ -322,6 +323,16 @@ char threadview = 0; /* boolean: show individual threads */ char calcpss = 0; /* boolean: read/calculate process PSS */ char getwchan = 0; /* boolean: obtain wchan string */ +/* +** arguments for bpf stats sampling +** We enable bpf stats for bpfsampleinterval seconds every bpfsamplerate +** atop intervals. bpfsampleinterval must be smaller than atop interval. +** +** If bpfsamplerate == 0, disable sampling of bpf stats. +*/ +unsigned int bpfsamplerate = 1; +unsigned int bpfsampleinterval = 1; + unsigned short hertz; unsigned int pagesize; unsigned int nrgpus; @@ -391,6 +402,9 @@ void do_almostcrit(char *, char *); void do_atopsarflags(char *, char *); void do_pacctdir(char *, char *); void do_perfevents(char *, char *); +void do_bpflines(char *, char *); +void do_bpfsamplerate(char *, char *); +void do_bpfsampleinterval(char *, char *); static struct { char *tag; @@ -440,6 +454,9 @@ static struct { { "atopsarflags", do_atopsarflags, 0, }, { "perfevents", do_perfevents, 0, }, { "pacctdir", do_pacctdir, 1, }, + { "bpflines", do_bpflines, 0, }, + { "bpfsamplerate", do_bpfsamplerate, 0, }, + { "bpfsampleinterval", do_bpfsampleinterval, 0, }, }; /* @@ -466,6 +483,8 @@ main(int argc, char *argv[]) exit(42); } + photo_bpf_check(); + /* ** preserve command arguments to allow restart of other version */ @@ -497,12 +516,12 @@ main(int argc, char *argv[]) if ( memcmp(p, "atopsar", 7) == 0) return atopsar(argc, argv); - /* - ** interpret command-line arguments & flags + /* + ** interpret command-line arguments & flags */ if (argc > 1) { - /* + /* ** gather all flags for visualization-functions ** ** generic flags will be handled here; @@ -600,17 +619,17 @@ main(int argc, char *argv[]) } /* - ** get optional interval-value and optional number of samples + ** 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]) ) @@ -766,6 +785,7 @@ engine(void) gpupending=0; /* boolean: request sent */ struct gpupidstat *gp = NULL; + struct bstats *bstats = NULL; /* ** initialization: allocate required memory dynamically @@ -817,6 +837,8 @@ engine(void) if (nrgpus) supportflags |= GPUSTAT; + if (system_support_bpf()) + supportflags |= BPFSTAT; /* ** MAIN-LOOP: ** - Wait for the requested number of seconds or for other trigger @@ -838,11 +860,15 @@ engine(void) /* ** if the limit-flag is specified: ** check if the next sample is expected before midnight; - ** if not, stop atop now + ** if not, stop atop now */ if (midnightflag && (curtime+interval) > timelimit) break; + if ((supportflags & BPFSTAT) && + bpfsamplerate && sampcnt % bpfsamplerate == 0) + bstats = get_devbstats(); + /* ** wait for alarm-signal to arrive (except first sample) ** or wait for SIGUSR1/SIGUSR2 @@ -859,13 +885,13 @@ engine(void) curtime = time(0); /* seconds since 1-1-1970 */ /* - ** send request for statistics to atopgpud + ** send request for statistics to atopgpud */ if (nrgpus) gpupending = gpud_statrequest(); /* - ** take a snapshot of the current system-level statistics + ** take a snapshot of the current system-level statistics ** and calculate the deviations (i.e. calculate the activity ** during the last sample) */ @@ -918,7 +944,7 @@ engine(void) curtime-pretime > 0 ? curtime-pretime : 1); /* - ** take a snapshot of the current task-level statistics + ** take a snapshot of the current task-level statistics ** and calculate the deviations (i.e. calculate the activity ** during the last sample) ** @@ -1013,10 +1039,14 @@ engine(void) ** the deviations */ lastcmd = (vis.show_samp)( curtime, - curtime-pretime > 0 ? curtime-pretime : 1, - &devtstat, devsstat, - nprocexit, noverflow, sampcnt==0); + curtime-pretime > 0 ? curtime-pretime : 1, + &devtstat, devsstat, bstats, + nprocexit, noverflow, sampcnt==0); + if (bstats) { + free(bstats->bpfall); + bstats = NULL; + } /* ** release dynamically allocated memory */ @@ -1065,7 +1095,7 @@ prusage(char *myname) 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", + printf("\t -%c calculate proportional set size (PSS) per process\n", MCALCPSS); printf("\t -%c determine WCHAN (string) per thread\n", MGETWCHAN); printf("\t -P generate parseable output for specified label(s)\n"); @@ -1146,6 +1176,18 @@ do_linelength(char *name, char *val) linelen = get_posval(name, val); } +void +do_bpfsamplerate(char *name, char *val) +{ + bpfsamplerate = get_posval(name, val); +} + +void +do_bpfsampleinterval(char *name, char *val) +{ + bpfsampleinterval = get_posval(name, val); +} + /* ** read RC-file and modify defaults accordingly */ @@ -1196,7 +1238,7 @@ readrc(char *path, int syslevel) default: if (tagname[0] == '#') continue; - + if (tagvalue[0] != '#') break; diff --git a/atop.h b/atop.h index 65890d77..7443102c 100644 --- a/atop.h +++ b/atop.h @@ -42,8 +42,9 @@ struct tstat; struct devtstat; struct sstat; struct netpertask; +struct bstats; -/* +/* ** miscellaneous flags */ #define RRBOOT 0x0001 @@ -57,7 +58,7 @@ struct netpertask; struct visualize { char (*show_samp) (time_t, int, - struct devtstat *, struct sstat *, + struct devtstat *, struct sstat *, struct bstats *, int, unsigned int, char); void (*show_error) (const char *, ...); void (*show_end) (void); @@ -105,6 +106,9 @@ extern int netbadness; extern int pagbadness; extern int almostcrit; +extern int bpflines; +extern unsigned int bpfsampleinterval; + /* ** bit-values for supportflags */ @@ -114,9 +118,10 @@ extern int almostcrit; #define NETATOPD 0x00000020 #define DOCKSTAT 0x00000040 #define GPUSTAT 0x00000080 +#define BPFSTAT 0x00000100 /* -** in rawlog file, the four least significant bits +** 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 */ @@ -126,7 +131,7 @@ extern int almostcrit; ** structure containing the start-addresses of functions for visualization */ char generic_samp (time_t, int, - struct devtstat *, struct sstat *, + struct devtstat *, struct sstat *, struct bstats *, int, unsigned int, char); void generic_error(const char *, ...); void generic_end (void); @@ -168,7 +173,7 @@ int contcompar(const void *, const void *); count_t subcount(count_t, count_t); int rawread(void); char rawwrite (time_t, int, - struct devtstat *, struct sstat *, + struct devtstat *, struct sstat *, struct bstats *, int, unsigned int, char); int numeric(char *); diff --git a/atopsar.c b/atopsar.c index fcd3f059..c6349c93 100644 --- a/atopsar.c +++ b/atopsar.c @@ -1,7 +1,7 @@ /* ** ATOP - System & Process Monitor ** -** The program 'atop'/'atopsar' offers the possibility to view the activity of +** 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 @@ -81,7 +81,7 @@ static char *datemsg = "-------------------------- analysis " /* ** structure definition for print-functions */ -struct pridef { +struct pridef { char wanted; /* selected option (boolean) */ char *cntcat; /* used categories of counters */ char flag; /* flag on command line */ @@ -108,7 +108,7 @@ 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 *, + struct devtstat *, struct sstat *, struct bstats *, int, unsigned int, char); static void reportheader(struct utsname *, time_t); @@ -123,12 +123,12 @@ atopsar(int argc, char *argv[]) usecolors = 't'; - /* - ** interpret command-line arguments & flags + /* + ** interpret command-line arguments & flags */ if (argc > 1) { - /* + /* ** gather all flags for the print-functions */ flaglist = malloc(pricnt+32); @@ -226,7 +226,7 @@ atopsar(int argc, char *argv[]) default: /* gather report-flags */ for (i=0; i < pricnt; i++) { - if (pridef[i].flag == c && + if (pridef[i].flag == c && pridef[i].wanted == 0 ) { pridef[i].wanted = 1; @@ -244,7 +244,7 @@ atopsar(int argc, char *argv[]) /* ** get optional interval-value and - ** optional number of samples + ** optional number of samples */ if (optind < argc && optind < MAXFL) { @@ -253,11 +253,11 @@ atopsar(int argc, char *argv[]) if (!numeric(argv[optind])) pratopsaruse(argv[0]); - + interval = atoi(argv[optind]); - + optind++; - + if (optind < argc) { if (!numeric(argv[optind]) ) @@ -488,7 +488,7 @@ engine(void) gpustats = gpud_statrequest(); /* - ** take a snapshot of the current system-level statistics + ** take a snapshot of the current system-level statistics ** and calculate the deviations (i.e. calculate the activity ** during the last sample) */ @@ -589,9 +589,9 @@ reportlive(time_t curtime, int numsecs, struct sstat *ss) printf(COLSETHEAD); printf("%s ", convtime(curtime-numsecs, timebuf)); - + (pridef[i].prihead)(osvers, osrel, ossub); - + if (usecolors) printf(COLRESET); @@ -601,7 +601,7 @@ reportlive(time_t curtime, int numsecs, struct sstat *ss) ** 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, @@ -613,7 +613,7 @@ reportlive(time_t curtime, int numsecs, struct sstat *ss) ** do not call function again */ pridef[i].wanted = 0; - + if (--numreports == 0) cleanstop(1); } @@ -654,7 +654,7 @@ reportlive(time_t curtime, int numsecs, struct sstat *ss) printf(COLSETHEAD); printf("%s ", convtime(curtime, timebuf)); - + (pridef[i].prihead)(osvers, osrel, ossub); if (usecolors) @@ -672,10 +672,10 @@ reportlive(time_t curtime, int numsecs, struct sstat *ss) ** 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, + osvers, osrel, ossub, stampalways ? timebuf : " ", 0, 0, 0, 0, 0, 0) ) ) { @@ -701,7 +701,7 @@ reportlive(time_t curtime, int numsecs, struct sstat *ss) printf(COLSETHEAD); printf("%s ", convtime(curtime, timebuf)); - + (pridef[i].prihead)(osvers, osrel, ossub); if (usecolors) @@ -720,6 +720,7 @@ reportlive(time_t curtime, int numsecs, struct sstat *ss) static char reportraw(time_t curtime, int numsecs, struct devtstat *devtstat, struct sstat *sstat, + struct bstats *bstats, int nexit, unsigned int noverflow, char flags) { static char firstcall = 1; @@ -1191,7 +1192,7 @@ do_atopsarflags(char *name, char *val) default: /* gather report-flags */ for (j=0; j < pricnt; j++) { - if (pridef[j].flag == val[i] && + if (pridef[j].flag == val[i] && pridef[j].wanted == 0 ) { pridef[j].wanted = 1; @@ -1486,7 +1487,7 @@ memline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, if (membadness) mbadness = ((ss->mem.physmem - ss->mem.freemem - ss->mem.cachemem - ss->mem.buffermem) - * 100.0 / ss->mem.physmem) + * 100.0 / ss->mem.physmem) * 100 / membadness; else mbadness = 0; @@ -1818,7 +1819,7 @@ nfmline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, else state = ' '; - printf("%-38s %10.3lfK %10.3lfK %c\n", + printf("%-38s %10.3lfK %10.3lfK %c\n", pn, (double)ss->nfs.nfsmounts.nfsmnt[i].bytestotread / 1024 / deltasec, @@ -1943,7 +1944,7 @@ ibline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, preprint(badness); - printf("%-10s %4hd %4.0f%% %7.1lf %7.1lf %5lld %5lld %7lld %5d", + printf("%-10s %4hd %4.0f%% %7.1lf %7.1lf %5lld %5lld %7lld %5d", ss->ifb.ifb[i].ibname, ss->ifb.ifb[i].portnr, busy, @@ -2080,7 +2081,7 @@ ifline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, preprint(badness); printf("%-6s %4s %7.1lf %7.1lf %8.0lf %8.0lf " - "%5lld %5lld %7ld %c", + "%5lld %5lld %7ld %c", pn, busyval, (double)ss->intf.intf[i].rpack / deltasec, (double)ss->intf.intf[i].spack / deltasec, @@ -2140,7 +2141,7 @@ IFline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, pn = ss->intf.intf[i].name; printf("%-6s %6.2lf %6.2lf %6.2lf %7.2lf %7.2lf " - "%8.2lf %10.2lf\n", + "%8.2lf %10.2lf\n", pn, (double)ss->intf.intf[i].rerrs / deltasec, (double)ss->intf.intf[i].serrs / deltasec, @@ -2177,7 +2178,7 @@ ipv4line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, 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", + 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, @@ -2201,7 +2202,7 @@ IPv4line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, 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", + " %5.1lf %5.1lf\n", (double)ss->net.ipv4.InDiscards / deltasec, (double)ss->net.ipv4.InHdrErrors / deltasec, (double)ss->net.ipv4.InAddrErrors / deltasec, @@ -2229,12 +2230,12 @@ icmpv4line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, 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, + 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; } @@ -2253,7 +2254,7 @@ ICMPv4line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, 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", + "%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, @@ -2307,7 +2308,7 @@ ipv6line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, 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", + 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, @@ -2332,7 +2333,7 @@ IPv6line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, 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", + " %5.1lf %5.1lf\n", (double)ss->net.ipv6.Ip6InDiscards / deltasec, (double)ss->net.ipv6.Ip6InHdrErrors / deltasec, (double)ss->net.ipv6.Ip6InAddrErrors / deltasec, @@ -2360,13 +2361,13 @@ icmpv6line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, 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, + 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; @@ -2386,7 +2387,7 @@ ICMPv6line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, 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", + "%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, @@ -2487,7 +2488,7 @@ httpline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc, printf("%10.2lf %8.2lf %9.2lf %11d %11d\n", (double)ss->www.accesses / deltasec, (double)ss->www.totkbytes / deltasec, - ss->www.accesses ? + ss->www.accesses ? (double)ss->www.totkbytes*1024/ss->www.accesses : 0, ss->www.iworkers, ss->www.bworkers); diff --git a/parseable.c b/parseable.c index a3e1e26d..05626ebf 100644 --- a/parseable.c +++ b/parseable.c @@ -165,7 +165,7 @@ parsedef(char *pd) } /* - ** check list of comma-separated labels + ** check list of comma-separated labels */ while (pd < ep) { @@ -173,7 +173,7 @@ parsedef(char *pd) ** exchange comma by null-byte */ if ( (p = strchr(pd, ',')) ) - *p = 0; + *p = 0; else p = ep-1; @@ -223,7 +223,7 @@ parsedef(char *pd) */ char parseout(time_t curtime, int numsecs, - struct devtstat *devtstat, struct sstat *sstat, + struct devtstat *devtstat, struct sstat *sstat, struct bstats *bstats, int nexit, unsigned int noverflow, char flag) { register int i; @@ -274,15 +274,15 @@ parseout(time_t curtime, int numsecs, ** print functions for system-level statistics */ void -calc_freqscale(count_t maxfreq, count_t cnt, count_t ticks, +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) + if (maxfreq && ticks) { *freq=cnt/ticks; *freqperc=100* *freq / maxfreq; - } + } else if (maxfreq) // max frequency is known so % can be calculated { *freq=cnt; diff --git a/parseable.h b/parseable.h index 4d592cd7..5b4aba4b 100644 --- a/parseable.h +++ b/parseable.h @@ -1,4 +1,4 @@ int parsedef(char *); char parseout(time_t, int, - struct devtstat *, struct sstat *, + struct devtstat *, struct sstat *, struct bstats *, int, unsigned int, char); diff --git a/photobpf.c b/photobpf.c new file mode 100644 index 00000000..48791d14 --- /dev/null +++ b/photobpf.c @@ -0,0 +1,277 @@ +/* +** 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 bpf-porgram counters. +** ================================================================ +** Author: Song Liu +** E-mail: song@kernel.org +** Date: Dec 2019 +** +** 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 "atop.h" +#include "photobpf.h" +#include "showgeneric.h" + +#define BPF_STATS_MIN_ALLOC 8 + +/* +** check configurations: +** bpfsampleinterval < interval +*/ +void +photo_bpf_check(void) +{ + if (bpfsampleinterval >= interval) + mcleanstop(1, "bpfsampleinterval must be smaller than interval"); +} + +/* boolean */ +int +system_support_bpf(void) +{ + int bpf_stats_fd = bpf_enable_stats(BPF_STATS_RUN_TIME); + + /* check bpf_enable_stats() returns valid fd */ + if (bpf_stats_fd < 0) + return 0; + close(bpf_stats_fd); + return 1; +} + +/* +** Get a snapshot of all bpf program stats +*/ +static struct bstats * +get_allbstats(void) +{ + int err; + __u32 id = 0; + unsigned int bufsize = 0; + struct bstats *curbstats = malloc(sizeof(struct bstats)); + + ptrverify(curbstats, "Malloc failed for bstats\n"); + + memset(curbstats, 0, sizeof(struct bstats)); + + while (true) { + int fd; + struct bpf_prog_info info = {}; + __u32 len = sizeof(struct bpf_prog_info); + struct bstat *bstat; + + err = bpf_prog_get_next_id(id, &id); + if (err) + break; + if (curbstats->nbpfall >= bufsize) { + bufsize += BPF_STATS_MIN_ALLOC; + curbstats->bpfall = realloc( + curbstats->bpfall, + bufsize * sizeof(struct bstat)); + ptrverify(curbstats->bpfall, + "Malloc failed for %u bstats\n", + bufsize); + } + + fd = bpf_prog_get_fd_by_id(id); + if (fd < 0) { + if (errno == ENOENT) + continue; + break; + } + + err = bpf_obj_get_info_by_fd(fd, &info, &len); + close(fd); + if (err) + break; + + bstat = curbstats->bpfall + curbstats->nbpfall; + + bstat->type = info.type; + bstat->id = info.id; + memcpy(bstat->name, info.name, BPF_OBJ_NAME_LEN); + bstat->run_time_ns = info.run_time_ns; + bstat->run_cnt = info.run_cnt; + + curbstats->nbpfall++; + } + + return curbstats; +} + +static int +bstatcompar(const void *a, const void *b) +{ + struct bstat *sa = (struct bstat *)a; + struct bstat *sb = (struct bstat *)b; + + if (sa->run_time_ns < sb->run_time_ns) + return 1; + if (sa->run_time_ns > sb->run_time_ns) + return -1; + + return 0; +} + +/* +** return deviate bpf program stats, sorted by run_time_ns. +** programs with zero run_time_ns are ingored. +*/ +struct bstats * +get_devbstats(void) +{ + int i, j; + struct bstats *prebstats; + struct bstats *curbstats; + int bpf_stats_fd; + + if (!(supportflags & BPFSTAT)) { + printf("NO support bpf\n"); + return NULL; + } + + /* bpf_enable_stats() enables stats and returns a valid fd */ + bpf_stats_fd = bpf_enable_stats(BPF_STATS_RUN_TIME); + + if (bpf_stats_fd < 0) { + supportflags &= ~BPFSTAT; + return NULL; + } + + prebstats = get_allbstats(); + sleep(bpfsampleinterval); + /* close the fd to disable stats */ + close(bpf_stats_fd); + curbstats = get_allbstats(); + + /* + ** deviate, save result in curbstats + */ + i = 0; + j = 0; + while (i < prebstats->nbpfall && j < curbstats->nbpfall) { + struct bstat *prebstat = prebstats->bpfall + i; + struct bstat *curbstat = curbstats->bpfall + j; + + if (prebstat->id < curbstat->id) { + i++; + } else if (prebstat->id > curbstat->id) { + j++; + } else { + curbstat->run_cnt -= prebstat->run_cnt; + curbstat->run_time_ns -= prebstat->run_time_ns; + i++; + j++; + } + } + + free(prebstats->bpfall); + + /* + ** sort result based on run_time_ns + */ + qsort(curbstats->bpfall, curbstats->nbpfall, + sizeof(curbstats->bpfall[0]), + bstatcompar); + + /* + ** drop stats with zero run time + */ + for (i = 0; i < curbstats->nbpfall; i++) + if (curbstats->bpfall[i].run_time_ns == 0) { + curbstats->bpfall = realloc(curbstats->bpfall, + i * sizeof(struct bstat)); + curbstats->nbpfall = i; + break; + } + + return curbstats; +} + +/* +** Print bpf stats. +** For less than 76 columns, skip. +** For 76 or more columens, show +** BPF_PROG_ID 11 bytes +** NAME 17+ bytes +** TOTAL_TIME_NS 15 bytes +** RUN_CNT 13 bytes +** CPU % 8 bytes +** AVG_TIME_NS 12 bytes +*/ +int +pribpf(struct bstats *devbstat, int curline) +{ + int i; + int maxw = screen ? COLS : linelen; + int namewidth = maxw - 59; + + if ((supportflags & BPFSTAT) == 0 || maxw < 76 || !devbstat) + return curline; + + curline += 1; + if (screen) { + move(curline, 0); + attron(A_REVERSE); + } else { + printg("\n\n"); + } + printg("%11s%*s%15s%13s%8s%12s", "BPF_PROG_ID", namewidth, "NAME", "TOTAL_TIME_NS", + "RUN_CNT", "CPU", "AVG_TIME_NS"); + + if (screen) + attroff(A_REVERSE); + else + printg("\n"); + + for (i = 0; i < devbstat->nbpfall; i++) { + float avgtime; + struct bstat *bstat = devbstat->bpfall + i; + + /* + ** show at most bpflines on screen + */ + if ((screen && i >= bpflines)) + break; + + curline += 1; + if (screen) + move(curline, 0); + else + printg("\n"); + + avgtime = (bstat->run_cnt == 0) ? 0.0 : + (float)(bstat->run_time_ns) / bstat->run_cnt; + + printg("%11d%*s%15llu%13llu%7llu%%%12.2f", bstat->id, namewidth, + bstat->name, bstat->run_time_ns, bstat->run_cnt, + bstat->run_time_ns / bpfsampleinterval / 10000000ULL, + avgtime); + } + + return curline; +} diff --git a/photobpf.h b/photobpf.h new file mode 100644 index 00000000..f4100d87 --- /dev/null +++ b/photobpf.h @@ -0,0 +1,75 @@ +/* +** 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 bpf-porgram-level counters maintained and +** functions to access the bpf-program-database. +** ================================================================ +** Author: Song Liu +** E-mail: song@kernel.org +** Date: Dec 2019 +** +** 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 + +/* +** structure containing information about a bpf program +*/ +struct bstat { + __u32 type; + __u32 id; + char name[BPF_OBJ_NAME_LEN]; + __u64 run_time_ns; + __u64 run_cnt; +} __attribute__((aligned(8))); + +/* +** structure containing information about all bpf programs, or a deviate of +** two snapshots. +*/ +struct bstats { + struct bstat *bpfall; + + unsigned int nbpfall; +}; + +#ifdef ATOP_BPF_SUPPORT +void photo_bpf_check(); +int system_support_bpf(void); + +struct bstats *get_devbstats(void); +int pribpf(struct bstats *devbstat, int curline); +#else +static inline void +photo_bpf_check(void) {} + +static inline int +system_support_bpf(void) +{ + return 0; +} + +static inline struct bstats * +get_devbstats(void) +{ + return NULL; +} + +static inline int +pribpf(struct bstats *devbstat, int curline) +{ + return curline; +} + +#endif diff --git a/rawlog.c b/rawlog.c index d2cb7d1e..05c1215d 100644 --- a/rawlog.c +++ b/rawlog.c @@ -1,7 +1,7 @@ /* ** ATOP - System & Process Monitor ** -** The program 'atop' offers the possibility to view the activity of +** The program 'atop' offers the possibility to view the activity of ** the system on system-level as well as process-level. ** ========================================================================== ** Author: Gerlof Langeveld @@ -52,12 +52,14 @@ #include "photoproc.h" #include "photosyst.h" #include "rawlog.h" +#include "photobpf.h" -#define BASEPATH "/var/log/atop" +#define BASEPATH "/var/log/atop" static int getrawrec (int, struct rawrecord *, int); static int getrawsstat(int, struct sstat *, int); static int getrawtstat(int, struct tstat *, int, int); +static int getrawbstat(int, struct bstat *, int, int); static int rawwopen(void); static int readchunk(int, void *, int); static int lookslikedatetome(char *); @@ -69,8 +71,8 @@ static void try_other_version(int, int); ** (file is opened/created during the first call) */ char -rawwrite(time_t curtime, int numsecs, - struct devtstat *devtstat, struct sstat *sstat, +rawwrite(time_t curtime, int numsecs, + struct devtstat *devtstat, struct sstat *sstat, struct bstats *bstats, int nexit, unsigned int noverflow, char flag) { static int rawfd = -1; @@ -79,10 +81,17 @@ rawwrite(time_t curtime, int numsecs, struct stat filestat; Byte scompbuf[sizeof(struct sstat)], *pcompbuf; + Byte *bcompbuf; unsigned long scomplen = sizeof scompbuf; unsigned long pcomplen = sizeof(struct tstat) * devtstat->ntaskall; - struct iovec iov[3]; + unsigned long bcomplen; + struct iovec iov[4]; + struct bstats dummybstats = {NULL, 0}; + + if (bstats == NULL) + bstats = &dummybstats; + bcomplen = sizeof(struct bstat) * bstats->nbpfall; /* ** first call: @@ -115,6 +124,17 @@ rawwrite(time_t curtime, int numsecs, testcompval(rv, "compress"); + bcompbuf = malloc(bcomplen); + + ptrverify(bcompbuf, "Malloc failed for compression buffer\n"); + + if (bcomplen) { + rv = compress(bcompbuf, &bcomplen, (Byte *)bstats->bpfall, + (unsigned long)bcomplen); + + testcompval(rv, "compress"); + } + /* ** fill record header and write to file */ @@ -135,6 +155,8 @@ rawwrite(time_t curtime, int numsecs, rr.totzomb = devtstat->totzombie; rr.scomplen = scomplen; rr.pcomplen = pcomplen; + rr.bcomplen = bcomplen; + rr.totbpf = bstats->nbpfall; if (flag&RRBOOT) rr.flags |= RRBOOT; @@ -170,7 +192,10 @@ rawwrite(time_t curtime, int numsecs, iov[2].iov_base = pcompbuf; iov[2].iov_len = pcomplen; - if ( writev(rawfd, iov, 3) == -1) + iov[3].iov_base = bcompbuf; + iov[3].iov_len = bcomplen; + + if ( writev(rawfd, iov, 4) == -1) { fprintf(stderr, "%s - ", rawname); if ( ftruncate(rawfd, filestat.st_size) == -1) @@ -184,6 +209,7 @@ rawwrite(time_t curtime, int numsecs, } free(pcompbuf); + free(bcompbuf); return '\0'; } @@ -225,6 +251,7 @@ rawwopen() if ( rh.sstatlen != sizeof(struct sstat) || rh.tstatlen != sizeof(struct tstat) || + rh.bstatlen != sizeof(struct bstat) || rh.rawheadlen != sizeof(struct rawheader) || rh.rawreclen != sizeof(struct rawrecord) ) { @@ -268,6 +295,7 @@ rawwopen() rh.aversion = getnumvers() | 0x8000; rh.sstatlen = sizeof(struct sstat); rh.tstatlen = sizeof(struct tstat); + rh.bstatlen = sizeof(struct bstat); rh.rawheadlen = sizeof(struct rawheader); rh.rawreclen = sizeof(struct rawrecord); rh.supportflags = supportflags | RAWLOGNG; @@ -303,6 +331,7 @@ rawread(void) struct rawrecord rr; struct sstat sstat; static struct devtstat devtstat; + struct bstats bstats = {NULL, 0}; struct stat filestat; @@ -328,7 +357,7 @@ rawread(void) tp = localtime(&timenow); snprintf(rawname, RAWNAMESZ, "%s/atop_%04d%02d%02d", - BASEPATH, + BASEPATH, tp->tm_year+1900, tp->tm_mon+1, tp->tm_mday); @@ -340,7 +369,7 @@ rawread(void) ** the full pathname of the raw file */ case 8: - if ( access(rawname, F_OK) == 0) + if ( access(rawname, F_OK) == 0) break; /* existing file */ if (lookslikedatetome(rawname)) @@ -350,7 +379,7 @@ rawread(void) strncpy(savedname, rawname, RAWNAMESZ-1); snprintf(rawname, RAWNAMESZ, "%s/atop_%s", - BASEPATH, + BASEPATH, savedname); break; } @@ -362,7 +391,7 @@ rawread(void) ** of y's). */ default: - if ( access(rawname, F_OK) == 0) + if ( access(rawname, F_OK) == 0) break; /* existing file */ /* @@ -382,7 +411,7 @@ rawread(void) tp = localtime(&timenow); snprintf(rawname, RAWNAMESZ, "%s/atop_%04d%02d%02d", - BASEPATH, + BASEPATH, tp->tm_year+1900, tp->tm_mon+1, tp->tm_mday); @@ -479,6 +508,7 @@ rawread(void) */ if (rh.sstatlen != sizeof(struct sstat) || rh.tstatlen != sizeof(struct tstat) || + rh.bstatlen != sizeof(struct bstat) || rh.rawheadlen != sizeof(struct rawheader) || rh.rawreclen != sizeof(struct rawrecord) ) { @@ -591,7 +621,7 @@ rawread(void) offsize+= OFFCHUNK; } } - + /* ** check if this sample is within the time-range ** specified with the -b and -e flags (if any) @@ -599,7 +629,7 @@ rawread(void) if ( (begintime > cursortime) ) { lastcmd = 1; - + if (isregular) { static off_t curr_pos = -1; @@ -721,6 +751,21 @@ rawread(void) devtstat.totslpu = rr.totslpu; devtstat.totzombie = rr.totzomb; + bstats.nbpfall = rr.totbpf; + + if (rr.totbpf) { + bstats.bpfall = malloc( + sizeof(struct bstat) * rr.totbpf); + + ptrverify(bstats.bpfall, + "Malloc failed for %d stored bpf stats\n", + rr.totbpf); + + if ( !getrawbstat(rawfd, bstats.bpfall, + rr.bcomplen, rr.totbpf) ) + cleanstop(7); + } + /* ** activate the installed print-function to visualize ** the system- and process-level statistics @@ -778,7 +823,7 @@ rawread(void) { lastcmd = (vis.show_samp)(rr.curtime, rr.interval, - &devtstat, &sstat, + &devtstat, &sstat, &bstats, rr.nexit, rr.noverflow, flags); } while (!isregular && @@ -790,6 +835,9 @@ rawread(void) free(devtstat.taskall); free(devtstat.procall); free(devtstat.procactive); + free(bstats.bpfall); + bstats.bpfall = NULL; + bstats.nbpfall = 0; switch (lastcmd) { @@ -878,7 +926,7 @@ getrawsstat(int rawfd, struct sstat *sp, int complen) } /* -** read the process-level statistics from the current offset +** read the bpf statistics from the current offset */ static int getrawtstat(int rawfd, struct tstat *pp, int complen, int ndeviat) @@ -906,7 +954,36 @@ getrawtstat(int rawfd, struct tstat *pp, int complen, int ndeviat) return 1; } -/* +/* +** read the process-level statistics from the current offset +*/ +static int +getrawbstat(int rawfd, struct bstat *bp, int complen, int nbpfall) +{ + Byte *compbuf; + unsigned long uncomplen = sizeof(struct bstat) * nbpfall; + int rv; + + compbuf = malloc(complen); + + ptrverify(compbuf, "Malloc failed for reading compressed procstats\n"); + + if ( readchunk(rawfd, compbuf, complen) < complen) + { + free(compbuf); + return 0; + } + + rv = uncompress((Byte *)bp, &uncomplen, compbuf, complen); + + testcompval(rv, "uncompress"); + + free(compbuf); + + return 1; +} + +/* ** verify if a particular ascii-string is in the format yyyymmdd */ static int diff --git a/rawlog.h b/rawlog.h index 951736d5..07b39847 100644 --- a/rawlog.h +++ b/rawlog.h @@ -30,7 +30,8 @@ struct rawheader { 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 bstatlen; /* length of struct bstat */ + char cfuture[4]; /* future use */ unsigned int pagesize; /* size of memory page (bytes) */ int supportflags; /* used features */ @@ -59,5 +60,7 @@ struct rawrecord { 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 */ + unsigned int bcomplen; /* length of compressed bstat's */ + unsigned int totbpf; /* number of bstat's */ + unsigned int ifuture[4]; /* future use */ }; diff --git a/showgeneric.c b/showgeneric.c index a0800f6e..7404d4ba 100644 --- a/showgeneric.c +++ b/showgeneric.c @@ -1,9 +1,9 @@ /* -** ATOP - System & Process Monitor +** 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. ** ========================================================================== @@ -28,7 +28,7 @@ ** 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 @@ -277,6 +277,7 @@ #include "atop.h" #include "photoproc.h" #include "photosyst.h" +#include "photobpf.h" #include "showgeneric.h" #include "showlinux.h" @@ -321,11 +322,11 @@ 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, + [MSORTCPU&0x1f]=compcpu, + [MSORTMEM&0x1f]=compmem, + [MSORTDSK&0x1f]=compdsk, + [MSORTNET&0x1f]=compnet, + [MSORTGPU&0x1f]=compgpu, }; extern proc_printpair ownprocs[]; @@ -335,12 +336,15 @@ extern proc_printpair ownprocs[]; */ int startoffset; +int bpflines = 3; + /* ** print the deviation-counters on process- and system-level */ char generic_samp(time_t curtime, int nsecs, - struct devtstat *devtstat, struct sstat *sstat, + struct devtstat *devtstat, struct sstat *sstat, + struct bstats *bstats, int nexit, unsigned int noverflow, char flag) { static int callnr = 0; @@ -370,7 +374,7 @@ generic_samp(time_t curtime, int nsecs, ** 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 */ @@ -416,6 +420,11 @@ generic_samp(time_t curtime, int nsecs, char threadallowed = 0; + /* + ** reserve 2 lines for proc and bpflines+1 lines for bpf programs + */ + int proc_bpf_lines = + (bstats && bstats->nbpfall) ? bpflines + 1 : 2; if (callnr == 0) /* first call? */ generic_init(); @@ -425,7 +434,7 @@ generic_samp(time_t curtime, int nsecs, startoffset = 0; /* - ** compute the total capacity of this system for the + ** compute the total capacity of this system for the ** four main resources */ totalcap(&syscap, sstat, devtstat->procactive, devtstat->nprocactive); @@ -508,11 +517,11 @@ generic_samp(time_t curtime, int nsecs, int lenavail = (screen ? COLS : linelen) - 50 - seclen - utsnodenamelen; int len1 = lenavail / 3; - int len2 = lenavail - len1 - len1; + 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%c%" - "*s%s elapsed", - utsname.nodename, len1, "", + "*s%s elapsed", + utsname.nodename, len1, "", format1, format2, len1, "", threadview ? MTHREAD : '-', fixedhead ? MSYSFIXED : '-', @@ -545,7 +554,7 @@ generic_samp(time_t curtime, int nsecs, if (noverflow) { - snprintf(statbuf, sizeof statbuf, + snprintf(statbuf, sizeof statbuf, "Only %d exited processes handled " "-- %u skipped!", nexit, noverflow); @@ -574,7 +583,7 @@ generic_samp(time_t curtime, int nsecs, ** limit the number of variable resource lines ** and try again */ - if (screen && curline+2 > LINES) + if (screen && curline+proc_bpf_lines > LINES) { curline = 2; @@ -583,7 +592,7 @@ generic_samp(time_t curtime, int nsecs, move(curline, 0); limitedlines(); - + curline = prisyst(sstat, curline, nsecs, avgval, fixedhead, &syssel, &autoorder, maxcpulines, maxgpulines, @@ -596,7 +605,7 @@ generic_samp(time_t curtime, int nsecs, ** if system-wide statistics still do not fit, ** the window is really to small */ - if (curline+2 > LINES) + if (curline+proc_bpf_lines > LINES) { endwin(); // finish curses interface @@ -668,6 +677,10 @@ generic_samp(time_t curtime, int nsecs, } } + if (screen) + move(curline, 0); + curline = pribpf(bstats, curline); + /* ** select the required list with tasks to be shown ** @@ -747,7 +760,7 @@ generic_samp(time_t curtime, int nsecs, "Malloc failed for %d pcum ptrs\n", nproc); for (i=0; i < nproc; i++) - { + { /* fill pointers */ pcumlist[i] = tpcumlist+i; } @@ -852,7 +865,7 @@ generic_samp(time_t curtime, int nsecs, suppressexit ) continue; - sellist[nsel++] = curlist[i]; + sellist[nsel++] = curlist[i]; } curlist = sellist; @@ -863,7 +876,7 @@ generic_samp(time_t curtime, int nsecs, } /* - ** sort the list in required order + ** sort the list in required order ** (default CPU-consumption) and print the list */ if (showorder == MSORTAUTO) @@ -949,7 +962,7 @@ generic_samp(time_t curtime, int nsecs, for (t = pcur - tall + 1; t < devtstat->ntaskall && pcur->gen.tgid && - pcur->gen.tgid == + pcur->gen.tgid == (tall+t)->gen.tgid; t++) { @@ -1046,7 +1059,7 @@ generic_samp(time_t curtime, int nsecs, if (tsklist) free(tsklist); if (sellist) free(sellist); - return lastchar; + return lastchar; /* ** stop it @@ -1983,7 +1996,7 @@ generic_samp(time_t curtime, int nsecs, break; /* - ** per-process PSS calculation wanted + ** per-process PSS calculation wanted */ case MCALCPSS: if (calcpss) @@ -1999,7 +2012,7 @@ generic_samp(time_t curtime, int nsecs, break; /* - ** per-thread WCHAN definition + ** per-thread WCHAN definition */ case MGETWCHAN: if (getwchan) @@ -2126,7 +2139,7 @@ generic_samp(time_t curtime, int nsecs, break; /* - ** reset statistics + ** reset statistics */ case MRESET: getalarm(0); /* restart the clock */ @@ -2183,7 +2196,7 @@ generic_samp(time_t curtime, int nsecs, /* ** handle arrow up to go one line up */ - case KEY_UP: + case KEY_UP: if (firstproc > 0) firstproc -= 1; break; @@ -2212,7 +2225,7 @@ generic_samp(time_t curtime, int nsecs, ** handle screen resize */ case KEY_RESIZE: - snprintf(statbuf, sizeof statbuf, + snprintf(statbuf, sizeof statbuf, "Window resized to %dx%d...", COLS, LINES); statmsg = statbuf; @@ -2268,7 +2281,7 @@ cumusers(struct tstat **curprocs, struct tstat *curusers, int numprocs) if ((*curprocs)->gen.state == 'E' && suppressexit) continue; - + if ( curusers->gen.ruid != (*curprocs)->gen.ruid ) { if (curusers->gen.pid) @@ -2356,7 +2369,7 @@ cumconts(struct tstat **curprocs, struct tstat *curconts, int numprocs) if ((*curprocs)->gen.state == 'E' && suppressexit) continue; - + if ( strcmp(curconts->gen.container, (*curprocs)->gen.container) != 0) { @@ -2593,7 +2606,7 @@ limitedlines(void) } /* -** get a numerical value from the user and verify +** get a numerical value from the user and verify */ static long getnumval(char *ask, long valuenow, int statline) @@ -3022,7 +3035,7 @@ showhelp(int helpline) scrollok(helpwin, 1); /* - ** show help-lines + ** show help-lines */ for (i=0, shown=0; i < helplines; i++, shown++) { @@ -3035,7 +3048,7 @@ showhelp(int helpline) { wmove (helpwin, winlines-1, 0); wclrtoeol(helpwin); - wprintw (helpwin, "Press 'q' to leave help, " + wprintw (helpwin, "Press 'q' to leave help, " "space for next page or " "other key for next line... "); @@ -3283,6 +3296,12 @@ do_maxcont(char *name, char *val) maxcontlines = get_posval(name, val); } +void +do_bpflines(char *name, char *val) +{ + bpflines = get_posval(name, val); +} + struct colmap { char *colname; diff --git a/various.c b/various.c index 3d5f1b84..3fa8e558 100644 --- a/various.c +++ b/various.c @@ -5,7 +5,7 @@ ** 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. +** time-of-day, the cpu-time consumption and the memory-occupation. ** ========================================================================== ** Author: Gerlof Langeveld ** E-mail: gerlof.langeveld@atoptool.nl @@ -115,6 +115,7 @@ #include "atop.h" #include "acctproc.h" +#include "photobpf.h" /* ** Function convtime() converts a value (number of seconds since @@ -193,7 +194,7 @@ getbranchtime(char *itim, time_t *newtime) tm.tm_mon -= 1; if (tm.tm_year < 100 || tm.tm_mon < 0 || tm.tm_mon > 11 || - tm.tm_mday < 1 || tm.tm_mday > 31 || + tm.tm_mday < 1 || tm.tm_mday > 31 || tm.tm_hour < 0 || tm.tm_hour > 23 || tm.tm_min < 0 || tm.tm_min > 59 ) { @@ -250,7 +251,7 @@ getbranchtime(char *itim, time_t *newtime) /* ** Normalize an epoch time with the number of seconds within a day -** Return-value: Normalized epoch +** Return-value: Normalized epoch */ time_t normalize_epoch(time_t epoch, long secondsinday) @@ -259,9 +260,9 @@ normalize_epoch(time_t epoch, long secondsinday) localtime_r(&epoch, &tm); // convert epoch to tm - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = secondsinday; + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = secondsinday; tm.tm_isdst = -1; return mktime(&tm); // convert tm to epoch @@ -269,7 +270,7 @@ normalize_epoch(time_t epoch, long secondsinday) /* -** Function val2valstr() converts a positive value to an ascii-string of a +** 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. @@ -352,17 +353,17 @@ val2elapstr(int value, char *strvalue) { char *p=strvalue; - if (value >= DAYSECS) + if (value >= DAYSECS) { p+=sprintf(p, "%dd", value/DAYSECS); } - if (value >= HOURSECS) + if (value >= HOURSECS) { p+=sprintf(p, "%dh", (value%DAYSECS)/HOURSECS); } - if (value >= MINSECS) + if (value >= MINSECS) { p+=sprintf(p, "%dm", (value%HOURSECS)/MINSECS); } @@ -396,7 +397,7 @@ val2cpustr(count_t value, char *strvalue) */ value = (value + 500) / 1000; - if (value < MAXSEC) + if (value < MAXSEC) { sprintf(strvalue, "%2lldm%02llds", value/60, value%60); } @@ -407,7 +408,7 @@ val2cpustr(count_t value, char *strvalue) */ value = (value + 30) / 60; - if (value < MAXMIN) + if (value < MAXMIN) { sprintf(strvalue, "%2lldh%02lldm", value/60, value%60); @@ -429,7 +430,7 @@ val2cpustr(count_t value, char *strvalue) } /* -** Function val2Hzstr() converts a value (in MHz) +** 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. @@ -450,7 +451,7 @@ val2Hzstr(count_t value, char *strvalue) if (fval >= 1000.0) // prepare for the future { - prefix='T'; + prefix='T'; fval /= 1000.0; } @@ -520,7 +521,7 @@ val2memstr(count_t value, char *strvalue, int pformat, int avgval, int nsecs) basewidth -= 2; suffix = "/s"; } - + /* ** determine which format will be used on bases of the value itself */ @@ -561,7 +562,7 @@ val2memstr(count_t value, char *strvalue, int pformat, int avgval, int nsecs) case MBFORMAT: sprintf(strvalue, "%*.1lfM%s", - basewidth-1, (double)((double)value/ONEMBYTE), suffix); + basewidth-1, (double)((double)value/ONEMBYTE), suffix); break; case GBFORMAT: @@ -588,7 +589,7 @@ val2memstr(count_t value, char *strvalue, int pformat, int avgval, int nsecs) /* -** Function numeric() checks if the ascii-string contains +** Function numeric() checks if the ascii-string contains ** a numeric (positive) value. ** Returns 1 (true) if so, or 0 (false). */ @@ -607,7 +608,7 @@ numeric(char *ns) /* -** Function getboot() returns the boot-time of this system +** Function getboot() returns the boot-time of this system ** as number of jiffies since 1-1-1970. */ unsigned long long