"Fossies" - the Fresh Open Source Software Archive

Member "atop-2.8.1/atopsar.c" (7 Jan 2023, 74150 Bytes) of package /linux/misc/atop-2.8.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "atopsar.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.7.1_vs_2.8.0.

    1 /*
    2 ** ATOP - System & Process Monitor
    3 **
    4 ** The program 'atop'/'atopsar' offers the possibility to view the activity of 
    5 ** the system on system-level as well as process-level.
    6 **
    7 ** This source-file contains the 'atopsar'-functionality, that makes use
    8 ** of the 'atop'-framework.
    9 ** ==========================================================================
   10 ** Author:      Gerlof Langeveld
   11 ** E-mail:      gerlof.langeveld@atoptool.nl
   12 ** Initial:     July 2007
   13 ** --------------------------------------------------------------------------
   14 ** Copyright (C) 2007-2010 Gerlof Langeveld
   15 **
   16 ** This program is free software; you can redistribute it and/or modify it
   17 ** under the terms of the GNU General Public License as published by the
   18 ** Free Software Foundation; either version 2, or (at your option) any
   19 ** later version.
   20 **
   21 ** This program is distributed in the hope that it will be useful, but
   22 ** WITHOUT ANY WARRANTY; without even the implied warranty of
   23 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   24 ** See the GNU General Public License for more details.
   25 **
   26 ** You should have received a copy of the GNU General Public License
   27 ** along with this program; if not, write to the Free Software
   28 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   29 ** --------------------------------------------------------------------------
   30 */
   31 
   32 #include <sys/types.h>
   33 #include <sys/param.h>
   34 #include <sys/mman.h>
   35 #include <sys/stat.h>
   36 #include <time.h>
   37 #include <stdio.h>
   38 #include <errno.h>
   39 #include <fcntl.h>
   40 #include <unistd.h>
   41 #include <stdlib.h>
   42 #include <signal.h>
   43 #include <sys/utsname.h>
   44 #include <string.h>
   45 #include <sys/time.h>
   46 #include <sys/resource.h>
   47 #include <regex.h>
   48 #include <sys/ioctl.h>
   49 
   50 #include "atop.h"
   51 #include "ifprop.h"
   52 #include "photosyst.h"
   53 #include "photoproc.h"
   54 #include "gpucom.h"
   55 
   56 #define MAXFL   64      /* maximum number of command-line flags  */
   57 
   58 
   59 /*
   60 ** color definitions
   61 */
   62 #define COLSETHEAD  "\033[30;43m"   /* black on yellow  */
   63 #define COLSETMED   "\033[36m"  /* cyan         */
   64 #define COLSETHIGH      "\033[31m"  /* red          */
   65 #define COLRESET        "\033[00m"  /* reset any color  */
   66 
   67 /*
   68 ** miscellaneous values
   69 */
   70 static unsigned int     nsamples = 9999999;
   71 static char     stampalways;
   72 static char     usemarkers;
   73 static char     allresources;
   74 static int      numreports;
   75 static time_t       saved_begintime;
   76 static unsigned int repeathead = 9999999;
   77 static unsigned int summarycnt = 1;
   78 static char     *datemsg = "-------------------------- analysis "
   79                        "date: %s --------------------------\n";
   80 
   81 /*
   82 ** structure definition for print-functions
   83 */
   84 struct pridef { 
   85     char    wanted;         /* selected option (boolean)              */
   86     char    *cntcat;        /* used categories of counters            */
   87     char    flag;           /* flag on command line                   */
   88     void    (*prihead)();   /* print header of list                   */
   89     int     (*priline)(struct sstat *, struct tstat *, struct tstat **,
   90                    int, time_t, time_t, time_t,
   91                    int, int, int, char *,
   92                        int, int, int, int, int, int);
   93                         /* print counters per line (excl. time)   */
   94     char    *about;         /* statistics about what                  */
   95 };
   96 
   97 extern struct pridef    pridef[];      /* table of print-functions        */
   98 extern int      pricnt;        /* total number of print-functions */
   99 
  100 static time_t       daylim;        /* last second of day in epoch     */
  101 static int      prinow;        /* current selection               */
  102 static char         coloron;       /* boolean: colors active now      */
  103 
  104 /*
  105 ** local prototypes
  106 */
  107 static void engine(void);
  108 static void pratopsaruse(char *);
  109 static void reportlive(time_t, int, struct sstat *);
  110 static char     reportraw (time_t, int,
  111                             struct devtstat *, struct sstat *,
  112                             int, unsigned int, char);
  113 
  114 static void reportheader(struct utsname *, time_t);
  115 static time_t   daylimit(time_t);
  116 
  117 int
  118 atopsar(int argc, char *argv[])
  119 {
  120     register int    i, c;
  121     struct rlimit   rlim;
  122     char        *p, *flaglist;
  123 
  124     usecolors = 't';
  125 
  126     /* 
  127     ** interpret command-line arguments & flags 
  128     */
  129     if (argc > 1)
  130     {
  131         /* 
  132         ** gather all flags for the print-functions
  133         */
  134         flaglist = malloc(pricnt+32);
  135 
  136         if (!flaglist)
  137             ptrverify(flaglist, "Malloc failed for %d flags\n", pricnt+32);
  138 
  139         for (i=0; i < pricnt; i++)
  140             flaglist[i] = pridef[i].flag;
  141 
  142         flaglist[i] = 0;
  143 
  144         /*
  145         ** add generic flags
  146         */
  147         strcat(flaglist, "b:e:SxCMHr:R:aA");
  148 
  149         while ((c=getopt(argc, argv, flaglist)) != EOF)
  150         {
  151             switch (c)
  152             {
  153                case '?':        /* usage wanted ?        */
  154                 pratopsaruse(argv[0]);
  155                 break;
  156 
  157                            case 'b':        /* begin time ?          */
  158                 if ( !getbranchtime(optarg, &begintime) )
  159                     pratopsaruse(argv[0]);
  160 
  161                 saved_begintime = begintime;
  162                 break;
  163 
  164                            case 'e':        /* end   time ?          */
  165                 if ( !getbranchtime(optarg, &endtime) )
  166                     pratopsaruse(argv[0]);
  167                 break;
  168 
  169                case 'r':        /* reading of file data ? */
  170                 strncpy(rawname, optarg, RAWNAMESZ-1);
  171 
  172                 if (strcmp(rawname, "-") == 0)
  173                     strcpy(rawname, "/dev/stdin");
  174 
  175                 rawreadflag++;
  176                 break;
  177 
  178                case 'R':        /* summarize samples */
  179                 if (!numeric(optarg))
  180                     pratopsaruse(argv[0]);
  181 
  182                 summarycnt = atoi(optarg);
  183 
  184                 if (summarycnt < 1)
  185                     pratopsaruse(argv[0]);
  186                 break;
  187 
  188                case 'S':        /* timestamp on every line */
  189                 stampalways = 1;
  190                 break;
  191 
  192                case 'x':        /* never use colors        */
  193                 usecolors = 0;
  194                 break;
  195 
  196                case 'C':        /* always use colors       */
  197                 usecolors = 'a';
  198                 break;
  199 
  200                case 'M':        /* markers for overload    */
  201                 usemarkers = 1;
  202                 break;
  203 
  204                case 'H':        /* repeat headers          */
  205                 repeathead = 23;    /* define default  */
  206 
  207                 if (isatty(fileno(stdout)))
  208                 {
  209                     struct winsize wsz;
  210 
  211                     if ( ioctl(1, TIOCGWINSZ, &wsz) != -1)
  212                         repeathead = wsz.ws_row - 1;
  213                 }
  214                 break;
  215 
  216                case 'a':        /* every interval all units */
  217                 allresources = 1;
  218                 break;
  219 
  220                case 'A':        /* all reports wanted ?  */
  221                 for (i=0; i < pricnt; i++)
  222                     pridef[i].wanted = 1;
  223 
  224                 numreports = pricnt;
  225                 break;
  226 
  227                default:     /* gather report-flags    */
  228                 for (i=0; i < pricnt; i++)
  229                 {
  230                     if (pridef[i].flag   == c && 
  231                         pridef[i].wanted == 0   )
  232                     {
  233                         pridef[i].wanted = 1;
  234                         numreports++;
  235                         break;
  236                     }
  237                 }
  238 
  239                 if (i == pricnt)
  240                     pratopsaruse(argv[0]);
  241             }
  242         }
  243 
  244         free(flaglist);
  245 
  246         /*
  247         ** get optional interval-value and
  248         ** optional number of samples   
  249         */
  250         if (optind < argc && optind < MAXFL)
  251         {
  252             if (rawreadflag)
  253                 pratopsaruse(argv[0]);
  254 
  255             if (!numeric(argv[optind]))
  256                 pratopsaruse(argv[0]);
  257     
  258             interval = atoi(argv[optind]);
  259     
  260             optind++;
  261     
  262             if (optind < argc)
  263             {
  264                 if (!numeric(argv[optind]) )
  265                     pratopsaruse(argv[0]);
  266 
  267                 if ( (nsamples = atoi(argv[optind])) < 1)
  268                     pratopsaruse(argv[0]);
  269             }
  270         }
  271         else    /* if no interval specified, read from logfile */
  272         {
  273             rawreadflag++;
  274         }
  275     }
  276     else    /* if no flags specified at all, read from logfile */
  277     {
  278         rawreadflag++;
  279     }
  280 
  281     /*
  282     ** if no report-flags have been specified, take the first
  283     ** option in the print-list as default
  284     */
  285     if (numreports == 0)
  286     {
  287         pridef[0].wanted = 1;
  288         numreports       = 1;
  289     }
  290 
  291     /*
  292     ** set stdout output on line-basis
  293     */
  294     setvbuf(stdout, (char *)0, _IOLBF, BUFSIZ);
  295 
  296     /*
  297     ** if only use colors when the output is directed to a tty,
  298     ** be sure that output is directed to a tty
  299     */
  300     if (usecolors == 't')
  301     {
  302         if (! isatty(fileno(stdout)) )
  303             usecolors = 0;
  304     }
  305 
  306     /*
  307     ** check if raw data from a file must be viewed
  308     */
  309     if (rawreadflag)
  310     {
  311         /*
  312         ** select own reportraw-function to be called
  313         ** by the rawread function
  314         */
  315         vis.show_samp  = reportraw;
  316 
  317         for (i=0; i < pricnt; i++)
  318         {
  319             if ( pridef[i].wanted )
  320             {
  321                 prinow    = i;
  322                 daylim    = 0;
  323                 begintime = saved_begintime;
  324 
  325                 if (!rawread()) // reading from named pipe
  326                     break;  // can only be done once
  327 
  328                 printf("\n");
  329             }
  330         }
  331 
  332         cleanstop(0);
  333     }
  334 
  335     /*
  336     ** live data must be gathered
  337     **
  338     ** determine the name of this node (without domain-name)
  339     ** and the kernel-version
  340     */
  341     (void) uname(&utsname);
  342 
  343     if ( (p = strchr(utsname.nodename, '.')) )
  344         *p = '\0';
  345 
  346     sscanf(utsname.release, "%d.%d.%d", &osrel, &osvers, &ossub);
  347 
  348     /*
  349     ** determine the clock rate and memory page size for this machine
  350     */
  351     hertz       = sysconf(_SC_CLK_TCK);
  352     pagesize    = sysconf(_SC_PAGESIZE);
  353 
  354     /*
  355     ** determine start-time for gathering current statistics
  356     */
  357     curtime = time(0);
  358 
  359         /*
  360     ** regain the root-privileges that we dropped at the beginning
  361     ** to do some privileged work now
  362     */
  363         regainrootprivs();
  364 
  365     /*
  366     ** lock in memory to get reliable samples (also when
  367     ** memory is low);
  368     ** ignored if not running under superuser privileges!
  369     */
  370     rlim.rlim_cur   = RLIM_INFINITY;
  371     rlim.rlim_max   = RLIM_INFINITY;
  372     (void) setrlimit(RLIMIT_MEMLOCK, &rlim);
  373     (void) mlockall(MCL_CURRENT|MCL_FUTURE);
  374 
  375     /*
  376     ** increment CPU scheduling-priority to get reliable samples (also
  377     ** during heavy CPU load);
  378     ** ignored if not running under superuser privileges!
  379     */
  380     if ( nice(-20) == -1)
  381         ;
  382     /*
  383     ** determine properties (like speed) of all interfaces
  384     */
  385     initifprop();
  386 
  387     /*
  388     ** since privileged activities are finished now, there is no
  389     ** need to keep running under root-privileges, so switch
  390     ** effective user-id to real user-id
  391     */
  392     if (! droprootprivs() )
  393         mcleanstop(42, "failed to drop root privs\n");
  394 
  395     /*
  396     ** start live reporting
  397     */
  398     engine();
  399 
  400     return 0;
  401 }
  402 
  403 /*
  404 ** engine() that drives the main-loop for atopsar
  405 */
  406 static void
  407 engine(void)
  408 {
  409     struct sigaction    sigact;
  410     void            getusr1(int);
  411 
  412     int         nrgpus;         /* number of GPUs        */
  413     int         nrgpuproc,  /* number of GPU procs   */
  414                 gpustats=0; /* boolean: request sent */
  415 
  416     /*
  417     ** reserve space for system-level statistics
  418     */
  419     static struct sstat *cursstat; /* current   */
  420     static struct sstat *presstat; /* previous  */
  421     static struct sstat *devsstat; /* deviation */
  422     static struct sstat *hlpsstat;
  423 
  424     /*
  425     ** initialization: allocate required memory dynamically
  426     */
  427     cursstat = calloc(1, sizeof(struct sstat));
  428     presstat = calloc(1, sizeof(struct sstat));
  429     devsstat = calloc(1, sizeof(struct sstat));
  430 
  431     ptrverify(cursstat,  "Malloc failed for current sysstats\n");
  432     ptrverify(presstat,  "Malloc failed for prev    sysstats\n");
  433     ptrverify(devsstat,  "Malloc failed for deviate sysstats\n");
  434 
  435     /*
  436     ** install the signal-handler for ALARM and SIGUSR1 (both triggers
  437     ** for the next sample)
  438     */
  439     memset(&sigact, 0, sizeof sigact);
  440     sigact.sa_handler = getusr1;
  441     sigaction(SIGUSR1, &sigact, (struct sigaction *)0);
  442 
  443     memset(&sigact, 0, sizeof sigact);
  444     sigact.sa_handler = getalarm;
  445     sigaction(SIGALRM, &sigact, (struct sigaction *)0);
  446 
  447     if (interval > 0)
  448         alarm(interval);
  449 
  450     /*
  451     ** print overall report header
  452     */
  453     reportheader(&utsname, time(0));
  454 
  455     /*
  456     ** open socket to the atopgpud daemon for GPU statistics
  457     */
  458     nrgpus = gpud_init();
  459 
  460     /*
  461     ** MAIN-LOOP:
  462     **    - Wait for the requested number of seconds or for other trigger
  463     **
  464     **    - System-level counters
  465     **      get current counters
  466     **      calculate the differences with the previous sample
  467     **
  468     **    - Call the print-function to visualize the differences
  469     */
  470     for (sampcnt=0; sampcnt < nsamples+1; sampcnt++)
  471     {
  472         /*
  473         ** wait for alarm-signal to arrive or
  474         ** wait for SIGUSR1 in case of an interval of 0.
  475         */
  476         if (sampcnt > 0)
  477             pause();
  478 
  479         /*
  480         ** gather time info for this sample
  481         */
  482         pretime  = curtime;
  483         curtime  = time(0);     /* seconds since 1-1-1970 */
  484 
  485         /*
  486         ** send request for statistics to atopgpud
  487         */
  488         if (nrgpus)
  489             gpustats = gpud_statrequest();
  490 
  491         /*
  492         ** take a snapshot of the current system-level statistics 
  493         ** and calculate the deviations (i.e. calculate the activity
  494         ** during the last sample)
  495         */
  496         hlpsstat = cursstat;    /* swap current/prev. stats */
  497         cursstat = presstat;
  498         presstat = hlpsstat;
  499 
  500         photosyst(cursstat);    /* obtain new counters      */
  501 
  502         /*
  503         ** receive and parse response from atopgpud
  504         */
  505         if (nrgpus && gpustats)
  506         {
  507             nrgpuproc = gpud_statresponse(nrgpus, cursstat->gpu.gpu, NULL);
  508 
  509             // connection lost or timeout on receive?
  510             if (nrgpuproc == -1)
  511             {
  512                 int ng;
  513 
  514                 // try to reconnect
  515                     ng = gpud_init();
  516 
  517                 if (ng != nrgpus)   // no success
  518                     nrgpus = 0;
  519 
  520                 if (nrgpus)
  521                 {
  522                     // request for stats again
  523                     if (gpud_statrequest())
  524                     {
  525                         // receive stats response
  526                         nrgpuproc = gpud_statresponse(nrgpus,
  527                              cursstat->gpu.gpu, NULL);
  528 
  529                         // persistent failure?
  530                         if (nrgpuproc == -1)
  531                             nrgpus = 0;
  532                     }
  533                 }
  534             }
  535 
  536             cursstat->gpu.nrgpus = nrgpus;
  537         }
  538 
  539         /*
  540         ** calculate deviations, i.e. activity during interval
  541         */
  542         deviatsyst(cursstat, presstat, devsstat,
  543                  curtime-pretime > 0 ? curtime-pretime : 1);
  544 
  545         /*
  546         ** activate the report-function to visualize the deviations
  547         */
  548         reportlive(curtime,
  549             curtime-pretime > 0 ? curtime-pretime : 1, devsstat);
  550     } /* end of main-loop */
  551 }
  552 
  553 /*
  554 ** report function to print a new sample in case of live measurements
  555 */
  556 static void
  557 reportlive(time_t curtime, int numsecs, struct sstat *ss)
  558 {
  559     char            timebuf[16], datebuf[16];
  560     int         i, nr = numreports, rv;
  561     static unsigned int curline, headline;
  562 
  563     /*
  564     ** printing more reports needs another way of handling compared
  565     ** to printing one report
  566     */
  567     if (numreports > 1)
  568     {
  569         /*
  570         ** skip first sample
  571         */
  572         if (sampcnt == 0)
  573             return;
  574 
  575         printf(datemsg, convdate(curtime, datebuf));
  576 
  577         for (i=0; i < pricnt && nr > 0; i++)
  578         {
  579             if ( !pridef[i].wanted )
  580                 continue;
  581 
  582             nr--;
  583 
  584             /*
  585             ** print header-line
  586             */
  587             printf("\n");
  588 
  589             if (usecolors)
  590                 printf(COLSETHEAD);
  591 
  592             printf("%s  ", convtime(curtime-numsecs, timebuf));
  593     
  594             (pridef[i].prihead)(osvers, osrel, ossub);
  595     
  596             if (usecolors)
  597                 printf(COLRESET);
  598 
  599             printf("\n");
  600 
  601             /*
  602             ** print line with statistical counters
  603             */
  604             printf("%s  ", convtime(curtime, timebuf));
  605     
  606             if ( !(pridef[i].priline)(ss, (struct tstat *)0, 0, 0,
  607                 numsecs, numsecs*hertz, hertz,
  608                 osvers, osrel, ossub,
  609                 stampalways ? timebuf : "        ",
  610                             0, 0, 0, 0, 0, 0) )
  611             {
  612                 /*
  613                 ** print line has failed;
  614                 ** do not call function again
  615                 */
  616                 pridef[i].wanted = 0;
  617     
  618                 if (--numreports == 0)
  619                     cleanstop(1);
  620             }
  621         }
  622 
  623         printf("\n");
  624     }
  625     else        /* just one report to be printed */
  626     {
  627         /*
  628         ** search required report
  629         */
  630         for (i=0; i < pricnt; i++)
  631             if ( pridef[i].wanted )
  632                 break;
  633 
  634         /*
  635         ** verify if we have passed midnight of some day
  636         */
  637         if (curtime > daylim)
  638         {
  639             printf(datemsg, convdate(curtime, datebuf));
  640             daylim = daylimit(curtime);
  641             curline++;
  642         }
  643 
  644         /*
  645         ** print first header
  646         */
  647         if (sampcnt == 0)
  648         {
  649             /*
  650             ** print header-line
  651             */
  652             printf("\n");
  653 
  654             if (usecolors)
  655                 printf(COLSETHEAD);
  656 
  657             printf("%s  ", convtime(curtime, timebuf));
  658     
  659             (pridef[i].prihead)(osvers, osrel, ossub);
  660 
  661             if (usecolors)
  662                 printf(COLRESET);
  663 
  664             printf("\n");
  665 
  666             curline+=2;
  667 
  668             headline = repeathead;
  669             return;
  670         }
  671 
  672         /*
  673         ** print line with statistical counters
  674         */
  675         printf("%s  ", convtime(curtime, timebuf));
  676     
  677         if ( !(rv = (pridef[i].priline)(ss, (struct tstat *)0, 0, 0,
  678                     numsecs, numsecs*hertz, hertz,
  679                     osvers, osrel, ossub, 
  680                                 stampalways ? timebuf : "        ",
  681                                 0, 0, 0, 0, 0, 0) ) )
  682         {
  683             /*
  684             ** print line has failed;
  685             ** do not call function again
  686             */
  687             cleanstop(1);
  688         }
  689 
  690         curline+=rv;
  691 
  692         if (curline >= headline)
  693         {
  694             headline = curline + repeathead;
  695 
  696             /*
  697             ** print header-line
  698             */
  699             printf("\n");
  700 
  701             if (usecolors)
  702                 printf(COLSETHEAD);
  703 
  704             printf("%s  ", convtime(curtime, timebuf));
  705     
  706             (pridef[i].prihead)(osvers, osrel, ossub);
  707 
  708             if (usecolors)
  709                 printf(COLRESET);
  710 
  711             printf("\n");
  712 
  713             curline+=2;
  714         }
  715     }
  716 }
  717 
  718 /*
  719 ** report function to print a new sample in case of logged measurements
  720 */
  721 static char
  722 reportraw(time_t curtime, int numsecs,
  723             struct devtstat *devtstat, struct sstat *sstat,
  724         int nexit, unsigned int noverflow, char flags)
  725 {
  726     static char     firstcall = 1;
  727     char            timebuf[16], datebuf[16];
  728     unsigned int        rv;
  729     static unsigned int curline, headline, sampsum,
  730                 totalsec, totalexit, lastnpres,
  731                 lastntrun, lastntslpi, lastntslpu, lastnzomb;
  732     static time_t       lasttime;
  733     static struct sstat totsyst;
  734 
  735     /*
  736     ** is this function still wanted?
  737     */
  738     if ( ! pridef[prinow].wanted )
  739         return '\0';
  740 
  741     /*
  742     ** when this is first call to this function,
  743     ** print overall header with system information
  744     */
  745     if (firstcall)
  746     {
  747         reportheader(&utsname, time(0));
  748         firstcall = 0;
  749     }
  750 
  751     /*
  752     ** verify if we have passed midnight
  753     */
  754     if (curtime > daylim)
  755     {
  756         printf(datemsg, convdate(curtime, datebuf));
  757         daylim = daylimit(curtime);
  758         curline++;
  759     }
  760 
  761     /*
  762     ** when this is the first record for a new report,
  763     ** initialize various variables
  764     */
  765     if (sampcnt == 1)
  766     {
  767         /*
  768         ** initialize variables for new report
  769         */
  770         pretime = curtime;
  771 
  772         curline   = 1;
  773         headline  = 0;
  774 
  775         sampsum   = summarycnt + 1;
  776         totalsec  = 0;
  777         totalexit = 0;
  778         memset(&totsyst, 0, sizeof totsyst);
  779 
  780         return '\0';
  781     }
  782 
  783     /*
  784     ** check if a (new) report header needs to be printed
  785     */
  786     if (curline >= headline)
  787     {
  788         headline = curline + repeathead;
  789 
  790         /*
  791         ** print header-line
  792         */
  793         printf("\n");
  794 
  795         if (usecolors)
  796             printf(COLSETHEAD);
  797 
  798         printf("%s  ", convtime(pretime, timebuf));
  799 
  800         (pridef[prinow].prihead)(osvers, osrel, ossub);
  801 
  802         if (usecolors)
  803             printf(COLRESET);
  804 
  805         printf("\n");
  806 
  807         curline+=2;
  808     }
  809 
  810     /*
  811     ** when current record contains log-restart indicator,
  812     ** print message and reinitialize variables
  813     */
  814     if (flags & RRBOOT)
  815     {
  816         /*
  817         ** when accumulating counters, print results upto
  818         ** the *previous* record
  819         */
  820         if (summarycnt > 1 && sampcnt <= sampsum && totalsec)
  821         {
  822             printf("%s  ", convtime(lasttime, timebuf));
  823 
  824             rv = (pridef[prinow].priline)(&totsyst,
  825                 (struct tstat *)0, 0, 0,
  826                 totalsec, totalsec*hertz, hertz,
  827                     osvers, osrel, ossub,
  828                         stampalways ? timebuf : "        ",
  829                             lastnpres, lastntrun, lastntslpi, lastntslpu,
  830                 totalexit, lastnzomb);
  831 
  832             if (rv == 0)
  833             {
  834                 curline++;
  835                 pridef[prinow].wanted = 0; /* not call again */
  836 
  837                 if (--numreports == 0)
  838                     cleanstop(1);
  839             }
  840             else
  841             {
  842                 curline += rv;
  843             }
  844         }
  845 
  846         /*
  847         ** print restart-line in case of logging restarted
  848         */
  849         printf("%s  ", convtime(curtime, timebuf));
  850 
  851         printf("......................... logging restarted "
  852                ".........................\n");
  853 
  854         pretime = curtime;
  855         curline++;
  856 
  857         /*
  858         ** reinitialize variables
  859         */
  860         sampsum   = summarycnt + sampcnt;
  861         totalsec  = 0;
  862         totalexit = 0;
  863         memset(&totsyst, 0, sizeof totsyst);
  864 
  865         return '\0';
  866     }
  867 
  868     /*
  869     ** when no accumulation is required,
  870     ** just print current sample
  871     */
  872     if (summarycnt == 1)
  873     {
  874         printf("%s  ", convtime(curtime, timebuf));
  875 
  876         rv = (pridef[prinow].priline) (sstat, devtstat->taskall,
  877                 devtstat->procall, devtstat->nprocall,
  878                 numsecs, numsecs*hertz, hertz,
  879                 osvers, osrel, ossub,
  880                         stampalways ? timebuf : "        ",
  881                 devtstat->ntaskall, devtstat->totrun,
  882                 devtstat->totslpi, devtstat->totslpu,
  883                 nexit, devtstat->totzombie);
  884 
  885         if (rv == 0)
  886         {
  887             curline++;
  888             pridef[prinow].wanted = 0; /* not call again */
  889 
  890             if (--numreports == 0)
  891                 cleanstop(1);
  892         }
  893         else
  894         {
  895             curline += rv;
  896         }
  897     }
  898     else        /* accumulation is required */
  899     {
  900         char  *cp = pridef[prinow].cntcat;
  901 
  902         /*
  903         ** maintain totals per category
  904         */
  905         while (*cp)
  906         {
  907             totalsyst(*cp, sstat, &totsyst);
  908             cp++;
  909         }
  910 
  911         totalsec  += numsecs;
  912         totalexit += nexit;
  913 
  914         /*
  915         ** remember some values in case the next record
  916         ** contains the log-restart indicator
  917         */
  918         lasttime   = curtime;
  919         lastnpres  = devtstat->nprocall;
  920         lastntrun  = devtstat->totrun;
  921         lastntslpi = devtstat->totslpi;
  922         lastntslpu = devtstat->totslpu;
  923         lastnzomb  = devtstat->totzombie;
  924 
  925         /*
  926         ** print line only if needed
  927         */
  928         if (sampcnt >= sampsum || ( (flags&RRLAST) && totalsec) )
  929         {
  930             /*
  931             ** print output line for required report
  932             */
  933             printf("%s  ", convtime(curtime, timebuf));
  934 
  935             rv = (pridef[prinow].priline) (&totsyst,
  936                     (struct tstat *)0, 0, 0,
  937                     totalsec, totalsec*hertz, hertz,
  938                     osvers, osrel, ossub,
  939                     stampalways ? timebuf : "        ",
  940                     devtstat->ntaskall, devtstat->totrun,
  941                     devtstat->totslpi, devtstat->totslpu,
  942                     totalexit, devtstat->totzombie);
  943 
  944             if (rv == 0)
  945             {
  946                 curline++;
  947                 pridef[prinow].wanted = 0; /* not call again */
  948 
  949                 if (--numreports == 0)
  950                     cleanstop(1);
  951             }
  952             else
  953             {
  954                 curline += rv;
  955             }
  956 
  957             sampsum   = summarycnt + sampcnt;
  958             totalsec  = 0;
  959             totalexit = 0;
  960             memset(&totsyst, 0, sizeof totsyst);
  961         }
  962         else
  963         {
  964             rv = 1;
  965         }
  966     }
  967 
  968     if (!rv)
  969     {
  970         /*
  971         ** print for line has failed;
  972         ** never call this function again
  973         */
  974         pridef[prinow].wanted = 0;
  975 
  976         if (--numreports == 0)
  977             cleanstop(1);
  978     }
  979 
  980     pretime = curtime;
  981 
  982     return '\0';
  983 }
  984 
  985 /*
  986 ** print overall header
  987 */
  988 static void
  989 reportheader(struct utsname *uname, time_t mtime)
  990 {
  991         char            cdate[16];
  992 
  993         printf("\n%s  %s  %s  %s  %s\n\n",
  994                 uname->nodename,
  995                 uname->release,
  996                 uname->version,
  997                 uname->machine,
  998             convdate(mtime, cdate));
  999 }
 1000 
 1001 /*
 1002 ** print usage of atopsar command
 1003 */
 1004 void
 1005 pratopsaruse(char *myname)
 1006 {
 1007     int i;
 1008 
 1009     fprintf(stderr,
 1010         "Usage: %s [-flags] [-r file|-|date|y...] [-R cnt] [-b time] [-e time]\n",
 1011                                 myname);
 1012     fprintf(stderr, "\t\tor\n");
 1013     fprintf(stderr,
 1014         "Usage: %s [-flags] interval [samples]\n", myname);
 1015     fprintf(stderr, "\n");
 1016     fprintf(stderr,
 1017         "\tToday's atop logfile is used by default!\n");
 1018     fprintf(stderr, "\n");
 1019     fprintf(stderr,
 1020         "\tGeneric flags:\n");
 1021     fprintf(stderr,
 1022         "\t  -r  read statistical data from specific atop logfile\n");
 1023     fprintf(stderr,
 1024         "\t      (pathname, - for stdin, date in format YYYYMMDD, or y[y..])\n");
 1025     fprintf(stderr,
 1026         "\t  -R  summarize <cnt> samples into one sample\n");
 1027     fprintf(stderr,
 1028         "\t  -b  begin  showing data from  specified time as [YYYYMMDD]hhmm\n");
 1029     fprintf(stderr,
 1030         "\t  -e  finish showing data after specified time as [YYYYMMDD]hhmm\n");
 1031     fprintf(stderr,
 1032         "\t  -S  print timestamp on every line in case of more "
 1033         "resources\n");
 1034     fprintf(stderr,
 1035         "\t  -x  never  use colors to indicate overload"
 1036         " (default: only if tty)\n");
 1037     fprintf(stderr,
 1038         "\t  -C  always use colors to indicate overload"
 1039         " (default: only if tty)\n");
 1040     fprintf(stderr,
 1041         "\t  -M  use markers to indicate overload "
 1042         "(* = critical, + = almost)\n");
 1043     fprintf(stderr,
 1044         "\t  -H  repeat report headers "
 1045         "(in case of tty: depending on screen lines)\n");
 1046     fprintf(stderr,
 1047         "\t  -a  print all resources, even when inactive\n");
 1048     fprintf(stderr, "\n");
 1049     fprintf(stderr,
 1050         "\tSpecific flags to select reports:\n");
 1051     fprintf(stderr,
 1052         "\t  -A  print all available reports\n");
 1053 
 1054     for (i=0; i < pricnt; i++)
 1055         fprintf(stderr,
 1056         "\t  -%c  %s\n", pridef[i].flag, pridef[i].about);
 1057 
 1058     fprintf(stderr, "\n");
 1059     fprintf(stderr,
 1060                 "Please refer to the man-page of 'atopsar' "
 1061             "for more details.\n");
 1062 
 1063 
 1064     cleanstop(1);
 1065 }
 1066 
 1067 /*
 1068 ** calculate the epoch-value for the last second
 1069 ** of the day given a certain epoch
 1070 */
 1071 static time_t
 1072 daylimit(time_t timval)
 1073 {
 1074     struct tm  *tp = localtime(&timval);
 1075 
 1076     tp->tm_hour = 23;
 1077     tp->tm_min  = 59;
 1078     tp->tm_sec  = 59;
 1079 
 1080     return mktime(tp);
 1081 }
 1082 
 1083 /*
 1084 ** function to be called before printing a statistics line
 1085 ** to switch on colors when necessary
 1086 */
 1087 static void
 1088 preprint(unsigned int badness)
 1089 {
 1090     if (usecolors)
 1091     {
 1092         if (badness >= 100)
 1093         {
 1094             coloron = 1;
 1095             printf(COLSETHIGH);
 1096         }
 1097         else
 1098         {
 1099             if (almostcrit && badness >= almostcrit)
 1100             {
 1101                 coloron = 1;
 1102                 printf(COLSETMED);
 1103             }
 1104         }
 1105     }
 1106 }
 1107 
 1108 /*
 1109 ** function to be called after printing a statistics line
 1110 ** to switch off colors when necessary and print a line feed
 1111 */
 1112 static void
 1113 postprint(unsigned int badness)
 1114 {
 1115     if (coloron)
 1116     {
 1117         coloron = 0;
 1118         printf(COLRESET);
 1119     }
 1120 
 1121     if (usemarkers)
 1122     {
 1123         if (badness >= 100)
 1124         {
 1125             printf(" *");
 1126         }
 1127         else
 1128         {
 1129             if (almostcrit && badness >= almostcrit)
 1130                 printf(" +");
 1131         }
 1132     }
 1133 
 1134     printf("\n");
 1135 }
 1136 
 1137 /*
 1138 ** function to handle the default flags for atopsar as
 1139 ** read from the files ~/.atoprc and /etc/atoprc
 1140 */
 1141 void
 1142 do_atopsarflags(char *name, char *val)
 1143 {
 1144     int     i, j;
 1145 
 1146     for (i=0; val[i]; i++)
 1147     {
 1148         switch (val[i])
 1149         {
 1150            case '-':
 1151             break;
 1152 
 1153            case 'S':        /* timestamp on every line */
 1154             stampalways = 1;
 1155             break;
 1156 
 1157            case 'x':        /* always colors for overload */
 1158             usecolors = 0;
 1159             break;
 1160 
 1161            case 'C':        /* always colors for overload */
 1162             usecolors = 'a';
 1163             break;
 1164 
 1165            case 'M':        /* markers for overload    */
 1166             usemarkers = 1;
 1167             break;
 1168 
 1169            case 'H':        /* repeat headers          */
 1170             repeathead = 23;    /* define default  */
 1171 
 1172             if (isatty(fileno(stdout)))
 1173             {
 1174                 struct winsize wsz;
 1175 
 1176                 if ( ioctl(1, TIOCGWINSZ, &wsz) != -1)
 1177                     repeathead = wsz.ws_row - 1;
 1178             }
 1179             break;
 1180 
 1181            case 'a':        /* every interval all units */
 1182             allresources = 1;
 1183             break;
 1184 
 1185            case 'A':        /* all reports wanted ?  */
 1186             for (j=0; j < pricnt; j++)
 1187                 pridef[j].wanted = 1;
 1188 
 1189             numreports = pricnt;
 1190             break;
 1191 
 1192            default:     /* gather report-flags    */
 1193             for (j=0; j < pricnt; j++)
 1194             {
 1195                 if (pridef[j].flag   == val[i] && 
 1196                     pridef[j].wanted == 0        )
 1197                 {
 1198                     pridef[j].wanted = 1;
 1199                     numreports++;
 1200                     break;
 1201                 }
 1202             }
 1203         }
 1204     }
 1205 }
 1206 
 1207 /**************************************************************************/
 1208 /*                 Functions to print statistics                          */
 1209 /**************************************************************************/
 1210 /*
 1211 ** CPU statistics
 1212 */
 1213 static void
 1214 cpuhead(int osvers, int osrel, int ossub)
 1215 {
 1216     printf("cpu  %%usr %%nice %%sys %%irq %%softirq  %%steal %%guest "
 1217            " %%wait %%idle  _cpu_");
 1218 }
 1219 
 1220 static int
 1221 cpuline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 1222         time_t deltasec, time_t deltatic, time_t hz,
 1223         int osvers, int osrel, int ossub, char *tstamp,
 1224         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 1225 {
 1226     register int    i, nlines = 1;
 1227     count_t     cputot;
 1228     unsigned int    badness;
 1229 
 1230     /*
 1231     ** print overall statistics
 1232     */
 1233         cputot = ss->cpu.all.stime + ss->cpu.all.utime +
 1234                  ss->cpu.all.ntime + ss->cpu.all.itime +
 1235                  ss->cpu.all.wtime + ss->cpu.all.Itime +
 1236                  ss->cpu.all.Stime + ss->cpu.all.steal;
 1237 
 1238     if (cputot == 0)
 1239         cputot = 1; /* avoid divide-by-zero */
 1240 
 1241     if (cpubadness)
 1242         badness = ((cputot - ss->cpu.all.itime - ss->cpu.all.wtime) *
 1243                             100.0 / cputot) * 100 / cpubadness;
 1244     else
 1245         badness = 0;
 1246 
 1247     preprint(badness);
 1248 
 1249     printf("all %5.0lf %5.0lf %4.0lf %4.0lf %8.0lf %7.0f %6.0f %6.0lf %5.0lf",
 1250                 (double) (ss->cpu.all.utime * 100.0) / cputot * ss->cpu.nrcpu,
 1251                 (double) (ss->cpu.all.ntime * 100.0) / cputot * ss->cpu.nrcpu,
 1252                 (double) (ss->cpu.all.stime * 100.0) / cputot * ss->cpu.nrcpu,
 1253                 (double) (ss->cpu.all.Itime * 100.0) / cputot * ss->cpu.nrcpu,
 1254                 (double) (ss->cpu.all.Stime * 100.0) / cputot * ss->cpu.nrcpu,
 1255                 (double) (ss->cpu.all.steal * 100.0) / cputot * ss->cpu.nrcpu,
 1256                 (double) (ss->cpu.all.guest * 100.0) / cputot * ss->cpu.nrcpu,
 1257                 (double) (ss->cpu.all.wtime * 100.0) / cputot * ss->cpu.nrcpu,
 1258                 (double) (ss->cpu.all.itime * 100.0) / cputot * ss->cpu.nrcpu);
 1259 
 1260     postprint(badness);
 1261 
 1262     /*
 1263     ** print per-cpu statistics
 1264     */
 1265     if (ss->cpu.nrcpu > 1)
 1266     {
 1267         for (i=0; i < ss->cpu.nrcpu; i++)
 1268         {
 1269                 cputot = ss->cpu.cpu[i].stime + ss->cpu.cpu[i].utime +
 1270                              ss->cpu.cpu[i].ntime + ss->cpu.cpu[i].itime +
 1271                              ss->cpu.cpu[i].wtime + ss->cpu.cpu[i].Itime +
 1272                              ss->cpu.cpu[i].Stime + ss->cpu.cpu[i].steal;
 1273 
 1274             if (cputot == 0)
 1275                 cputot = 1; /* avoid divide-by-zero */
 1276 
 1277             if (cpubadness)
 1278                 badness = ((cputot - ss->cpu.cpu[i].itime -
 1279                         ss->cpu.cpu[i].wtime) * 100.0 /
 1280                             cputot) * 100 / cpubadness;
 1281             else
 1282                 badness = 0;
 1283 
 1284             printf("%s ", tstamp);
 1285 
 1286             preprint(badness);
 1287 
 1288             printf("%4d %5.0lf %5.0lf %4.0lf %4.0lf %8.0lf "
 1289                    "%7.0f %6.0lf %6.0lf %5.0lf",
 1290                  i,
 1291                          (double)(ss->cpu.cpu[i].utime * 100.0) / cputot,
 1292                          (double)(ss->cpu.cpu[i].ntime * 100.0) / cputot,
 1293                          (double)(ss->cpu.cpu[i].stime * 100.0) / cputot,
 1294                          (double)(ss->cpu.cpu[i].Itime * 100.0) / cputot,
 1295                          (double)(ss->cpu.cpu[i].Stime * 100.0) / cputot,
 1296                          (double)(ss->cpu.cpu[i].steal * 100.0) / cputot,
 1297                          (double)(ss->cpu.cpu[i].guest * 100.0) / cputot,
 1298                          (double)(ss->cpu.cpu[i].wtime * 100.0) / cputot,
 1299                          (double)(ss->cpu.cpu[i].itime * 100.0) / cputot);
 1300 
 1301             postprint(badness);
 1302 
 1303             nlines++;
 1304         }
 1305     }
 1306 
 1307     return nlines;
 1308 }
 1309 
 1310 
 1311 /*
 1312 ** GPU statistics
 1313 */
 1314 static void
 1315 gpuhead(int osvers, int osrel, int ossub)
 1316 {
 1317     printf("   busaddr   gpubusy  membusy  memocc  memtot memuse  gputype"
 1318            "   _gpu_");
 1319 }
 1320 
 1321 static int
 1322 gpuline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 1323         time_t deltasec, time_t deltatic, time_t hz,
 1324         int osvers, int osrel, int ossub, char *tstamp,
 1325         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 1326 {
 1327     static char firstcall = 1;
 1328     register long   i, nlines = 0;
 1329     char        fmt1[16], fmt2[16];
 1330     count_t     avgmemuse;
 1331 
 1332     for (i=0; i < ss->gpu.nrgpus; i++)  /* per GPU */
 1333     {
 1334         /*
 1335         ** determine whether or not the GPU has been active
 1336         ** during interval
 1337         */
 1338         int wasactive;
 1339 
 1340         wasactive = ss->gpu.gpu[i].gpuperccum +
 1341                     ss->gpu.gpu[i].memperccum;
 1342 
 1343         if (wasactive == -2)      // metrics not available?
 1344             wasactive = 0;
 1345 
 1346         if (ss->gpu.gpu[i].samples == 0)
 1347             avgmemuse = ss->gpu.gpu[i].memusenow;
 1348         else
 1349             avgmemuse = ss->gpu.gpu[i].memusecum /
 1350                         ss->gpu.gpu[i].samples;
 1351 
 1352         // memusage > 512 MiB (rather arbitrary)?
 1353         //
 1354         if (avgmemuse > 512*1024)
 1355             wasactive = 1;
 1356 
 1357         /*
 1358         ** print for the first sample all GPUs that are found;
 1359         ** afterwards print only info about the GPUs
 1360         ** that were really active during the interval
 1361         */
 1362         if (!firstcall && !allresources && !wasactive)
 1363             continue;
 1364 
 1365         if (nlines++)
 1366             printf("%s  ", tstamp);
 1367 
 1368         if (ss->gpu.gpu[i].samples == 0)
 1369             ss->gpu.gpu[i].samples = 1;
 1370 
 1371         if (ss->gpu.gpu[i].gpuperccum == -1)
 1372             strcpy(fmt1, "N/A");
 1373         else
 1374             snprintf(fmt1, sizeof fmt1, "%lld%%",
 1375                ss->gpu.gpu[i].gpuperccum / ss->gpu.gpu[i].samples);
 1376 
 1377         if (ss->gpu.gpu[i].memperccum == -1)
 1378             strcpy(fmt2, "N/A");
 1379         else
 1380             snprintf(fmt2, sizeof fmt2, "%lld%%",
 1381                ss->gpu.gpu[i].memperccum / ss->gpu.gpu[i].samples);
 1382 
 1383         if (ss->gpu.gpu[i].memtotnow == 0)
 1384             ss->gpu.gpu[i].memtotnow = 1;
 1385 
 1386         printf("%2ld/%9.9s %7s  %7s  %5lld%%  %5lldM %5lldM  %s\n",
 1387             i, ss->gpu.gpu[i].busid,
 1388             fmt1, fmt2,
 1389             ss->gpu.gpu[i].memusenow*100/ss->gpu.gpu[i].memtotnow,
 1390             ss->gpu.gpu[i].memtotnow / 1024,
 1391             ss->gpu.gpu[i].memusenow / 1024,
 1392             ss->gpu.gpu[i].type);
 1393     }
 1394 
 1395     if (nlines == 0)
 1396     {
 1397         printf("\n");
 1398         nlines++;
 1399     }
 1400 
 1401     firstcall = 0;
 1402     return nlines;
 1403 }
 1404 
 1405 /*
 1406 ** other processor statistics
 1407 */
 1408 static void
 1409 prochead(int osvers, int osrel, int ossub)
 1410 {
 1411     printf("pswch/s devintr/s  clones/s  loadavg1 loadavg5 loadavg15  "
 1412            "     _load_");
 1413 }
 1414 
 1415 static int
 1416 procline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 1417         time_t deltasec, time_t deltatic, time_t hz,
 1418         int osvers, int osrel, int ossub, char *tstamp,
 1419         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 1420 {
 1421     printf("%7.0lf %9.0lf %9.2lf  %8.2lf %8.2lf  %8.2lf\n",
 1422         (double)ss->cpu.csw    / deltasec,
 1423         (double)ss->cpu.devint / deltasec,
 1424         (double)ss->cpu.nprocs / deltasec,
 1425         ss->cpu.lavg1, ss->cpu.lavg5, ss->cpu.lavg15);
 1426     return 1;
 1427 }
 1428 
 1429 /*
 1430 ** process statistics
 1431 */
 1432 static void
 1433 taskhead(int osvers, int osrel, int ossub)
 1434 {
 1435     printf("clones/s pexit/s  curproc curzomb    thrrun thrslpi thrslpu "
 1436            "_procthr_");
 1437 }
 1438 
 1439 static int
 1440 taskline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 1441         time_t deltasec, time_t deltatic, time_t hz,
 1442         int osvers, int osrel, int ossub, char *tstamp,
 1443         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 1444 {
 1445     if (ppres == 0)
 1446     {
 1447         printf("report not available for live measurements.....\n");
 1448         return 0;
 1449     }
 1450 
 1451     if (ts)     /* process statistics available */
 1452     {
 1453         printf("%8.2lf %7.2lf  %7d %7d    %6d %7d %7d\n",
 1454             (double)ss->cpu.nprocs / deltasec,
 1455             (double)pexit          / deltasec,
 1456             nactproc-pexit, pzombie, ntrun, ntslpi, ntslpu);
 1457     }
 1458     else
 1459     {
 1460         printf("%8.2lf %7.2lf  %7d %7d\n",
 1461             (double)ss->cpu.nprocs / deltasec,
 1462             (double)pexit          / deltasec,
 1463             nactproc-pexit, pzombie);
 1464     }
 1465 
 1466     return 1;
 1467 }
 1468 
 1469 /*
 1470 ** memory- & swap-usage
 1471 */
 1472 static void
 1473 memhead(int osvers, int osrel, int ossub)
 1474 {
 1475     printf("memtotal memfree buffers cached dirty slabmem"
 1476            "  swptotal swpfree _mem_"             );
 1477 }
 1478 
 1479 static int
 1480 memline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 1481         time_t deltasec, time_t deltatic, time_t hz,
 1482         int osvers, int osrel, int ossub, char *tstamp,
 1483         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 1484 {
 1485     unsigned int    mbadness, sbadness;
 1486 
 1487     if (membadness)
 1488         mbadness = ((ss->mem.physmem  - ss->mem.freemem 
 1489                          - ss->mem.cachemem - ss->mem.buffermem
 1490                          + ss->mem.shmem) * 100.0 / ss->mem.physmem) 
 1491                                    * 100   / membadness;
 1492     else
 1493         mbadness = 0;
 1494 
 1495         if (swpbadness)
 1496             sbadness = ((ss->mem.totswap - ss->mem.freeswap)
 1497                                    * 100.0 / ss->mem.totswap)
 1498                                        * 100   / swpbadness;
 1499         else
 1500                 sbadness = 0;
 1501 
 1502     preprint(mbadness >= sbadness ? mbadness : sbadness);
 1503 
 1504     printf("%7lldM %6lldM %6lldM %5lldM %4lldM %6lldM  %7lldM %6lldM",
 1505         ss->mem.physmem   * (pagesize / 1024) /1024,
 1506         ss->mem.freemem   * (pagesize / 1024) /1024,
 1507         ss->mem.buffermem * (pagesize / 1024) /1024,
 1508         ss->mem.cachemem  * (pagesize / 1024) /1024,
 1509         ss->mem.cachedrt  * (pagesize / 1024) /1024,
 1510         ss->mem.slabmem   * (pagesize / 1024) /1024,
 1511         ss->mem.totswap   * (pagesize / 1024) /1024,
 1512         ss->mem.freeswap  * (pagesize / 1024) /1024);
 1513 
 1514     postprint(mbadness >= sbadness ? mbadness : sbadness);
 1515 
 1516     return 1;
 1517 }
 1518 
 1519 /*
 1520 ** swapping statistics
 1521 */
 1522 static void
 1523 swaphead(int osvers, int osrel, int ossub)
 1524 {
 1525     printf("pagescan/s  swapin/s swapout/s oomkill"
 1526            "  commitspc  commitlim   _swap_");
 1527 }
 1528 
 1529 static int
 1530 swapline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 1531         time_t deltasec, time_t deltatic, time_t hz,
 1532         int osvers, int osrel, int ossub, char *tstamp,
 1533         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 1534 {
 1535     unsigned int    badness;
 1536 
 1537     if (membadness)
 1538                 badness = (ss->mem.swouts / deltasec * pagbadness)
 1539                 * 100 / membadness;
 1540     else
 1541         badness = 0;
 1542 
 1543     /*
 1544     ** take care that this line is anyhow colored for
 1545     ** 'almost critical' in case of swapouts > 1 per second
 1546     */
 1547     if (ss->mem.swouts / deltasec > 0  &&
 1548         pagbadness && almostcrit && badness < almostcrit)
 1549         badness = almostcrit;
 1550 
 1551     if (ss->mem.commitlim && ss->mem.committed > ss->mem.commitlim)
 1552         badness = 100;         /* force colored output */
 1553 
 1554     preprint(badness);
 1555 
 1556     printf("%10.2lf %9.2lf %9.2lf %7lld %9lluM %9lluM",
 1557         (double)ss->mem.pgscans / deltasec,
 1558         (double)ss->mem.swins   / deltasec,
 1559         (double)ss->mem.swouts  / deltasec,
 1560                 ss->mem.oomkills,
 1561                 ss->mem.committed * (pagesize / 1024) / 1024,
 1562                 ss->mem.commitlim * (pagesize / 1024) / 1024);
 1563 
 1564     postprint(badness);
 1565 
 1566     return 1;
 1567 }
 1568 
 1569 /*
 1570 ** PSI statistics
 1571 */
 1572 static void
 1573 psihead(int osvers, int osrel, int ossub)
 1574 {
 1575     printf("cpusome    memsome  memfull    iosome  iofull");
 1576 }
 1577 
 1578 static int
 1579 psiline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 1580         time_t deltasec, time_t deltatic, time_t hz,
 1581         int osvers, int osrel, int ossub, char *tstamp,
 1582         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 1583 {
 1584     // calculate pressure percentages for entire interval
 1585     unsigned int    csperc  = ss->psi.cpusome.total/(deltatic*10000/hz);
 1586     unsigned int    msperc  = ss->psi.memsome.total/(deltatic*10000/hz);
 1587     unsigned int    mfperc  = ss->psi.memfull.total/(deltatic*10000/hz);
 1588     unsigned int    isperc  = ss->psi.iosome.total /(deltatic*10000/hz);
 1589     unsigned int    ifperc  = ss->psi.iofull.total /(deltatic*10000/hz);
 1590     unsigned int    badness = 0;
 1591 
 1592     if (!ss->psi.present)
 1593     {
 1594         printf("no PSI stats available for this interval...\n");
 1595         return 1;
 1596     }
 1597 
 1598     // correct percentages if needed
 1599     if (csperc > 100)
 1600         csperc = 100;
 1601 
 1602     if (msperc > 100)
 1603         msperc = 100;
 1604 
 1605     if (mfperc > 100)
 1606         mfperc = 100;
 1607 
 1608     if (isperc > 100)
 1609         isperc = 100;
 1610 
 1611     if (ifperc > 100)
 1612         ifperc = 100;
 1613 
 1614     // consider a 'some' percentage > 0 as almost critical
 1615     // (I/O full tends to increase rapidly as well)
 1616     if (csperc || msperc || isperc || ifperc)
 1617         badness = 80;
 1618 
 1619     // consider a memory 'full' percentage > 0 as critical
 1620     if (mfperc)
 1621         badness = 100;
 1622 
 1623     // show results
 1624     preprint(badness);
 1625 
 1626     printf("   %3u%%       %3u%%     %3u%%      %3u%%    %3u%%",
 1627         csperc, msperc, mfperc, isperc, ifperc);
 1628 
 1629     postprint(badness);
 1630 
 1631     return 1;
 1632 }
 1633 
 1634 
 1635 /*
 1636 ** disk statistics
 1637 */
 1638 static void
 1639 lvmhead(int osvers, int osrel, int ossub)
 1640 {
 1641     printf("disk           busy read/s KB/read  "
 1642            "writ/s KB/writ avque avserv _lvm_");
 1643 }
 1644 
 1645 static void
 1646 mddhead(int osvers, int osrel, int ossub)
 1647 {
 1648     printf("disk           busy read/s KB/read  "
 1649            "writ/s KB/writ avque avserv _mdd_");
 1650 }
 1651 
 1652 static void
 1653 dskhead(int osvers, int osrel, int ossub)
 1654 {
 1655     printf("disk           busy read/s KB/read  "
 1656            "writ/s KB/writ avque avserv _dsk_");
 1657 }
 1658 
 1659 static int
 1660 gendskline(struct sstat *ss, char *tstamp, char selector)
 1661 {
 1662     static char firstcall = 1;
 1663     register int    i, nlines = 0, nunit = 0;
 1664     count_t     mstot, iotot;
 1665     struct perdsk   *dp;
 1666     unsigned int    badness;
 1667 
 1668     switch (selector)
 1669     {
 1670        case 'l':
 1671         dp  = ss->dsk.lvm;
 1672         nunit   = ss->dsk.nlvm;
 1673         break;
 1674 
 1675        case 'm':
 1676         dp  = ss->dsk.mdd;
 1677         nunit   = ss->dsk.nmdd;
 1678         break;
 1679 
 1680        case 'd':
 1681         dp  = ss->dsk.dsk;
 1682         nunit   = ss->dsk.ndsk;
 1683         break;
 1684 
 1685        default:
 1686         return 0;
 1687     }
 1688 
 1689         mstot  = (ss->cpu.all.stime + ss->cpu.all.utime +
 1690                   ss->cpu.all.ntime + ss->cpu.all.itime +
 1691                   ss->cpu.all.wtime + ss->cpu.all.Itime +
 1692                   ss->cpu.all.Stime + ss->cpu.all.steal  )
 1693                 * (count_t)1000 / hertz / ss->cpu.nrcpu;
 1694 
 1695     for (i=0; i < nunit; i++, dp++)
 1696     {
 1697         char    *pn;
 1698         int len;
 1699 
 1700         iotot = dp->nread + dp->nwrite +
 1701                      (dp->ndisc != -1 ? dp->ndisc : 0);
 1702 
 1703         if (iotot == 0 && !firstcall && !allresources)
 1704             continue;   /* no activity on this disk */
 1705 
 1706         /*
 1707         ** disk was active during last interval; print info
 1708         */
 1709         if (nlines++)
 1710             printf("%s  ", tstamp);
 1711 
 1712         if (dskbadness)
 1713             badness = (dp->io_ms * 100.0 / mstot) * 100/dskbadness;
 1714                 else
 1715             badness = 0;
 1716 
 1717         preprint(badness);
 1718 
 1719         if ( (len = strlen(dp->name)) > 14)
 1720             pn = dp->name + len - 14;
 1721         else
 1722             pn = dp->name;
 1723 
 1724         printf("%-14s %3.0lf%% %6.1lf %7.1lf %7.1lf %7.1lf "
 1725                "%5.1lf %9.5lf ms",
 1726                 pn,
 1727             mstot ? (double)dp->io_ms  *  100.0 / mstot   : 0.0,
 1728             mstot ? (double)dp->nread  * 1000.0 / mstot   : 0.0,
 1729             dp->nread  ?
 1730                     (double)dp->nrsect / dp->nread / 2.0  : 0.0,
 1731             mstot ? (double)dp->nwrite * 1000.0 / mstot   : 0.0,
 1732             dp->nwrite ?
 1733                     (double)dp->nwsect / dp->nwrite / 2.0 : 0.0,
 1734             dp->io_ms  ? (double)dp->avque / dp->io_ms    : 0.0,
 1735                 iotot ? (double)dp->io_ms  / iotot            : 0.0);
 1736 
 1737         postprint(badness);
 1738     }
 1739 
 1740     if (nlines == 0)
 1741     {
 1742         printf("\n");
 1743         nlines++;
 1744     }
 1745 
 1746     firstcall = 0;
 1747 
 1748     return nlines;
 1749 }
 1750 
 1751 static int
 1752 lvmline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 1753         time_t deltasec, time_t deltatic, time_t hz,
 1754         int osvers, int osrel, int ossub, char *tstamp,
 1755         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 1756 {
 1757     return gendskline(ss, tstamp, 'l');
 1758 }
 1759 
 1760 static int
 1761 mddline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 1762         time_t deltasec, time_t deltatic, time_t hz,
 1763         int osvers, int osrel, int ossub, char *tstamp,
 1764         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 1765 {
 1766     return gendskline(ss, tstamp, 'm');
 1767 }
 1768 
 1769 static int
 1770 dskline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 1771         time_t deltasec, time_t deltatic, time_t hz,
 1772         int osvers, int osrel, int ossub, char *tstamp,
 1773         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 1774 {
 1775     return gendskline(ss, tstamp, 'd');
 1776 }
 1777 
 1778 /*
 1779 ** NFS client statistics
 1780 */
 1781 static void
 1782 nfmhead(int osvers, int osrel, int ossub)
 1783 {
 1784     printf("mounted_device                          physread/s  physwrit/s"
 1785                "  _nfm_");
 1786 }
 1787 
 1788 static int
 1789 nfmline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 1790         time_t deltasec, time_t deltatic, time_t hz,
 1791         int osvers, int osrel, int ossub, char *tstamp,
 1792         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 1793 {
 1794     static char firstcall = 1;
 1795     register long   i, nlines = 0;
 1796     char        *pn, state;
 1797     int     len;
 1798 
 1799     for (i=0; i < ss->nfs.nfsmounts.nrmounts; i++)  /* per NFS mount */
 1800     {
 1801         /*
 1802         ** print for the first sample all mounts that
 1803         ** are found; afterwards print only the mounts
 1804         ** that were really active during the interval
 1805         */
 1806         if (firstcall                                  ||
 1807             allresources                               ||
 1808             ss->nfs.nfsmounts.nfsmnt[i].age < deltasec ||
 1809             ss->nfs.nfsmounts.nfsmnt[i].bytestotread   ||
 1810             ss->nfs.nfsmounts.nfsmnt[i].bytestotwrite    )
 1811         {
 1812             if (nlines++)
 1813                 printf("%s  ", tstamp);
 1814 
 1815             if ( (len = strlen(ss->nfs.nfsmounts.nfsmnt[i].mountdev)) > 38)
 1816                 pn = ss->nfs.nfsmounts.nfsmnt[i].mountdev + len - 38;
 1817             else
 1818                 pn = ss->nfs.nfsmounts.nfsmnt[i].mountdev;
 1819 
 1820                 if (ss->nfs.nfsmounts.nfsmnt[i].age < deltasec)
 1821                 state = 'M';
 1822             else
 1823                 state = ' ';
 1824 
 1825             printf("%-38s %10.3lfK %10.3lfK    %c\n", 
 1826                 pn,
 1827                 (double)ss->nfs.nfsmounts.nfsmnt[i].bytestotread  /
 1828                                 1024 / deltasec,
 1829                 (double)ss->nfs.nfsmounts.nfsmnt[i].bytestotwrite /
 1830                                 1024 / deltasec,
 1831                 state);
 1832         }
 1833     }
 1834 
 1835     if (nlines == 0)
 1836     {
 1837         printf("\n");
 1838         nlines++;
 1839     }
 1840 
 1841     firstcall= 0;
 1842     return nlines;
 1843 }
 1844 
 1845 static void
 1846 nfchead(int osvers, int osrel, int ossub)
 1847 {
 1848     printf("     rpc/s   rpcread/s  rpcwrite/s  retrans/s  autrefresh/s   "
 1849                "  _nfc_");
 1850 }
 1851 
 1852 static int
 1853 nfcline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 1854         time_t deltasec, time_t deltatic, time_t hz,
 1855         int osvers, int osrel, int ossub, char *tstamp,
 1856         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 1857 {
 1858     printf("%10.2lf  %10.2lf  %10.2lf %10.2lf  %12.2lf\n",
 1859         (double)ss->nfs.client.rpccnt        / deltasec,
 1860         (double)ss->nfs.client.rpcread       / deltasec,
 1861         (double)ss->nfs.client.rpcwrite      / deltasec,
 1862         (double)ss->nfs.client.rpcretrans    / deltasec,
 1863         (double)ss->nfs.client.rpcautrefresh / deltasec);
 1864 
 1865     return 1;
 1866 }
 1867 
 1868 static void
 1869 nfshead(int osvers, int osrel, int ossub)
 1870 {
 1871     printf("  rpc/s  rpcread/s rpcwrite/s MBcr/s  MBcw/s  "
 1872                "nettcp/s netudp/s _nfs_");
 1873 }
 1874 
 1875 static int
 1876 nfsline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 1877         time_t deltasec, time_t deltatic, time_t hz,
 1878         int osvers, int osrel, int ossub, char *tstamp,
 1879         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 1880 {
 1881     printf("%7.2lf %10.2lf %10.2lf %6.2lf %7.2lf %9.2lf %8.2lf\n",
 1882         (double)ss->nfs.server.rpccnt    / deltasec,
 1883         (double)ss->nfs.server.rpcread   / deltasec,
 1884         (double)ss->nfs.server.rpcwrite  / deltasec,
 1885         (double)ss->nfs.server.nrbytes / 1024.0 / 1024.0 / deltasec,
 1886         (double)ss->nfs.server.nwbytes / 1024.0 / 1024.0 / deltasec,
 1887         (double)ss->nfs.server.nettcpcnt / deltasec,
 1888         (double)ss->nfs.server.netudpcnt / deltasec);
 1889 
 1890     return 1;
 1891 }
 1892 
 1893 /*
 1894 ** network-interface statistics
 1895 */
 1896 static void
 1897 ibhead(int osvers, int osrel, int ossub)
 1898 {
 1899     printf("controller port  busy ipack/s opack/s "
 1900            "igbps ogbps maxgbps lanes  _ib_");
 1901 }
 1902 
 1903 static int
 1904 ibline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 1905         time_t deltasec, time_t deltatic, time_t hz,
 1906         int osvers, int osrel, int ossub, char *tstamp,
 1907         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 1908 {
 1909     static char firstcall = 1;
 1910     register long   i, nlines = 0;
 1911     double      busy;
 1912     unsigned int    badness;
 1913 
 1914     for (i=0; i < ss->ifb.nrports; i++) /* per interface */
 1915     {
 1916         count_t ival, oval;
 1917 
 1918         /*
 1919         ** print for the first sample all ports that
 1920         ** are found; afterwards print only the ports
 1921         ** that were really active during the interval
 1922         */
 1923         if (!firstcall && !allresources &&
 1924             !ss->ifb.ifb[i].rcvb && !ss->ifb.ifb[i].sndb)
 1925             continue;
 1926 
 1927         /*
 1928         ** convert byte-transfers to bit-transfers     (*          8)
 1929         ** convert bit-transfers  to gigabit-transfers (/ 1000000000)
 1930         ** per second
 1931         */
 1932         ival = ss->ifb.ifb[i].rcvb*ss->ifb.ifb[i].lanes/125000000/deltasec;
 1933         oval = ss->ifb.ifb[i].sndb*ss->ifb.ifb[i].lanes/125000000/deltasec;
 1934 
 1935         /*
 1936         ** calculate busy-percentage for port
 1937         */
 1938         busy = (ival > oval ? ival*100 : oval*100)/ss->ifb.ifb[i].rate;
 1939 
 1940         if (nlines++)
 1941             printf("%s  ", tstamp);
 1942 
 1943         if (netbadness)
 1944             badness = busy * 100 / netbadness;
 1945         else
 1946             badness = 0;
 1947 
 1948         preprint(badness);
 1949 
 1950         printf("%-10s %4hd %4.0f%% %7.1lf %7.1lf %5lld %5lld %7lld %5d", 
 1951             ss->ifb.ifb[i].ibname,
 1952             ss->ifb.ifb[i].portnr,
 1953             busy,
 1954             (double)ss->ifb.ifb[i].rcvp / deltasec,
 1955             (double)ss->ifb.ifb[i].sndp / deltasec,
 1956             ival, oval,
 1957             ss->ifb.ifb[i].rate / 1000,
 1958             ss->ifb.ifb[i].lanes);
 1959 
 1960         postprint(badness);
 1961     }
 1962 
 1963     if (nlines == 0)
 1964     {
 1965         printf("\n");
 1966         nlines++;
 1967     }
 1968 
 1969     firstcall = 0;
 1970     return nlines;
 1971 }
 1972 
 1973 
 1974 /*
 1975 ** network-interface statistics
 1976 */
 1977 static void
 1978 ifhead(int osvers, int osrel, int ossub)
 1979 {
 1980     printf("interf busy ipack/s opack/s iKbyte/s oKbyte/s "
 1981            "imbps ombps maxmbps_if_");
 1982 }
 1983 
 1984 static int
 1985 ifline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 1986         time_t deltasec, time_t deltatic, time_t hz,
 1987         int osvers, int osrel, int ossub, char *tstamp,
 1988         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 1989 {
 1990     static char firstcall = 1;
 1991     register long   i, nlines = 0;
 1992     double      busy;
 1993     char        busyval[16], dupval;
 1994     unsigned int    badness;
 1995     char        *pn;
 1996     int     len;
 1997 
 1998     for (i=0; i < ss->intf.nrintf; i++) /* per interface */
 1999     {
 2000         count_t ival, oval;
 2001 
 2002         /*
 2003         ** print for the first sample all interfaces which
 2004         ** are found; afterwards print only the interfaces
 2005         ** which were really active during the interval
 2006         */
 2007         if (!firstcall && !allresources &&
 2008             !ss->intf.intf[i].rpack && !ss->intf.intf[i].spack)
 2009             continue;
 2010 
 2011         /*
 2012         ** convert byte-transfers to bit-transfers     (*       8)
 2013         ** convert bit-transfers  to megabit-transfers (/ 1000000)
 2014         ** per second
 2015         */
 2016         ival = ss->intf.intf[i].rbyte/125000/deltasec;
 2017         oval = ss->intf.intf[i].sbyte/125000/deltasec;
 2018 
 2019         /*
 2020         ** calculate busy-percentage for interface
 2021         */
 2022         if (ss->intf.intf[i].speed) /* speed known? */
 2023         {
 2024             if (ss->intf.intf[i].duplex)
 2025                 busy = (ival > oval ? ival*100 : oval*100) /
 2026                         ss->intf.intf[i].speed;
 2027             else
 2028                 busy = (ival + oval) * 100 /
 2029                         ss->intf.intf[i].speed;
 2030 
 2031             // especially with wireless, the speed might have
 2032             // dropped temporarily to a very low value (snapshot)
 2033             // it might be better to take the speed of the
 2034             // previous sample
 2035             if (busy > 100 && ss->intf.intf[i].speed <
 2036                                 ss->intf.intf[i].speedp )
 2037             {
 2038                 ss->intf.intf[i].speed =
 2039                     ss->intf.intf[i].speedp;
 2040 
 2041                 if (ss->intf.intf[i].duplex)
 2042                     busy = (ival > oval ?
 2043                         ival*100 : oval*100) /
 2044                             ss->intf.intf[i].speed;
 2045                 else
 2046                     busy = (ival + oval) * 100 /
 2047                             ss->intf.intf[i].speed;
 2048             }
 2049 
 2050             snprintf(busyval, sizeof busyval,
 2051                         "%3.0lf%%", busy);
 2052         }
 2053         else
 2054         {
 2055             strcpy(busyval, "?"); /* speed unknown */
 2056             busy = 0;
 2057         }
 2058 
 2059         if (nlines++)
 2060             printf("%s  ", tstamp);
 2061 
 2062         if (ss->intf.intf[i].speed)
 2063         {
 2064             if (ss->intf.intf[i].duplex)
 2065                 dupval = 'f';
 2066             else
 2067                 dupval = 'h';
 2068         }
 2069         else
 2070         {
 2071             dupval = ' ';
 2072         }
 2073 
 2074         if (netbadness)
 2075             badness = busy * 100 / netbadness;
 2076         else
 2077             badness = 0;
 2078 
 2079         if ( (len = strlen(ss->intf.intf[i].name)) > 6)
 2080             pn = ss->intf.intf[i].name + len - 6;
 2081         else
 2082             pn = ss->intf.intf[i].name;
 2083 
 2084         preprint(badness);
 2085 
 2086         printf("%-6s %4s %7.1lf %7.1lf %8.0lf %8.0lf "
 2087                "%5lld %5lld %7ld %c", 
 2088             pn, busyval,
 2089             (double)ss->intf.intf[i].rpack / deltasec,
 2090             (double)ss->intf.intf[i].spack / deltasec,
 2091             (double)ss->intf.intf[i].rbyte / 1024 / deltasec,
 2092             (double)ss->intf.intf[i].sbyte / 1024 / deltasec,
 2093             ival, oval,
 2094             ss->intf.intf[i].speed, dupval);
 2095 
 2096         postprint(badness);
 2097     }
 2098 
 2099     if (nlines == 0)
 2100     {
 2101         printf("\n");
 2102         nlines++;
 2103     }
 2104 
 2105     firstcall = 0;
 2106     return nlines;
 2107 }
 2108 
 2109 static void
 2110 IFhead(int osvers, int osrel, int ossub)
 2111 {
 2112     printf("interf ierr/s oerr/s coll/s idrop/s odrop/s "
 2113            "iframe/s ocarrier/s  _if_");
 2114 }
 2115 
 2116 static int
 2117 IFline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 2118         time_t deltasec, time_t deltatic, time_t hz,
 2119         int osvers, int osrel, int ossub, char *tstamp,
 2120         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 2121 {
 2122     static char firstcall = 1;
 2123     register long   i, nlines = 0;
 2124     char        *pn;
 2125     int     len;
 2126 
 2127     for (i=0; i < ss->intf.nrintf; i++) /* per interface */
 2128     {
 2129         /*
 2130         ** print for the first sample all interfaces which
 2131         ** are found; afterwards print only the interfaces
 2132         ** which were really active during the interval
 2133         */
 2134         if (!firstcall && !allresources &&
 2135             !ss->intf.intf[i].rpack && !ss->intf.intf[i].spack)
 2136             continue;
 2137 
 2138         if (nlines++)
 2139             printf("%s  ", tstamp);
 2140 
 2141         if ( (len = strlen(ss->intf.intf[i].name)) > 6)
 2142             pn = ss->intf.intf[i].name + len - 6;
 2143         else
 2144             pn = ss->intf.intf[i].name;
 2145 
 2146         printf("%-6s %6.2lf %6.2lf %6.2lf %7.2lf %7.2lf "
 2147                "%8.2lf %10.2lf\n", 
 2148             pn,
 2149             (double)ss->intf.intf[i].rerrs    / deltasec,
 2150             (double)ss->intf.intf[i].serrs    / deltasec,
 2151             (double)ss->intf.intf[i].scollis  / deltasec,
 2152             (double)ss->intf.intf[i].rdrop    / deltasec,
 2153             (double)ss->intf.intf[i].sdrop    / deltasec,
 2154             (double)ss->intf.intf[i].rframe   / deltasec,
 2155             (double)ss->intf.intf[i].scarrier / deltasec);
 2156     }
 2157 
 2158     if (nlines == 0)
 2159     {
 2160         printf("\n");
 2161         nlines++;
 2162     }
 2163 
 2164     firstcall= 0;
 2165     return nlines;
 2166 }
 2167 
 2168 /*
 2169 ** IP version 4 statistics
 2170 */
 2171 static void
 2172 ipv4head(int osvers, int osrel, int ossub)
 2173 {
 2174     printf("inrecv/s outreq/s indeliver/s forward/s "
 2175            "reasmok/s fragcreat/s  _ipv4_");
 2176 }
 2177 
 2178 static int
 2179 ipv4line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 2180         time_t deltasec, time_t deltatic, time_t hz,
 2181         int osvers, int osrel, int ossub, char *tstamp,
 2182         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 2183 {
 2184     printf("%8.1lf %8.1lf %11.1lf %9.1lf %9.1lf %11.1lf\n", 
 2185         (double)ss->net.ipv4.InReceives  / deltasec,
 2186         (double)ss->net.ipv4.OutRequests / deltasec,
 2187         (double)ss->net.ipv4.InDelivers  / deltasec,
 2188         (double)ss->net.ipv4.Forwarding  / deltasec,
 2189         (double)ss->net.ipv4.ReasmOKs    / deltasec,
 2190         (double)ss->net.ipv4.FragCreates / deltasec);
 2191     return 1;
 2192 }
 2193 
 2194 static void
 2195 IPv4head(int osvers, int osrel, int ossub)
 2196 {
 2197     printf("in: dsc/s hder/s ader/s unkp/s ratim/s rfail/s "
 2198            "out: dsc/s nrt/s_ipv4_");
 2199 }
 2200 
 2201 static int
 2202 IPv4line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 2203         time_t deltasec, time_t deltatic, time_t hz,
 2204         int osvers, int osrel, int ossub, char *tstamp,
 2205         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 2206 {
 2207     printf("    %5.1lf %6.1lf %6.1lf %6.1lf %7.1lf %7.1lf  "
 2208            "    %5.1lf %5.1lf\n", 
 2209         (double)ss->net.ipv4.InDiscards      / deltasec,
 2210         (double)ss->net.ipv4.InHdrErrors     / deltasec,
 2211         (double)ss->net.ipv4.InAddrErrors    / deltasec,
 2212         (double)ss->net.ipv4.InUnknownProtos / deltasec,
 2213         (double)ss->net.ipv4.ReasmTimeout    / deltasec,
 2214         (double)ss->net.ipv4.ReasmFails      / deltasec,
 2215         (double)ss->net.ipv4.OutDiscards     / deltasec,
 2216         (double)ss->net.ipv4.OutNoRoutes     / deltasec);
 2217     return 1;
 2218 }
 2219 
 2220 /*
 2221 ** ICMP version 4 statistics
 2222 */
 2223 static void
 2224 icmpv4head(int osvers, int osrel, int ossub)
 2225 {
 2226     printf("intot/s outtot/s  inecho/s inerep/s  "
 2227            "otecho/s oterep/s       _icmpv4_"   );
 2228 }
 2229 
 2230 static int
 2231 icmpv4line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 2232         time_t deltasec, time_t deltatic, time_t hz,
 2233         int osvers, int osrel, int ossub, char *tstamp,
 2234         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 2235 {
 2236     printf("%7.1lf %8.1lf  %8.2lf %8.2lf  %8.2lf %8.2lf\n", 
 2237         (double)ss->net.icmpv4.InMsgs      / deltasec, 
 2238         (double)ss->net.icmpv4.OutMsgs     / deltasec, 
 2239         (double)ss->net.icmpv4.InEchos     / deltasec, 
 2240         (double)ss->net.icmpv4.OutEchos    / deltasec, 
 2241         (double)ss->net.icmpv4.InEchoReps  / deltasec, 
 2242         (double)ss->net.icmpv4.OutEchoReps / deltasec);
 2243     return 1;
 2244 }
 2245 
 2246 static void
 2247 ICMPv4head(int osvers, int osrel, int ossub)
 2248 {
 2249     printf("ierr/s isq/s ird/s idu/s ite/s "
 2250            "oerr/s osq/s ord/s odu/s ote/s_icmpv4_");
 2251 }
 2252 
 2253 static int
 2254 ICMPv4line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 2255         time_t deltasec, time_t deltatic, time_t hz,
 2256         int osvers, int osrel, int ossub, char *tstamp,
 2257         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 2258 {
 2259     printf("%6.2lf %5.2lf %5.2lf %5.2lf %5.2lf "
 2260            "%6.2lf %5.2lf %5.2lf %5.2lf %5.2lf\n", 
 2261         (double)ss->net.icmpv4.InErrors        / deltasec,
 2262         (double)ss->net.icmpv4.InSrcQuenchs    / deltasec,
 2263         (double)ss->net.icmpv4.InRedirects     / deltasec,
 2264         (double)ss->net.icmpv4.InDestUnreachs  / deltasec,
 2265         (double)ss->net.icmpv4.InTimeExcds     / deltasec,
 2266         (double)ss->net.icmpv4.OutErrors       / deltasec,
 2267         (double)ss->net.icmpv4.OutSrcQuenchs   / deltasec,
 2268         (double)ss->net.icmpv4.OutRedirects    / deltasec,
 2269         (double)ss->net.icmpv4.OutDestUnreachs / deltasec,
 2270         (double)ss->net.icmpv4.OutTimeExcds    / deltasec);
 2271     return 1;
 2272 }
 2273 
 2274 /*
 2275 ** UDP version 4 statistics
 2276 */
 2277 static void
 2278 udpv4head(int osvers, int osrel, int ossub)
 2279 {
 2280     printf("indgram/s outdgram/s   inerr/s  noport/s    "
 2281            "                  _udpv4_");
 2282 }
 2283 
 2284 static int
 2285 udpv4line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 2286         time_t deltasec, time_t deltatic, time_t hz,
 2287         int osvers, int osrel, int ossub, char *tstamp,
 2288         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 2289 {
 2290     printf("%9.1lf %10.1lf   %7.2lf %9.2lf\n",
 2291         (double)ss->net.udpv4.InDatagrams  / deltasec,
 2292         (double)ss->net.udpv4.OutDatagrams / deltasec,
 2293         (double)ss->net.udpv4.InErrors     / deltasec,
 2294         (double)ss->net.udpv4.NoPorts      / deltasec);
 2295     return 1;
 2296 }
 2297 
 2298 /*
 2299 ** IP version 6 statistics
 2300 */
 2301 static void
 2302 ipv6head(int osvers, int osrel, int ossub)
 2303 {
 2304     printf("inrecv/s outreq/s inmc/s outmc/s indeliv/s "
 2305            "reasmok/s fragcre/s _ipv6_");
 2306 }
 2307 
 2308 static int
 2309 ipv6line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 2310         time_t deltasec, time_t deltatic, time_t hz,
 2311         int osvers, int osrel, int ossub, char *tstamp,
 2312         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 2313 {
 2314     printf("%8.1lf %8.1lf %6.1lf %7.1lf %9.1lf %9.1lf %9.1lf\n", 
 2315         (double)ss->net.ipv6.Ip6InReceives   / deltasec,
 2316         (double)ss->net.ipv6.Ip6OutRequests  / deltasec,
 2317         (double)ss->net.ipv6.Ip6InMcastPkts  / deltasec,
 2318         (double)ss->net.ipv6.Ip6OutMcastPkts / deltasec,
 2319         (double)ss->net.ipv6.Ip6InDelivers   / deltasec,
 2320         (double)ss->net.ipv6.Ip6ReasmOKs     / deltasec,
 2321         (double)ss->net.ipv6.Ip6FragCreates  / deltasec);
 2322     return 1;
 2323 }
 2324 
 2325 static void
 2326 IPv6head(int osvers, int osrel, int ossub)
 2327 {
 2328     printf("in: dsc/s hder/s ader/s unkp/s ratim/s rfail/s "
 2329            "out: dsc/s nrt/s_ipv6_");
 2330 }
 2331 
 2332 static int
 2333 IPv6line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 2334         time_t deltasec, time_t deltatic, time_t hz,
 2335         int osvers, int osrel, int ossub, char *tstamp,
 2336         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 2337 {
 2338     printf("    %5.1lf %6.1lf %6.1lf %6.1lf %7.1lf %7.1lf  "
 2339            "    %5.1lf %5.1lf\n", 
 2340         (double)ss->net.ipv6.Ip6InDiscards      / deltasec,
 2341         (double)ss->net.ipv6.Ip6InHdrErrors     / deltasec,
 2342         (double)ss->net.ipv6.Ip6InAddrErrors    / deltasec,
 2343         (double)ss->net.ipv6.Ip6InUnknownProtos / deltasec,
 2344         (double)ss->net.ipv6.Ip6ReasmTimeout    / deltasec,
 2345         (double)ss->net.ipv6.Ip6ReasmFails      / deltasec,
 2346         (double)ss->net.ipv6.Ip6OutDiscards  / deltasec,
 2347         (double)ss->net.ipv6.Ip6OutNoRoutes     / deltasec);
 2348     return 1;
 2349 }
 2350 
 2351 /*
 2352 ** ICMP version 6 statistics
 2353 */
 2354 static void
 2355 icmpv6head(int osvers, int osrel, int ossub)
 2356 {
 2357     printf("intot/s outtot/s inerr/s innsol/s innadv/s "
 2358            "otnsol/s otnadv/s  _icmp6_"   );
 2359 }
 2360 
 2361 static int
 2362 icmpv6line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 2363         time_t deltasec, time_t deltatic, time_t hz,
 2364         int osvers, int osrel, int ossub, char *tstamp,
 2365         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 2366 {
 2367     printf("%7.1lf %8.1lf %7.2lf %8.2lf %8.2lf %8.2lf %8.2lf\n", 
 2368         (double)ss->net.icmpv6.Icmp6InMsgs                  / deltasec, 
 2369         (double)ss->net.icmpv6.Icmp6OutMsgs                 / deltasec, 
 2370         (double)ss->net.icmpv6.Icmp6InErrors                / deltasec, 
 2371         (double)ss->net.icmpv6.Icmp6InNeighborSolicits      / deltasec, 
 2372         (double)ss->net.icmpv6.Icmp6InNeighborAdvertisements/ deltasec, 
 2373         (double)ss->net.icmpv6.Icmp6OutNeighborSolicits     / deltasec, 
 2374         (double)ss->net.icmpv6.Icmp6OutNeighborAdvertisements
 2375                                 /deltasec);
 2376     return 1;
 2377 }
 2378 
 2379 static void
 2380 ICMPv6head(int osvers, int osrel, int ossub)
 2381 {
 2382     printf("iecho/s ierep/s oerep/s idu/s odu/s ird/s ord/s ite/s "
 2383            "ote/s  _icmpv6_");
 2384 }
 2385 
 2386 static int
 2387 ICMPv6line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 2388         time_t deltasec, time_t deltatic, time_t hz,
 2389         int osvers, int osrel, int ossub, char *tstamp,
 2390         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 2391 {
 2392     printf("%7.2lf %7.2lf %7.2lf %5.2lf %5.2lf "
 2393            "%5.2lf %5.2lf %5.2lf %5.2lf\n", 
 2394         (double)ss->net.icmpv6.Icmp6InEchos         / deltasec,
 2395         (double)ss->net.icmpv6.Icmp6InEchoReplies   / deltasec,
 2396         (double)ss->net.icmpv6.Icmp6OutEchoReplies  / deltasec,
 2397         (double)ss->net.icmpv6.Icmp6InDestUnreachs  / deltasec,
 2398         (double)ss->net.icmpv6.Icmp6OutDestUnreachs / deltasec,
 2399         (double)ss->net.icmpv6.Icmp6InRedirects     / deltasec,
 2400         (double)ss->net.icmpv6.Icmp6OutRedirects    / deltasec,
 2401         (double)ss->net.icmpv6.Icmp6InTimeExcds     / deltasec,
 2402         (double)ss->net.icmpv6.Icmp6OutTimeExcds    / deltasec);
 2403     return 1;
 2404 }
 2405 
 2406 /*
 2407 ** UDP version 6 statistics
 2408 */
 2409 static void
 2410 udpv6head(int osvers, int osrel, int ossub)
 2411 {
 2412     printf("indgram/s outdgram/s   inerr/s  noport/s    "
 2413            "                  _udpv6_");
 2414 }
 2415 
 2416 static int
 2417 udpv6line(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 2418         time_t deltasec, time_t deltatic, time_t hz,
 2419         int osvers, int osrel, int ossub, char *tstamp,
 2420         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 2421 {
 2422     printf("%9.1lf %10.1lf   %7.2lf %9.2lf\n",
 2423         (double)ss->net.udpv6.Udp6InDatagrams  / deltasec,
 2424         (double)ss->net.udpv6.Udp6OutDatagrams / deltasec,
 2425         (double)ss->net.udpv6.Udp6InErrors     / deltasec,
 2426         (double)ss->net.udpv6.Udp6NoPorts      / deltasec);
 2427     return 1;
 2428 }
 2429 
 2430 /*
 2431 ** TCP statistics
 2432 */
 2433 static void
 2434 tcphead(int osvers, int osrel, int ossub)
 2435 {
 2436     printf("insegs/s outsegs/s  actopen/s pasopen/s  "
 2437            "nowopen                _tcp_");
 2438 }
 2439 
 2440 static int
 2441 tcpline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 2442         time_t deltasec, time_t deltatic, time_t hz,
 2443         int osvers, int osrel, int ossub, char *tstamp,
 2444         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 2445 {
 2446     printf("%8.1lf %9.1lf  %9.1lf %9.1lf  %7lld\n",
 2447         (double)ss->net.tcp.InSegs       / deltasec,
 2448         (double)ss->net.tcp.OutSegs      / deltasec,
 2449         (double)ss->net.tcp.ActiveOpens  / deltasec,
 2450         (double)ss->net.tcp.PassiveOpens / deltasec,
 2451                 ss->net.tcp.CurrEstab);
 2452     return 1;
 2453 }
 2454 
 2455 static void
 2456 TCPhead(int osvers, int osrel, int ossub)
 2457 {
 2458     printf("inerr/s  retrans/s  attfail/s  "
 2459            "estabreset/s  outreset/s         _tcp_");
 2460 }
 2461 
 2462 static int
 2463 TCPline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 2464         time_t deltasec, time_t deltatic, time_t hz,
 2465         int osvers, int osrel, int ossub, char *tstamp,
 2466         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 2467 {
 2468     printf("%7.1lf  %9.1lf  %9.1lf  %12.1lf  %10.1lf\n",
 2469         (double)ss->net.tcp.InErrs       / deltasec,
 2470         (double)ss->net.tcp.RetransSegs  / deltasec,
 2471         (double)ss->net.tcp.AttemptFails / deltasec,
 2472         (double)ss->net.tcp.EstabResets  / deltasec,
 2473         (double)ss->net.tcp.OutRsts      / deltasec);
 2474     return 1;
 2475 }
 2476 
 2477 #if HTTPSTATS
 2478 static void
 2479 httphead(int osvers, int osrel, int ossub)
 2480 {
 2481     printf("requests/s  Kbytes/s  bytes/req    "
 2482            "idleworkers busyworkers     _http_");
 2483 }
 2484 
 2485 static int
 2486 httpline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 2487         time_t deltasec, time_t deltatic, time_t hz,
 2488         int osvers, int osrel, int ossub, char *tstamp,
 2489         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 2490 {
 2491     printf("%10.2lf  %8.2lf  %9.2lf    %11d %11d\n",
 2492         (double)ss->www.accesses      / deltasec,
 2493         (double)ss->www.totkbytes     / deltasec,
 2494         ss->www.accesses ? 
 2495             (double)ss->www.totkbytes*1024/ss->www.accesses : 0,
 2496                 ss->www.iworkers,
 2497                 ss->www.bworkers);
 2498 
 2499     return 1;
 2500 }
 2501 #endif
 2502 
 2503 /*
 2504 ** per-process statistics: top-3 processor consumers
 2505 */
 2506 static void
 2507 topchead(int osvers, int osrel, int ossub)
 2508 {
 2509     printf("  pid command  cpu%% |   pid command  cpu%% | "
 2510            "  pid command  cpu%%_top3_");
 2511 }
 2512 
 2513 static int
 2514 topcline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 2515         time_t deltasec, time_t deltatic, time_t hz,
 2516         int osvers, int osrel, int ossub, char *tstamp,
 2517         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 2518 {
 2519     count_t availcpu;
 2520 
 2521     if (!ts)
 2522     {
 2523         printf("report not available.....\n");
 2524         return 0;
 2525     }
 2526 
 2527     /*
 2528     ** sort process list in cpu order
 2529     */
 2530     qsort(ps, nactproc, sizeof(struct tstat *), compcpu);
 2531 
 2532     availcpu  = ss->cpu.all.stime + ss->cpu.all.utime +
 2533                 ss->cpu.all.ntime + ss->cpu.all.itime +
 2534                 ss->cpu.all.wtime + ss->cpu.all.Itime +
 2535             ss->cpu.all.Stime + ss->cpu.all.steal;
 2536 
 2537     availcpu /= ss->cpu.nrcpu;
 2538 
 2539     if (availcpu == 0)
 2540         availcpu = 1;   /* avoid divide-by-zero */
 2541 
 2542     if (nactproc >= 1 && (ps[0])->cpu.stime + (ps[0])->cpu.utime > 0)
 2543         printf("%5d %-8.8s %3.0lf%% | ",
 2544           (ps[0])->gen.pid, (ps[0])->gen.name,
 2545           (double)((ps[0])->cpu.stime + (ps[0])->cpu.utime)*100.0/availcpu);
 2546         else
 2547         printf("%19s | ", " ");
 2548 
 2549     if (nactproc >= 2 && (ps[1])->cpu.stime + (ps[1])->cpu.utime > 0)
 2550         printf("%5d %-8.8s %3.0lf%% | ",
 2551           (ps[1])->gen.pid, (ps[1])->gen.name,
 2552           (double)((ps[1])->cpu.stime + (ps[1])->cpu.utime)*100.0/availcpu);
 2553         else
 2554         printf("%19s | ", " ");
 2555 
 2556     if (nactproc >= 3 && (ps[2])->cpu.stime + (ps[2])->cpu.utime > 0)
 2557         printf("%5d %-8.8s %3.0lf%%\n",
 2558           (ps[2])->gen.pid, (ps[2])->gen.name,
 2559           (double)((ps[2])->cpu.stime + (ps[2])->cpu.utime)*100.0/availcpu);
 2560         else
 2561         printf("%19s\n", " ");
 2562 
 2563 
 2564     return 1;
 2565 }
 2566 
 2567 /*
 2568 ** per-process statistics: top-3 memory consumers
 2569 */
 2570 static void
 2571 topmhead(int osvers, int osrel, int ossub)
 2572 {
 2573     printf("  pid command  mem%% |   pid command  mem%% | "
 2574            "  pid command  mem%%_top3_");
 2575 }
 2576 
 2577 static int
 2578 topmline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 2579         time_t deltasec, time_t deltatic, time_t hz,
 2580         int osvers, int osrel, int ossub, char *tstamp,
 2581         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 2582 {
 2583     count_t     availmem;
 2584 
 2585     if (!ts)
 2586     {
 2587         printf("report not available.....\n");
 2588         return 0;
 2589     }
 2590 
 2591     /*
 2592     ** sort process list in memory order
 2593     */
 2594     qsort(ps, nactproc, sizeof(struct tstat *), compmem);
 2595 
 2596     availmem  = ss->mem.physmem * pagesize/1024;
 2597 
 2598         if (nactproc >= 1)
 2599         printf("%5d %-8.8s %3.0lf%% | ",
 2600           (ps[0])->gen.pid, (ps[0])->gen.name,
 2601           (double)(ps[0])->mem.rmem * 100.0 / availmem);
 2602         else
 2603         printf("%19s | ", " ");
 2604 
 2605         if (nactproc >= 2)
 2606         printf("%5d %-8.8s %3.0lf%% | ",
 2607           (ps[1])->gen.pid, (ps[1])->gen.name,
 2608           (double)(ps[1])->mem.rmem * 100.0 / availmem);
 2609         else
 2610         printf("%19s | ", " ");
 2611 
 2612         if (nactproc >= 3)
 2613         printf("%5d %-8.8s %3.0lf%%\n",
 2614           (ps[2])->gen.pid, (ps[2])->gen.name,
 2615           (double)(ps[2])->mem.rmem * 100.0 / availmem);
 2616         else
 2617         printf("%19s\n", " ");
 2618 
 2619 
 2620     return 1;
 2621 }
 2622 
 2623 /*
 2624 ** per-process statistics: top-3 disk consumers
 2625 */
 2626 static void
 2627 topdhead(int osvers, int osrel, int ossub)
 2628 {
 2629     printf("  pid command  dsk%% |   pid command  dsk%% | "
 2630            "  pid command  dsk%%_top3_");
 2631 }
 2632 
 2633 static int
 2634 topdline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 2635         time_t deltasec, time_t deltatic, time_t hz,
 2636         int osvers, int osrel, int ossub, char *tstamp,
 2637         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 2638 {
 2639     int     i;
 2640     count_t     availdsk;
 2641 
 2642     if (!ts)
 2643     {
 2644         printf("report not available.....\n");
 2645         return 0;
 2646     }
 2647 
 2648     if ( !(supportflags & IOSTAT) )
 2649     {
 2650         printf("no per-process disk counters available.....\n");
 2651         return 0;
 2652     }
 2653 
 2654     /*
 2655     ** determine total disk accesses for all processes
 2656     */
 2657     for (i=0, availdsk=0; i < nactproc; i++)
 2658     {
 2659         availdsk += (ps[i])->dsk.rio + (ps[i])->dsk.wio;
 2660     }
 2661 
 2662     if (availdsk == 0)
 2663         availdsk = 1;
 2664 
 2665     /*
 2666     ** sort process list in disk order
 2667     */
 2668     qsort(ps, nactproc, sizeof(struct tstat *), compdsk);
 2669 
 2670         if (nactproc >= 1 && (ps[0])->dsk.rio + (ps[0])->dsk.wio > 0)
 2671         printf("%5d %-8.8s %3.0lf%% | ",
 2672           (ps[0])->gen.pid, (ps[0])->gen.name,
 2673           (double)((ps[0])->dsk.rio+(ps[0])->dsk.wio) *100.0/availdsk);
 2674         else
 2675         printf("%19s | ", " ");
 2676 
 2677         if (nactproc >= 2 && (ps[1])->dsk.rio + (ps[1])->dsk.wio > 0)
 2678         printf("%5d %-8.8s %3.0lf%% | ",
 2679           (ps[1])->gen.pid, (ps[1])->gen.name,
 2680           (double)((ps[1])->dsk.rio+(ps[1])->dsk.wio) *100.0/availdsk);
 2681         else
 2682         printf("%19s | ", " ");
 2683 
 2684         if (nactproc >= 3 && (ps[2])->dsk.rio + (ps[2])->dsk.wio > 0)
 2685         printf("%5d %-8.8s %3.0lf%%\n",
 2686           (ps[2])->gen.pid, (ps[2])->gen.name,
 2687           (double)((ps[2])->dsk.rio+(ps[2])->dsk.wio) *100.0/availdsk);
 2688         else
 2689         printf("%19s\n", " ");
 2690 
 2691 
 2692     return 1;
 2693 }
 2694 
 2695 /*
 2696 ** per-process statistics: top-3 network consumers
 2697 */
 2698 static void
 2699 topnhead(int osvers, int osrel, int ossub)
 2700 {
 2701     printf("  pid command  net%% |   pid command  net%% | "
 2702            "  pid command  net%%_top3_");
 2703 }
 2704 
 2705 static int
 2706 topnline(struct sstat *ss, struct tstat *ts, struct tstat **ps, int nactproc,
 2707         time_t deltasec, time_t deltatic, time_t hz,
 2708         int osvers, int osrel, int ossub, char *tstamp,
 2709         int ppres,  int ntrun, int ntslpi, int ntslpu, int pexit, int pzombie)
 2710 {
 2711     int     i;
 2712     count_t     availnet;
 2713     count_t     totbytes;
 2714 
 2715     if (!ts)
 2716     {
 2717         printf("report not available.....\n");
 2718         return 0;
 2719     }
 2720 
 2721     if ( !(supportflags & NETATOP) )
 2722     {
 2723         printf("no per-process network counters available.....\n");
 2724         return 0;
 2725     }
 2726 
 2727     /*
 2728     ** determine total network accesses for all processes
 2729     */
 2730     for (i=0, availnet=0; i < nactproc; i++)
 2731     {
 2732         availnet += (*(ps+i))->net.tcpssz + (*(ps+i))->net.tcprsz +
 2733                     (*(ps+i))->net.udpssz + (*(ps+i))->net.udprsz;
 2734     }
 2735 
 2736     if (availnet == 0)
 2737         availnet = 1;
 2738 
 2739     /*
 2740     ** sort process list in network order
 2741     */
 2742     qsort(ps, nactproc, sizeof(struct tstat *), compnet);
 2743 
 2744         if (nactproc >= 1)
 2745     {
 2746         totbytes = (ps[0])->net.tcpssz + (ps[0])->net.tcprsz +
 2747                    (ps[0])->net.udpssz + (ps[0])->net.udprsz;
 2748 
 2749         if (totbytes > 0)
 2750             printf("%5d %-8.8s %3.0lf%% | ",
 2751                 (ps[0])->gen.pid, (ps[0])->gen.name,
 2752                 (double)totbytes * 100.0 / availnet);
 2753             else
 2754             printf("%19s | ", " ");
 2755     }
 2756         else
 2757         printf("%19s | ", " ");
 2758 
 2759         if (nactproc >= 2)
 2760     {
 2761         totbytes = (ps[1])->net.tcpssz + (ps[1])->net.tcprsz +
 2762                    (ps[1])->net.udpssz + (ps[1])->net.udprsz;
 2763 
 2764         if (totbytes > 0)
 2765             printf("%5d %-8.8s %3.0lf%% | ",
 2766                 (ps[1])->gen.pid, (ps[1])->gen.name,
 2767                 (double)totbytes * 100.0 / availnet);
 2768             else
 2769             printf("%19s | ", " ");
 2770     }
 2771         else
 2772         printf("%19s | ", " ");
 2773 
 2774         if (nactproc >= 3)
 2775     {
 2776         totbytes = (ps[2])->net.tcpssz + (ps[2])->net.tcprsz +
 2777                    (ps[2])->net.udpssz + (ps[2])->net.udprsz;
 2778 
 2779         if (totbytes > 0)
 2780             printf("%5d %-8.8s %3.0lf%%\n",
 2781                 (ps[2])->gen.pid, (ps[2])->gen.name,
 2782                 (double)totbytes * 100.0 / availnet);
 2783             else
 2784                 printf("%19s\n", " ");
 2785     }
 2786         else
 2787         printf("%19s\n", " ");
 2788 
 2789 
 2790     return 1;
 2791 }
 2792 
 2793 /*********************************************************************/
 2794 /* Function definition table.                                        */
 2795 /*                                                                   */
 2796 /* The layout of this table is as follows:                           */
 2797 /*     Column 1:                                                     */
 2798 /*        Boolean which indicates if the specified function is       */
 2799 /*        active during a run of 'atopsar'. When started,            */
 2800 /*        this boolean will be defined 'true' for all entries for    */
 2801 /*        which the command-line flag has been specified. Initially  */
 2802 /*        this column should contain 0 (false), unless this function */
 2803 /*        is always required.                                        */
 2804 /*        If no flags are specified for 'atopsar', the first entry   */
 2805 /*        in this table is defined active (default flag).            */
 2806 /*                                                                   */
 2807 /*     Column 2:                                                     */
 2808 /*        Categories of counters used by this function.              */
 2809 /*           c = cpu  counters,    m = memory  counters,             */
 2810 /*           d = disk counters,    n = network counters              */
 2811 /*                                                                   */
 2812 /*     Column 3:                                                     */
 2813 /*        Flag which can be used as command-line argument to         */
 2814 /*        select the function defined in this table-entry. Be sure   */
 2815 /*        that a unique character is choosen.                        */
 2816 /*        Notice that certain flags are reserved!                    */
 2817 /*                                                                   */
 2818 /*     Column 4:                                                     */
 2819 /*        Entry-point of the 'printhead' function.                   */
 2820 /*                                                                   */
 2821 /*     Column 5:                                                     */
 2822 /*        Entry-point of the 'printline' function.                   */
 2823 /*                                                                   */
 2824 /*     Column 6:                                                     */
 2825 /*        Information about the statistics shown by the function     */
 2826 /*        specified by the table-entry. This text is printed as      */
 2827 /*        command-usage.                                             */
 2828 /*********************************************************************/
 2829 struct pridef pridef[] =
 2830 {
 2831    {0,  "c",  'c',  cpuhead,    cpuline,    "cpu utilization",        },
 2832    {0,  "c",  'p',  prochead,   procline,   "process(or) load",       },
 2833    {0,  "c",  'P',  taskhead,   taskline,   "processes & threads",    },
 2834    {0,  "c",  'g',  gpuhead,    gpuline,    "gpu utilization",        },
 2835    {0,  "m",  'm',  memhead,    memline,    "memory & swapspace",     },
 2836    {0,  "m",  's',  swaphead,   swapline,   "swap rate",              },
 2837    {0,  "cmd",'B',  psihead,    psiline,    "pressure stall info (PSI)",},
 2838    {0,  "cd", 'l',  lvmhead,    lvmline,    "logical volume activity", },
 2839    {0,  "cd", 'f',  mddhead,    mddline,    "multiple device activity",},
 2840    {0,  "cd", 'd',  dskhead,    dskline,    "disk activity",          },
 2841    {0,  "n",  'h',  ibhead, ibline,     "infiniband utilization", },
 2842    {0,  "n",  'n',  nfmhead,    nfmline,    "NFS client mounts",      },
 2843    {0,  "n",  'j',  nfchead,    nfcline,    "NFS client activity",    },
 2844    {0,  "n",  'J',  nfshead,    nfsline,    "NFS server activity",    },
 2845    {0,  "n",  'i',  ifhead, ifline,     "net-interf (general)",   },
 2846    {0,  "n",  'I',  IFhead, IFline,     "net-interf (errors)",    },
 2847    {0,  "n",  'w',  ipv4head,   ipv4line,   "ip   v4    (general)",   },
 2848    {0,  "n",  'W',  IPv4head,   IPv4line,   "ip   v4    (errors)",    },
 2849    {0,  "n",  'y',  icmpv4head, icmpv4line, "icmp v4    (general)",   },
 2850    {0,  "n",  'Y',  ICMPv4head, ICMPv4line, "icmp v4    (per type)",  },
 2851    {0,  "n",  'u',  udpv4head,  udpv4line,      "udp  v4",                },
 2852    {0,  "n",  'z',  ipv6head,   ipv6line,   "ip   v6    (general)",   },
 2853    {0,  "n",  'Z',  IPv6head,   IPv6line,   "ip   v6    (errors)",    },
 2854    {0,  "n",  'k',  icmpv6head, icmpv6line, "icmp v6    (general)",   },
 2855    {0,  "n",  'K',  ICMPv6head, ICMPv6line, "icmp v6    (per type)",  },
 2856    {0,  "n",  'U',  udpv6head,  udpv6line,      "udp  v6",                },
 2857    {0,  "n",  't',  tcphead,    tcpline,    "tcp        (general)",   },
 2858    {0,  "n",  'T',  TCPhead,    TCPline,    "tcp        (errors)",    },
 2859 #if HTTPSTATS
 2860    {0,  "n",  'o',  httphead,   httpline,   "HTTP activity",          },
 2861 #endif
 2862    {0,  "",   'O',  topchead,   topcline,   "top-3 processes cpu",    },
 2863    {0,  "",   'G',  topmhead,   topmline,   "top-3 processes memory", },
 2864    {0,  "",   'D',  topdhead,   topdline,   "top-3 processes disk",   },
 2865    {0,  "",   'N',  topnhead,   topnline,   "top-3 processes network",},
 2866 };
 2867 
 2868 int pricnt = sizeof(pridef)/sizeof(struct pridef);