"Fossies" - the Fresh Open Source Software Archive

Member "atop-2.8.1/deviate.c" (7 Jan 2023, 57440 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 "deviate.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' 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 functions to calculate the differences for
    8 ** the system-level and process-level counters since the previous sample.
    9 ** ==========================================================================
   10 ** Author:      Gerlof Langeveld
   11 ** E-mail:      gerlof.langeveld@atoptool.nl
   12 ** Date:        November 1996
   13 ** LINUX-port:  June 2000
   14 ** --------------------------------------------------------------------------
   15 ** Copyright (C) 2000-2021 Gerlof Langeveld
   16 **
   17 ** This program is free software; you can redistribute it and/or modify it
   18 ** under the terms of the GNU General Public License as published by the
   19 ** Free Software Foundation; either version 2, or (at your option) any
   20 ** later version.
   21 **
   22 ** This program is distributed in the hope that it will be useful, but
   23 ** WITHOUT ANY WARRANTY; without even the implied warranty of
   24 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   25 ** See the GNU General Public License for more details.
   26 **
   27 ** You should have received a copy of the GNU General Public License
   28 ** along with this program; if not, write to the Free Software
   29 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   30 ** --------------------------------------------------------------------------
   31 */
   32 
   33 #include <sys/types.h>
   34 #include <sys/param.h>
   35 #include <sys/stat.h>
   36 #include <signal.h>
   37 #include <time.h>
   38 #include <stdio.h>
   39 #include <errno.h>
   40 #include <fcntl.h>
   41 #include <unistd.h>
   42 #include <stdlib.h>
   43 #include <limits.h>
   44 #include <memory.h>
   45 #include <string.h>
   46 
   47 #include "atop.h"
   48 #include "ifprop.h"
   49 #include "photoproc.h"
   50 #include "photosyst.h"
   51 
   52 static      void calcdiff(struct tstat *, const struct tstat *,
   53                                       const struct tstat *,
   54                                       char, count_t);
   55 static inline   count_t subcount(count_t, count_t);
   56 
   57 /*
   58 ** calculate the process-activity during the last sample
   59 */
   60 void
   61 deviattask(struct tstat    *curtpres, unsigned long ntaskpres,
   62            struct tstat    *curpexit, unsigned long nprocexit,
   63        struct devtstat *devtstat,
   64        struct sstat    *devsstat)
   65 {
   66     register int        c, d, pall=0, pact=0;
   67     register struct tstat   *curstat, *devstat, *thisproc;
   68     struct tstat        prestat, *pprestat;
   69     struct pinfo        *pinfo;
   70     count_t         totusedcpu;
   71     char            hashtype = 'p';
   72 
   73     /*
   74     ** needed for sanity check later on...
   75     */
   76     totusedcpu  = devsstat->cpu.all.stime + devsstat->cpu.all.utime +
   77               devsstat->cpu.all.ntime + devsstat->cpu.all.itime +
   78               devsstat->cpu.all.wtime + devsstat->cpu.all.Itime +
   79               devsstat->cpu.all.Stime + devsstat->cpu.all.steal;
   80 
   81     /*
   82     ** make new list of all tasks in the task-database;
   83     ** after handling all task, the left-overs are tasks
   84     ** that have disappeared since the previous sample
   85     */
   86     pdb_makeresidue();
   87 
   88     /*
   89     ** remove allocated lists of previous sample and initialize counters
   90     */
   91     if (devtstat->taskall)
   92         free(devtstat->taskall);
   93 
   94     if (devtstat->procall)
   95         free(devtstat->procall);
   96 
   97     if (devtstat->procactive)
   98         free(devtstat->procactive);
   99 
  100     memset(devtstat, 0, sizeof *devtstat);
  101 
  102     /*
  103     ** create list for the sample deviations of all tasks
  104     */
  105     devtstat->ntaskall = ntaskpres + nprocexit;
  106     devtstat->taskall  = malloc(devtstat->ntaskall * sizeof(struct tstat));
  107 
  108     ptrverify(devtstat->taskall, "Malloc failed for %lu deviated tasks\n",
  109                                   devtstat->ntaskall);
  110 
  111     /*
  112     ** calculate deviations per present task
  113     */
  114     for (c=0, thisproc = devtstat->taskall; c < ntaskpres; c++)
  115     {
  116         char    newtask = 0;
  117 
  118         curstat = curtpres+c;
  119         devstat = devtstat->taskall+c;
  120 
  121         if (curstat->gen.isproc)
  122         {
  123             thisproc = devstat; // remember last process seen
  124 
  125             devtstat->nprocall++;
  126 
  127             if (curstat->gen.state == 'Z')
  128             {
  129                 devtstat->totzombie++;
  130             }
  131             else
  132             {
  133                 devtstat->totrun   += curstat->gen.nthrrun;
  134                 devtstat->totslpi  += curstat->gen.nthrslpi;
  135                 devtstat->totslpu  += curstat->gen.nthrslpu;
  136             }
  137         }
  138 
  139         /*
  140         ** get previous figures from task-database
  141         */
  142         if ( pdb_gettask(curstat->gen.pid, curstat->gen.isproc,
  143                          curstat->gen.btime, &pinfo))
  144         {
  145             /*
  146             ** task already present in the previous sample
  147             **
  148             ** save stats from previous sample (to use for
  149             ** further calculations) and store new statistics
  150             ** in task-database
  151             */
  152             if (memcmp(curstat, &pinfo->tstat, 
  153                                sizeof(struct tstat)) == EQ)
  154             {
  155                 /*
  156                 ** no activity for task
  157                 */
  158                 curstat->gen.wasinactive = 1;
  159                 pprestat = curstat;
  160             }
  161             else
  162             {
  163                 /*
  164                 ** save the values of the previous sample
  165                 ** and overwrite the previous sample in
  166                 ** the database with the current sample
  167                 */
  168                 prestat     = pinfo->tstat;
  169                 pprestat    = &prestat;
  170                 pinfo->tstat    = *curstat;
  171 
  172                 curstat->gen.wasinactive = 0;
  173 
  174                 devtstat->ntaskactive++;
  175 
  176                 if (curstat->gen.isproc)
  177                 {
  178                     devtstat->nprocactive++;
  179                 }
  180                 else
  181                 {
  182                     if (thisproc->gen.wasinactive)
  183                     {
  184                         thisproc->gen.wasinactive = 0;
  185                         devtstat->ntaskactive++;
  186                         devtstat->nprocactive++;
  187                     }
  188                 }
  189             }
  190         }
  191         else
  192         {
  193             /*
  194             ** new task which must have been started during
  195             ** last interval
  196             */
  197             memset(&prestat, 0, sizeof(prestat));
  198             pprestat = &prestat;
  199 
  200             curstat->gen.wasinactive = 0;
  201             devtstat->ntaskactive++;
  202 
  203             if (curstat->gen.isproc)
  204             {
  205                 devtstat->nprocactive++;
  206             }
  207             else
  208             {
  209                 if (thisproc->gen.wasinactive)
  210                 {
  211                     thisproc->gen.wasinactive = 0;
  212                     devtstat->ntaskactive++;
  213                     devtstat->nprocactive++;
  214                 }
  215             }
  216 
  217             /*
  218             ** create new task struct
  219             */
  220             pinfo = calloc(1, sizeof(struct pinfo));
  221 
  222             ptrverify(pinfo, "Malloc failed for new pinfo\n");
  223 
  224             pinfo->tstat = *curstat;
  225 
  226             /*
  227             ** add new task to task-database
  228             */
  229             pdb_addtask(curstat->gen.pid, pinfo);
  230 
  231             newtask = 1;
  232         }
  233 
  234         /*
  235         ** do the difference calculations
  236         */
  237         calcdiff(devstat, curstat, pprestat, newtask, totusedcpu);
  238     }
  239 
  240     /*
  241     ** calculate deviations per exited process
  242     */
  243     if (nprocexit > 0 && supportflags&NETATOPD)
  244     {
  245         if (curpexit->gen.pid)
  246             hashtype = 'p';
  247         else
  248             hashtype = 'b';
  249 
  250         netatop_exithash(hashtype);
  251     }
  252 
  253     for (d=c, c=0; c < nprocexit; c++)
  254     {
  255         /*
  256         ** check if this process has been started AND
  257         ** finished since previous sample;
  258         ** if so, it has no use to check if there is still 
  259         ** existing info present in the process-database
  260         */
  261         curstat = curpexit+c;
  262         curstat->gen.wasinactive = 0;
  263 
  264         devtstat->nprocall++;
  265         devtstat->nprocactive++;
  266         devtstat->ntaskactive++;
  267 
  268         if (curstat->gen.pid)   /* acctrecord contains pid? */
  269         {
  270             if ( pdb_gettask(curstat->gen.pid, 1,
  271                              curstat->gen.btime, &pinfo))
  272                     prestat = pinfo->tstat;
  273                 else
  274                     memset(&prestat, 0, sizeof(prestat));
  275         }
  276         else
  277         {
  278             if ( curstat->gen.btime > pretime )
  279             {
  280                 /*
  281                 ** process-start and -finish in same interval
  282                 */
  283                 memset(&prestat, 0, sizeof(prestat));
  284             }
  285             else
  286             {
  287                 /*
  288                 ** process must be known in process-database;
  289                 ** try to match one of the remaining processes
  290                 ** against this exited one
  291                 */
  292                 if ( pdb_srchresidue(curstat, &pinfo) )
  293                     prestat = pinfo->tstat;
  294                 else
  295                     memset(&prestat, 0, sizeof(prestat));
  296             }
  297         }
  298 
  299         /*
  300         ** now do the calculations
  301         */
  302         devstat = devtstat->taskall+d;
  303         memset(devstat, 0, sizeof *devstat);
  304 
  305         devstat->gen = curstat->gen;
  306 
  307         if ( curstat->gen.pid == 0 )
  308             devstat->gen.pid    = prestat.gen.pid;
  309 
  310         if (!prestat.gen.pid)
  311             devstat->gen.excode |= ~(INT_MAX);
  312 
  313         strcpy(devstat->gen.cmdline, prestat.gen.cmdline);
  314 
  315         devstat->cpu.curcpu = -1;
  316 
  317         /*
  318         ** due to the strange exponent-type storage of values
  319         ** in the process accounting record, the resource-value
  320         ** in the exit-record might have been smaller than the
  321         ** stored value of the last registered sample; in that
  322         ** case the deviation should be set to zero
  323         */
  324         if (curstat->cpu.stime > prestat.cpu.stime)
  325             devstat->cpu.stime  = curstat->cpu.stime -
  326                                   prestat.cpu.stime;
  327 
  328         if (curstat->cpu.utime > prestat.cpu.utime)
  329             devstat->cpu.utime  = curstat->cpu.utime -
  330                                   prestat.cpu.utime;
  331 
  332         if (curstat->mem.minflt > prestat.mem.minflt)
  333             devstat->mem.minflt = curstat->mem.minflt - 
  334                                   prestat.mem.minflt;
  335 
  336         if (curstat->mem.majflt > prestat.mem.majflt)
  337             devstat->mem.majflt = curstat->mem.majflt -
  338                                   prestat.mem.majflt;
  339 
  340         if (curstat->dsk.rio > (prestat.dsk.rio + prestat.dsk.wio))
  341             devstat->dsk.rio    = curstat->dsk.rio  -
  342                                   prestat.dsk.rio   -
  343                                   prestat.dsk.wio;
  344 
  345         /*
  346         ** try to match the network counters of netatop
  347         */
  348         if (supportflags & NETATOPD)
  349         {
  350             unsigned long   val = (hashtype == 'p' ?
  351                         curstat->gen.pid :
  352                         curstat->gen.btime);
  353 
  354             netatop_exitfind(val, devstat, &prestat);
  355         }
  356 
  357         /*
  358         ** handle the gpu counters
  359         */
  360         if (curstat->gpu.state || prestat.gpu.state) // GPU use?
  361         {
  362             if (curstat->gpu.state)
  363                 devstat->gpu.state = curstat->gpu.state;
  364             else
  365                 devstat->gpu.state = prestat.gpu.state;
  366 
  367             devstat->gpu.nrgpus = curstat->gpu.nrgpus;
  368             devstat->gpu.gpulist    = curstat->gpu.gpulist;
  369             devstat->gpu.gpubusy    = curstat->gpu.gpubusy;
  370             devstat->gpu.membusy    = curstat->gpu.membusy;
  371             devstat->gpu.timems = curstat->gpu.timems;
  372 
  373             devstat->gpu.memnow = curstat->gpu.memnow;
  374             devstat->gpu.memcum = curstat->gpu.memcum -
  375                           prestat.gpu.memcum;
  376             devstat->gpu.sample = curstat->gpu.sample -
  377                           prestat.gpu.sample;
  378         }
  379         else
  380         {
  381             devstat->gpu.state = '\0';
  382         }
  383 
  384         if (prestat.gen.pid > 0)
  385             pdb_deltask(prestat.gen.pid, prestat.gen.isproc);
  386 
  387         d++;
  388     }
  389 
  390     /*
  391     ** remove unused entries from RESIDUE chain
  392     */
  393     pdb_cleanresidue();
  394 
  395     /*
  396     ** create and fill other pointer lists
  397     */
  398     devtstat->procall    = malloc(devtstat->nprocall *
  399                         sizeof(struct tstat *));
  400     devtstat->procactive = malloc(devtstat->nprocactive *
  401                         sizeof(struct tstat *));
  402 
  403     ptrverify(devtstat->procall, "Malloc failed for %d processes\n",
  404                                   devtstat->nprocall);
  405 
  406     ptrverify(devtstat->procactive, "Malloc failed for %d active procs\n",
  407                                   devtstat->nprocactive);
  408 
  409 
  410         for (c=0, thisproc=devstat=devtstat->taskall; c < devtstat->ntaskall;
  411                                 c++, devstat++)
  412         {
  413             if (devstat->gen.isproc)
  414         {
  415                 devtstat->procall[pall++] = devstat;
  416 
  417             if (! devstat->gen.wasinactive)
  418                     devtstat->procactive[pact++] = devstat;
  419         }
  420         }
  421 }
  422 
  423 /*
  424 ** calculate the differences between the current sample and
  425 ** the previous sample for a task
  426 */
  427 static void
  428 calcdiff(struct tstat *devstat, const struct tstat *curstat,
  429                                 const struct tstat *prestat,
  430                             char newtask, count_t totusedcpu)
  431 {
  432     /*
  433     ** for inactive tasks, set all counters to zero to avoid calculating
  434     ** the deviations (after all, there are no deviations)
  435     */
  436     if (curstat->gen.wasinactive)
  437     {
  438         memset(devstat, 0, sizeof *devstat);
  439     }
  440 
  441     /*
  442     ** copy all STATIC values from the current task settings
  443     */
  444     devstat->gen          = curstat->gen;
  445 
  446     if (newtask)
  447         devstat->gen.excode |= ~(INT_MAX);
  448 
  449     devstat->cpu.nice        = curstat->cpu.nice;
  450     devstat->cpu.prio        = curstat->cpu.prio;
  451     devstat->cpu.rtprio      = curstat->cpu.rtprio;
  452     devstat->cpu.policy      = curstat->cpu.policy;
  453     devstat->cpu.curcpu      = curstat->cpu.curcpu;
  454     devstat->cpu.sleepavg    = curstat->cpu.sleepavg;
  455     devstat->cpu.cgcpuweight = curstat->cpu.cgcpuweight;
  456     devstat->cpu.cgcpumax    = curstat->cpu.cgcpumax;
  457     devstat->cpu.cgcpumaxr   = curstat->cpu.cgcpumaxr;
  458 
  459     if (curstat->cpu.wchan[0])
  460         strcpy(devstat->cpu.wchan, curstat->cpu.wchan);
  461     else
  462         devstat->cpu.wchan[0] = 0;
  463 
  464     devstat->mem.vexec  = curstat->mem.vexec;
  465     devstat->mem.vmem   = curstat->mem.vmem;
  466     devstat->mem.rmem   = curstat->mem.rmem;
  467     devstat->mem.pmem   = curstat->mem.pmem;
  468     devstat->mem.vdata  = curstat->mem.vdata;
  469     devstat->mem.vstack = curstat->mem.vstack;
  470     devstat->mem.vlibs  = curstat->mem.vlibs;
  471     devstat->mem.vswap  = curstat->mem.vswap;
  472     devstat->mem.vlock  = curstat->mem.vlock;
  473 
  474     devstat->mem.cgmemmax  = curstat->mem.cgmemmax;
  475     devstat->mem.cgmemmaxr = curstat->mem.cgmemmaxr;
  476     devstat->mem.cgswpmax  = curstat->mem.cgswpmax;
  477     devstat->mem.cgswpmaxr = curstat->mem.cgswpmaxr;
  478 
  479     if (curstat->gpu.state || prestat->gpu.state) // GPU use?
  480     {
  481         if (curstat->gpu.state)
  482             devstat->gpu.state = curstat->gpu.state;
  483         else
  484             devstat->gpu.state = prestat->gpu.state;
  485 
  486         devstat->gpu.nrgpus  = curstat->gpu.nrgpus;
  487         devstat->gpu.gpulist = curstat->gpu.gpulist;
  488         devstat->gpu.gpubusy = curstat->gpu.gpubusy;
  489         devstat->gpu.membusy = curstat->gpu.membusy;
  490         devstat->gpu.memnow  = curstat->gpu.memnow;
  491         devstat->gpu.timems  = curstat->gpu.timems;
  492     }
  493     else
  494     {
  495         devstat->gpu.state = '\0';
  496     }
  497 
  498     /*
  499     ** for inactive tasks, only the static values had to be copied, while
  500     ** all use counters have already been set to zero
  501     */
  502     if (curstat->gen.wasinactive)
  503         return;
  504 
  505     /*
  506     ** calculate deviations for tasks that were really active
  507     ** (i.e. modified) during the sample
  508     */
  509     devstat->cpu.stime  = 
  510         subcount(curstat->cpu.stime, prestat->cpu.stime);
  511     devstat->cpu.utime  =
  512         subcount(curstat->cpu.utime, prestat->cpu.utime);
  513 
  514     /*
  515     ** particular kernel versions sometimes supply a smaller
  516     ** amount for consumed CPU-ticks than a previous sample;
  517     ** with unsigned calculations this results in 497 days of
  518     ** CPU-consumption so a sanity-check is needed here...
  519     */
  520     if (devstat->cpu.stime > totusedcpu)
  521         devstat->cpu.stime = 1;
  522 
  523     if (devstat->cpu.utime > totusedcpu)
  524         devstat->cpu.utime = 1;
  525 
  526     devstat->cpu.rundelay  =
  527         subcount(curstat->cpu.rundelay, prestat->cpu.rundelay);
  528 
  529     devstat->cpu.blkdelay  =
  530         subcount(curstat->cpu.blkdelay, prestat->cpu.blkdelay);
  531 
  532     devstat->dsk.rio    =
  533         subcount(curstat->dsk.rio, prestat->dsk.rio);
  534     devstat->dsk.rsz    =
  535         subcount(curstat->dsk.rsz, prestat->dsk.rsz);
  536     devstat->dsk.wio    =
  537         subcount(curstat->dsk.wio, prestat->dsk.wio);
  538     devstat->dsk.wsz    =
  539         subcount(curstat->dsk.wsz, prestat->dsk.wsz);
  540     devstat->dsk.cwsz   =
  541         subcount(curstat->dsk.cwsz, prestat->dsk.cwsz);
  542 
  543     devstat->mem.vgrow  = curstat->mem.vmem   - prestat->mem.vmem;
  544     devstat->mem.rgrow  = curstat->mem.rmem   - prestat->mem.rmem;
  545 
  546     devstat->mem.minflt = 
  547         subcount(curstat->mem.minflt, prestat->mem.minflt);
  548     devstat->mem.majflt =
  549         subcount(curstat->mem.majflt, prestat->mem.majflt);
  550 
  551     /*
  552     ** network counters: due to an unload/load of the netatop module,
  553     ** previous counters might be larger than the current
  554     */
  555     if (curstat->net.tcpsnd >= prestat->net.tcpsnd)
  556         devstat->net.tcpsnd =
  557             subcount(curstat->net.tcpsnd, prestat->net.tcpsnd);
  558     else
  559         devstat->net.tcpsnd = curstat->net.tcpsnd;
  560 
  561     if (curstat->net.tcpssz >= prestat->net.tcpssz)
  562         devstat->net.tcpssz =
  563             subcount(curstat->net.tcpssz, prestat->net.tcpssz);
  564     else
  565         devstat->net.tcpssz = curstat->net.tcpssz;
  566 
  567     if (curstat->net.tcprcv >= prestat->net.tcprcv)
  568         devstat->net.tcprcv =
  569             subcount(curstat->net.tcprcv, prestat->net.tcprcv);
  570     else
  571         devstat->net.tcprcv = curstat->net.tcprcv;
  572 
  573     if (curstat->net.tcprsz >= prestat->net.tcprsz)
  574         devstat->net.tcprsz =
  575             subcount(curstat->net.tcprsz, prestat->net.tcprsz);
  576     else
  577         devstat->net.tcprsz = curstat->net.tcprsz;
  578 
  579     if (curstat->net.udpsnd >= prestat->net.udpsnd)
  580         devstat->net.udpsnd =
  581             subcount(curstat->net.udpsnd, prestat->net.udpsnd);
  582     else
  583         devstat->net.udpsnd = curstat->net.udpsnd;
  584 
  585     if (curstat->net.udpssz >= prestat->net.udpssz)
  586         devstat->net.udpssz =
  587             subcount(curstat->net.udpssz, prestat->net.udpssz);
  588     else
  589         devstat->net.udpssz = curstat->net.udpssz;
  590 
  591     if (curstat->net.udprcv >= prestat->net.udprcv)
  592         devstat->net.udprcv =
  593             subcount(curstat->net.udprcv, prestat->net.udprcv);
  594     else
  595         devstat->net.udprcv = curstat->net.udprcv;
  596 
  597     if (curstat->net.udprsz >= prestat->net.udprsz)
  598         devstat->net.udprsz =
  599             subcount(curstat->net.udprsz, prestat->net.udprsz);
  600     else
  601         devstat->net.udprsz = curstat->net.udprsz;
  602 
  603 
  604     if (curstat->gpu.state)
  605     {
  606         devstat->gpu.memcum = curstat->gpu.memcum - prestat->gpu.memcum;
  607         devstat->gpu.sample = curstat->gpu.sample - prestat->gpu.sample;
  608     }
  609 }
  610 
  611 /*
  612 ** calculate the system-activity during the last sample
  613 */
  614 void
  615 deviatsyst(struct sstat *cur, struct sstat *pre, struct sstat *dev,
  616                             long interval)
  617 {
  618     register int    i, j;
  619     count_t     *cdev, *ccur, *cpre;
  620     struct ifprop   ifprop;
  621 
  622     dev->cpu.nrcpu     = cur->cpu.nrcpu;
  623     dev->cpu.devint    = subcount(cur->cpu.devint, pre->cpu.devint);
  624     dev->cpu.csw       = subcount(cur->cpu.csw,    pre->cpu.csw);
  625     dev->cpu.nprocs    = subcount(cur->cpu.nprocs, pre->cpu.nprocs);
  626 
  627     dev->cpu.all.stime = subcount(cur->cpu.all.stime, pre->cpu.all.stime);
  628     dev->cpu.all.utime = subcount(cur->cpu.all.utime, pre->cpu.all.utime);
  629     dev->cpu.all.ntime = subcount(cur->cpu.all.ntime, pre->cpu.all.ntime);
  630     dev->cpu.all.itime = subcount(cur->cpu.all.itime, pre->cpu.all.itime);
  631     dev->cpu.all.wtime = subcount(cur->cpu.all.wtime, pre->cpu.all.wtime);
  632     dev->cpu.all.Itime = subcount(cur->cpu.all.Itime, pre->cpu.all.Itime);
  633     dev->cpu.all.Stime = subcount(cur->cpu.all.Stime, pre->cpu.all.Stime);
  634 
  635     dev->cpu.all.steal = subcount(cur->cpu.all.steal, pre->cpu.all.steal);
  636     dev->cpu.all.guest = subcount(cur->cpu.all.guest, pre->cpu.all.guest);
  637 
  638     dev->cpu.all.instr = subcount(cur->cpu.all.instr, pre->cpu.all.instr);
  639     dev->cpu.all.cycle = subcount(cur->cpu.all.cycle, pre->cpu.all.cycle);
  640 
  641     for (i=0; i < dev->cpu.nrcpu; i++)
  642     {
  643         count_t     ticks;
  644 
  645         dev->cpu.cpu[i].cpunr = cur->cpu.cpu[i].cpunr;
  646         dev->cpu.cpu[i].stime = subcount(cur->cpu.cpu[i].stime,
  647                              pre->cpu.cpu[i].stime);
  648         dev->cpu.cpu[i].utime = subcount(cur->cpu.cpu[i].utime,
  649                              pre->cpu.cpu[i].utime);
  650         dev->cpu.cpu[i].ntime = subcount(cur->cpu.cpu[i].ntime,
  651                              pre->cpu.cpu[i].ntime);
  652         dev->cpu.cpu[i].itime = subcount(cur->cpu.cpu[i].itime,
  653                              pre->cpu.cpu[i].itime);
  654         dev->cpu.cpu[i].wtime = subcount(cur->cpu.cpu[i].wtime,
  655                              pre->cpu.cpu[i].wtime);
  656         dev->cpu.cpu[i].Itime = subcount(cur->cpu.cpu[i].Itime,
  657                              pre->cpu.cpu[i].Itime);
  658         dev->cpu.cpu[i].Stime = subcount(cur->cpu.cpu[i].Stime,
  659                              pre->cpu.cpu[i].Stime);
  660 
  661         dev->cpu.cpu[i].steal = subcount(cur->cpu.cpu[i].steal,
  662                              pre->cpu.cpu[i].steal);
  663         dev->cpu.cpu[i].guest = subcount(cur->cpu.cpu[i].guest,
  664                              pre->cpu.cpu[i].guest);
  665 
  666         dev->cpu.cpu[i].instr = subcount(cur->cpu.cpu[i].instr,
  667                              pre->cpu.cpu[i].instr);
  668         dev->cpu.cpu[i].cycle = subcount(cur->cpu.cpu[i].cycle,
  669                              pre->cpu.cpu[i].cycle);
  670 
  671         ticks             = cur->cpu.cpu[i].freqcnt.ticks;
  672 
  673         dev->cpu.cpu[i].freqcnt.maxfreq = 
  674                     cur->cpu.cpu[i].freqcnt.maxfreq;
  675         dev->cpu.cpu[i].freqcnt.cnt = ticks ?
  676                     subcount(cur->cpu.cpu[i].freqcnt.cnt,
  677                              pre->cpu.cpu[i].freqcnt.cnt)
  678                            : cur->cpu.cpu[i].freqcnt.cnt;
  679 
  680         dev->cpu.cpu[i].freqcnt.ticks = ticks ?
  681                     subcount(cur->cpu.cpu[i].freqcnt.ticks,
  682                              pre->cpu.cpu[i].freqcnt.ticks)
  683                            : cur->cpu.cpu[i].freqcnt.ticks;
  684     }
  685 
  686     dev->cpu.lavg1      = cur->cpu.lavg1;
  687     dev->cpu.lavg5      = cur->cpu.lavg5;
  688     dev->cpu.lavg15     = cur->cpu.lavg15;
  689 
  690     dev->mem.physmem    = cur->mem.physmem;
  691     dev->mem.freemem    = cur->mem.freemem;
  692     dev->mem.buffermem  = cur->mem.buffermem;
  693     dev->mem.slabmem    = cur->mem.slabmem;
  694     dev->mem.slabreclaim    = cur->mem.slabreclaim;
  695     dev->mem.committed  = cur->mem.committed;
  696     dev->mem.commitlim  = cur->mem.commitlim;
  697     dev->mem.cachemem   = cur->mem.cachemem;
  698     dev->mem.cachedrt   = cur->mem.cachedrt;
  699     dev->mem.totswap    = cur->mem.totswap;
  700     dev->mem.freeswap   = cur->mem.freeswap;
  701     dev->mem.swapcached = cur->mem.swapcached;
  702     dev->mem.pagetables = cur->mem.pagetables;
  703 
  704     dev->mem.shmem      = cur->mem.shmem;
  705     dev->mem.shmrss     = cur->mem.shmrss;
  706     dev->mem.shmswp     = cur->mem.shmswp;
  707 
  708     dev->mem.tothugepage    = cur->mem.tothugepage;
  709     dev->mem.freehugepage   = cur->mem.freehugepage;
  710     dev->mem.hugepagesz = cur->mem.hugepagesz;
  711 
  712     dev->mem.vmwballoon = cur->mem.vmwballoon;
  713     dev->mem.zfsarcsize = cur->mem.zfsarcsize;
  714     dev->mem.ksmsharing = cur->mem.ksmsharing;
  715     dev->mem.ksmshared  = cur->mem.ksmshared;
  716     dev->mem.zswstored  = cur->mem.zswstored;
  717     dev->mem.zswtotpool = cur->mem.zswtotpool;
  718 
  719     dev->mem.tcpsock    = cur->mem.tcpsock;
  720     dev->mem.udpsock    = cur->mem.udpsock;
  721 
  722     dev->mem.pgouts     = subcount(cur->mem.pgouts,  pre->mem.pgouts);
  723     dev->mem.pgins      = subcount(cur->mem.pgins,   pre->mem.pgins);
  724     dev->mem.swouts     = subcount(cur->mem.swouts,  pre->mem.swouts);
  725     dev->mem.swins      = subcount(cur->mem.swins,   pre->mem.swins);
  726     dev->mem.pgscans    = subcount(cur->mem.pgscans, pre->mem.pgscans);
  727     dev->mem.pgsteal    = subcount(cur->mem.pgsteal, pre->mem.pgsteal);
  728     dev->mem.allocstall = subcount(cur->mem.allocstall,
  729                                          pre->mem.allocstall);
  730 
  731     if (cur->mem.oomkills != -1)
  732         dev->mem.oomkills = subcount(cur->mem.oomkills, pre->mem.oomkills);
  733     else
  734         dev->mem.oomkills = -1;
  735 
  736     dev->mem.compactstall   = subcount(cur->mem.compactstall,
  737                                          pre->mem.compactstall);
  738     dev->mem.numamigrate    = subcount(cur->mem.numamigrate, pre->mem.numamigrate);
  739     dev->mem.pgmigrate  = subcount(cur->mem.pgmigrate,   pre->mem.pgmigrate);
  740 
  741     dev->memnuma.nrnuma     = cur->memnuma.nrnuma;
  742 
  743     for (i=0; i < dev->memnuma.nrnuma; i++)
  744     {
  745         dev->memnuma.numa[i].numanr      = cur->memnuma.numa[i].numanr;
  746         dev->memnuma.numa[i].totmem      = cur->memnuma.numa[i].totmem;
  747         dev->memnuma.numa[i].freemem     = cur->memnuma.numa[i].freemem;
  748         dev->memnuma.numa[i].filepage    = cur->memnuma.numa[i].filepage;
  749         dev->memnuma.numa[i].active      = cur->memnuma.numa[i].active;
  750         dev->memnuma.numa[i].inactive    = cur->memnuma.numa[i].inactive;
  751         dev->memnuma.numa[i].dirtymem    = cur->memnuma.numa[i].dirtymem;
  752         dev->memnuma.numa[i].shmem       = cur->memnuma.numa[i].shmem;
  753         dev->memnuma.numa[i].slabmem     = cur->memnuma.numa[i].slabmem;
  754         dev->memnuma.numa[i].slabreclaim = cur->memnuma.numa[i].slabreclaim;
  755         dev->memnuma.numa[i].tothp       = cur->memnuma.numa[i].tothp;
  756         dev->memnuma.numa[i].frag        = cur->memnuma.numa[i].frag;
  757     }
  758 
  759     dev->cpunuma.nrnuma = cur->cpunuma.nrnuma;
  760 
  761     if (dev->cpunuma.nrnuma > 1)
  762     {
  763         for (i=0; i < dev->cpunuma.nrnuma; i++)
  764         {
  765             dev->cpunuma.numa[i].nrcpu  = cur->cpunuma.numa[i].nrcpu;
  766             dev->cpunuma.numa[i].numanr = cur->cpunuma.numa[i].numanr;
  767 
  768             dev->cpunuma.numa[i].utime  = subcount(cur->cpunuma.numa[i].utime,
  769                                 pre->cpunuma.numa[i].utime);
  770             dev->cpunuma.numa[i].ntime  = subcount(cur->cpunuma.numa[i].ntime,
  771                                 pre->cpunuma.numa[i].ntime);
  772             dev->cpunuma.numa[i].stime  = subcount(cur->cpunuma.numa[i].stime,
  773                                 pre->cpunuma.numa[i].stime);
  774             dev->cpunuma.numa[i].itime  = subcount(cur->cpunuma.numa[i].itime,
  775                                 pre->cpunuma.numa[i].itime);
  776             dev->cpunuma.numa[i].wtime  = subcount(cur->cpunuma.numa[i].wtime,
  777                                 pre->cpunuma.numa[i].wtime);
  778             dev->cpunuma.numa[i].Itime  = subcount(cur->cpunuma.numa[i].Itime,
  779                                 pre->cpunuma.numa[i].Itime);
  780             dev->cpunuma.numa[i].Stime  = subcount(cur->cpunuma.numa[i].Stime,
  781                                 pre->cpunuma.numa[i].Stime);
  782             dev->cpunuma.numa[i].steal  = subcount(cur->cpunuma.numa[i].steal,
  783                                 pre->cpunuma.numa[i].steal);
  784             dev->cpunuma.numa[i].guest  = subcount(cur->cpunuma.numa[i].guest,
  785                                 pre->cpunuma.numa[i].guest);
  786         }
  787     }
  788 
  789     dev->psi = cur->psi;
  790 
  791     if (cur->psi.present)
  792     {
  793         dev->psi.cpusome.total  = cur->psi.cpusome.total -
  794                       pre->psi.cpusome.total;
  795         dev->psi.memsome.total  = cur->psi.memsome.total -
  796                       pre->psi.memsome.total;
  797         dev->psi.memfull.total  = cur->psi.memfull.total -
  798                       pre->psi.memfull.total;
  799         dev->psi.iosome.total   = cur->psi.iosome.total -
  800                       pre->psi.iosome.total;
  801         dev->psi.iofull.total   = cur->psi.iofull.total -
  802                       pre->psi.iofull.total;
  803     }
  804 
  805     /*
  806     ** structures with network-related counters are considered
  807     ** as tables of frequency-counters that have to be subtracted;
  808     ** values that do not represent a frequency are corrected afterwards
  809     */
  810     for (cdev = (count_t *)&dev->net.ipv4,
  811          ccur = (count_t *)&cur->net.ipv4,
  812          cpre = (count_t *)&pre->net.ipv4,
  813          i    = 0;
  814         i < (sizeof dev->net.ipv4 / sizeof(count_t));
  815                 cdev++, ccur++, cpre++, i++)
  816                 *cdev = *ccur - *cpre;
  817     
  818     dev->net.ipv4.Forwarding = cur->net.ipv4.Forwarding;
  819     dev->net.ipv4.DefaultTTL = cur->net.ipv4.DefaultTTL;
  820 
  821         /* ------------- */
  822 
  823     for (cdev = (count_t *)&dev->net.icmpv4,
  824          ccur = (count_t *)&cur->net.icmpv4,
  825          cpre = (count_t *)&pre->net.icmpv4,
  826          i    = 0;
  827         i < (sizeof dev->net.icmpv4 / sizeof(count_t));
  828                 cdev++, ccur++, cpre++, i++)
  829                 *cdev = *ccur - *cpre;
  830 
  831         /* ------------- */
  832 
  833     for (cdev = (count_t *)&dev->net.udpv4,
  834          ccur = (count_t *)&cur->net.udpv4,
  835          cpre = (count_t *)&pre->net.udpv4,
  836          i    = 0;
  837         i < (sizeof dev->net.udpv4 / sizeof(count_t));
  838                 cdev++, ccur++, cpre++, i++)
  839                 *cdev = *ccur - *cpre;
  840 
  841         /* ------------- */
  842 
  843     for (cdev = (count_t *)&dev->net.ipv6,
  844          ccur = (count_t *)&cur->net.ipv6,
  845          cpre = (count_t *)&pre->net.ipv6,
  846          i    = 0;
  847         i < (sizeof dev->net.ipv6 / sizeof(count_t));
  848                 cdev++, ccur++, cpre++, i++)
  849                 *cdev = *ccur - *cpre;
  850 
  851         /* ------------- */
  852 
  853     for (cdev = (count_t *)&dev->net.icmpv6,
  854          ccur = (count_t *)&cur->net.icmpv6,
  855          cpre = (count_t *)&pre->net.icmpv6,
  856          i    = 0;
  857         i < (sizeof dev->net.icmpv6 / sizeof(count_t));
  858                 cdev++, ccur++, cpre++, i++)
  859                 *cdev = *ccur - *cpre;
  860 
  861         /* ------------- */
  862 
  863     for (cdev = (count_t *)&dev->net.udpv6,
  864          ccur = (count_t *)&cur->net.udpv6,
  865          cpre = (count_t *)&pre->net.udpv6,
  866          i    = 0;
  867         i < (sizeof dev->net.udpv6 / sizeof(count_t));
  868                 cdev++, ccur++, cpre++, i++)
  869                 *cdev = *ccur - *cpre;
  870 
  871         /* ------------- */
  872 
  873     for (cdev = (count_t *)&dev->net.tcp,
  874          ccur = (count_t *)&cur->net.tcp,
  875          cpre = (count_t *)&pre->net.tcp,
  876          i    = 0;
  877         i < (sizeof dev->net.tcp / sizeof(count_t));
  878                 cdev++, ccur++, cpre++, i++)
  879                 *cdev = *ccur - *cpre;
  880 
  881     dev->net.tcp.RtoAlgorithm = cur->net.tcp.RtoAlgorithm;
  882     dev->net.tcp.RtoMin       = cur->net.tcp.RtoMin;
  883     dev->net.tcp.RtoMax       = cur->net.tcp.RtoMax;
  884     dev->net.tcp.MaxConn      = cur->net.tcp.MaxConn;
  885     dev->net.tcp.CurrEstab    = cur->net.tcp.CurrEstab;
  886 
  887     /*
  888     ** calculate deviations for interfaces
  889     */
  890     for (i=0; cur->intf.intf[i].name[0]; i++)
  891     {
  892         // fill current properties for each valid interface
  893         strcpy(ifprop.name, cur->intf.intf[i].name);
  894 
  895         getifprop(&ifprop);
  896 
  897         cur->intf.intf[i].type   = ifprop.type;
  898         cur->intf.intf[i].speed  = ifprop.speed;
  899         cur->intf.intf[i].speedp = ifprop.speed;
  900         cur->intf.intf[i].duplex = ifprop.fullduplex;
  901     }
  902 
  903     if (pre->intf.intf[0].name[0] == '\0')  /* first sample? */
  904     {
  905         for (i=0; cur->intf.intf[i].name[0]; i++)
  906         {
  907             strcpy(pre->intf.intf[i].name, cur->intf.intf[i].name);
  908 
  909             pre->intf.intf[i].type   = cur->intf.intf[i].type;
  910             pre->intf.intf[i].speed  = cur->intf.intf[i].speed;
  911             pre->intf.intf[i].speedp = cur->intf.intf[i].speedp;
  912             pre->intf.intf[i].duplex = cur->intf.intf[i].duplex;
  913         }
  914     }
  915     
  916     for (i=0, j=0; cur->intf.intf[i].name[0]; i++, j++)
  917     {
  918         /*
  919         ** be sure that we have the same interface
  920         ** (interfaces could have been added or removed since
  921         ** previous sample)
  922         */
  923         if (strcmp(cur->intf.intf[i].name, pre->intf.intf[j].name) != 0)
  924         {
  925             // try to resync
  926             for (j=0; pre->intf.intf[j].name[0]; j++)
  927             {
  928                 if (strcmp(cur->intf.intf[i].name,
  929                            pre->intf.intf[j].name) == 0)
  930                     break;
  931             }
  932 
  933             // resync not succeeded?
  934             if (! pre->intf.intf[j].name[0])
  935             {
  936                 memcpy(&dev->intf.intf[i],
  937                        &cur->intf.intf[i],
  938                        sizeof cur->intf.intf[i]);
  939 
  940                 j = 0;
  941                 continue;
  942             }
  943         }
  944 
  945         /*
  946         ** calculate interface deviations for this sample
  947         */
  948         strcpy(dev->intf.intf[i].name, cur->intf.intf[i].name);
  949 
  950         dev->intf.intf[i].rbyte = subcount(cur->intf.intf[i].rbyte,
  951                                                pre->intf.intf[j].rbyte);
  952         dev->intf.intf[i].rpack = subcount(cur->intf.intf[i].rpack,
  953                                            pre->intf.intf[j].rpack);
  954         dev->intf.intf[i].rerrs = subcount(cur->intf.intf[i].rerrs,
  955                                            pre->intf.intf[j].rerrs);
  956         dev->intf.intf[i].rdrop = subcount(cur->intf.intf[i].rdrop,
  957                                            pre->intf.intf[j].rdrop);
  958         dev->intf.intf[i].rfifo = subcount(cur->intf.intf[i].rfifo,
  959                                            pre->intf.intf[j].rfifo);
  960         dev->intf.intf[i].rframe= subcount(cur->intf.intf[i].rframe,
  961                                            pre->intf.intf[j].rframe);
  962         dev->intf.intf[i].rcompr= subcount(cur->intf.intf[i].rcompr,
  963                                            pre->intf.intf[j].rcompr);
  964         dev->intf.intf[i].rmultic=subcount(cur->intf.intf[i].rmultic,
  965                                            pre->intf.intf[j].rmultic);
  966 
  967         dev->intf.intf[i].sbyte = subcount(cur->intf.intf[i].sbyte,
  968                                            pre->intf.intf[j].sbyte);
  969         dev->intf.intf[i].spack = subcount(cur->intf.intf[i].spack,
  970                                            pre->intf.intf[j].spack);
  971         dev->intf.intf[i].serrs = subcount(cur->intf.intf[i].serrs,
  972                                            pre->intf.intf[j].serrs);
  973         dev->intf.intf[i].sdrop = subcount(cur->intf.intf[i].sdrop,
  974                                            pre->intf.intf[j].sdrop);
  975         dev->intf.intf[i].sfifo = subcount(cur->intf.intf[i].sfifo,
  976                                            pre->intf.intf[j].sfifo);
  977         dev->intf.intf[i].scollis= subcount(cur->intf.intf[i].scollis,
  978                                            pre->intf.intf[j].scollis);
  979         dev->intf.intf[i].scarrier= subcount(cur->intf.intf[i].scarrier,
  980                                            pre->intf.intf[j].scarrier);
  981         dev->intf.intf[i].scompr= subcount(cur->intf.intf[i].scompr,
  982                                            pre->intf.intf[j].scompr);
  983 
  984         dev->intf.intf[i].type      = cur->intf.intf[i].type;
  985         dev->intf.intf[i].duplex    = cur->intf.intf[i].duplex;
  986         dev->intf.intf[i].speed     = cur->intf.intf[i].speed;
  987         dev->intf.intf[i].speedp    = pre->intf.intf[j].speed;
  988 
  989         cur->intf.intf[i].speedp    = pre->intf.intf[j].speed;
  990     }
  991 
  992     dev->intf.intf[i].name[0] = '\0';
  993     dev->intf.nrintf = i;
  994 
  995     /*
  996     ** calculate deviations for disks
  997     */
  998     for (i=j=0; cur->dsk.dsk[i].name[0]; i++)
  999     {
 1000         int realj = j;
 1001 
 1002         /*
 1003         ** check if disk has been added or removed since
 1004         ** previous interval
 1005         */
 1006         if ( strcmp(cur->dsk.dsk[i].name, pre->dsk.dsk[j].name) != 0)
 1007         {
 1008             for (j++; pre->dsk.dsk[j].name[0]; j++)
 1009             {
 1010                 if ( strcmp(cur->dsk.dsk[i].name,
 1011                         pre->dsk.dsk[j].name) == 0)
 1012                     break;
 1013             }
 1014 
 1015             /*
 1016             ** either the corresponding entry has been found
 1017             ** in the case that a disk has been removed, or
 1018             ** an empty entry has been found (all counters
 1019             ** on zero) in the case that a disk has been added
 1020             ** during the last sample
 1021             */
 1022         }
 1023 
 1024         strcpy(dev->dsk.dsk[i].name, cur->dsk.dsk[i].name);
 1025 
 1026         dev->dsk.dsk[i].nread  = subcount(cur->dsk.dsk[i].nread,
 1027                                           pre->dsk.dsk[j].nread);
 1028         dev->dsk.dsk[i].nrsect = subcount(cur->dsk.dsk[i].nrsect,
 1029                                           pre->dsk.dsk[j].nrsect);
 1030         dev->dsk.dsk[i].nwrite = subcount(cur->dsk.dsk[i].nwrite,
 1031                                           pre->dsk.dsk[j].nwrite);
 1032         dev->dsk.dsk[i].nwsect = subcount(cur->dsk.dsk[i].nwsect,
 1033                                           pre->dsk.dsk[j].nwsect);
 1034         dev->dsk.dsk[i].inflight  = cur->dsk.dsk[i].inflight;
 1035         dev->dsk.dsk[i].io_ms  = subcount(cur->dsk.dsk[i].io_ms,
 1036                                           pre->dsk.dsk[j].io_ms);
 1037         dev->dsk.dsk[i].avque  = subcount(cur->dsk.dsk[i].avque,
 1038                                           pre->dsk.dsk[j].avque);
 1039 
 1040         if (cur->dsk.dsk[i].ndisc != -1)    // discards supported?
 1041         {
 1042             dev->dsk.dsk[i].ndisc  = subcount(cur->dsk.dsk[i].ndisc,
 1043                                                   pre->dsk.dsk[j].ndisc);
 1044             dev->dsk.dsk[i].ndsect = subcount(cur->dsk.dsk[i].ndsect,
 1045                                                   pre->dsk.dsk[j].ndsect);
 1046         }
 1047         else
 1048         {
 1049             dev->dsk.dsk[i].ndisc  = -1;
 1050             dev->dsk.dsk[i].ndsect = 0;
 1051         }
 1052 
 1053         /*
 1054         ** determine new j
 1055         */
 1056         if (pre->dsk.dsk[j].name)   // existing matching entry
 1057             j++;
 1058         else
 1059             j = realj;      // empty entry: stick to old j
 1060     }
 1061 
 1062     dev->dsk.dsk[i].name[0] = '\0';
 1063     dev->dsk.ndsk = i;
 1064 
 1065     /*
 1066     ** calculate deviations for multiple devices
 1067     */
 1068     for (i=j=0; cur->dsk.mdd[i].name[0]; i++)
 1069     {
 1070         int realj = j;
 1071 
 1072         /*
 1073         ** check if md has been added or removed since
 1074         ** previous interval
 1075         */
 1076         if ( strcmp(cur->dsk.mdd[i].name, pre->dsk.mdd[j].name) != 0)
 1077         {
 1078             for (j++; pre->dsk.mdd[j].name[0]; j++)
 1079             {
 1080                 if ( strcmp(cur->dsk.mdd[i].name,
 1081                         pre->dsk.mdd[j].name) == 0)
 1082                     break;
 1083             }
 1084 
 1085             /*
 1086             ** either the corresponding entry has been found
 1087             ** in the case that a md has been removed, or
 1088             ** an empty entry has been found (all counters
 1089             ** on zero) in the case that a md has been added
 1090             ** during the last sample
 1091             */
 1092         }
 1093 
 1094         strcpy(dev->dsk.mdd[i].name, cur->dsk.mdd[i].name);
 1095 
 1096         dev->dsk.mdd[i].nread  = subcount(cur->dsk.mdd[i].nread,
 1097                                           pre->dsk.mdd[j].nread);
 1098         dev->dsk.mdd[i].nrsect = subcount(cur->dsk.mdd[i].nrsect,
 1099                                           pre->dsk.mdd[j].nrsect);
 1100         dev->dsk.mdd[i].nwrite = subcount(cur->dsk.mdd[i].nwrite,
 1101                                           pre->dsk.mdd[j].nwrite);
 1102         dev->dsk.mdd[i].nwsect = subcount(cur->dsk.mdd[i].nwsect,
 1103                                           pre->dsk.mdd[j].nwsect);
 1104         dev->dsk.mdd[i].io_ms  = subcount(cur->dsk.mdd[i].io_ms,
 1105                                           pre->dsk.mdd[j].io_ms);
 1106         dev->dsk.mdd[i].avque  = subcount(cur->dsk.mdd[i].avque,
 1107                                           pre->dsk.mdd[j].avque);
 1108 
 1109         if (cur->dsk.mdd[i].ndisc != -1)    // discards supported?
 1110         {
 1111             dev->dsk.mdd[i].ndisc  = subcount(cur->dsk.mdd[i].ndisc,
 1112                                                   pre->dsk.mdd[j].ndisc);
 1113             dev->dsk.mdd[i].ndsect = subcount(cur->dsk.mdd[i].ndsect,
 1114                                                   pre->dsk.mdd[j].ndsect);
 1115         }
 1116         else
 1117         {
 1118             dev->dsk.mdd[i].ndisc  = -1;
 1119             dev->dsk.mdd[i].ndsect = 0;
 1120         }
 1121 
 1122         /*
 1123         ** determine new j
 1124         */
 1125         if (pre->dsk.mdd[j].name)   // existing matching entry
 1126             j++;
 1127         else
 1128             j = realj;      // empty entry: stick to old j
 1129     }
 1130 
 1131     dev->dsk.mdd[i].name[0] = '\0';
 1132     dev->dsk.nmdd = i;
 1133 
 1134     /*
 1135     ** calculate deviations for LVM logical volumes
 1136     */
 1137     for (i=j=0; cur->dsk.lvm[i].name[0]; i++)
 1138     {
 1139         int realj = j;
 1140 
 1141         /*
 1142         ** check if logical volume has been added or removed since
 1143         ** previous interval
 1144         */
 1145         if ( strcmp(cur->dsk.lvm[i].name, pre->dsk.lvm[j].name) != 0)
 1146         {
 1147             for (j++; pre->dsk.lvm[j].name[0]; j++)
 1148             {
 1149                 if ( strcmp(cur->dsk.lvm[i].name,
 1150                         pre->dsk.lvm[j].name) == 0)
 1151                     break;
 1152             }
 1153 
 1154             /*
 1155             ** either the corresponding entry has been found
 1156             ** in the case that a logical volume has been removed,
 1157             ** or an empty entry has been found (all counters
 1158             ** on zero) in the case that a logical volume has
 1159             ** been added during the last sample
 1160             */
 1161         }
 1162 
 1163         strcpy(dev->dsk.lvm[i].name, cur->dsk.lvm[i].name);
 1164 
 1165         dev->dsk.lvm[i].nread  = subcount(cur->dsk.lvm[i].nread,
 1166                                           pre->dsk.lvm[j].nread);
 1167         dev->dsk.lvm[i].nrsect = subcount(cur->dsk.lvm[i].nrsect,
 1168                                           pre->dsk.lvm[j].nrsect);
 1169         dev->dsk.lvm[i].nwrite = subcount(cur->dsk.lvm[i].nwrite,
 1170                                           pre->dsk.lvm[j].nwrite);
 1171         dev->dsk.lvm[i].nwsect = subcount(cur->dsk.lvm[i].nwsect,
 1172                                           pre->dsk.lvm[j].nwsect);
 1173         dev->dsk.lvm[i].io_ms  = subcount(cur->dsk.lvm[i].io_ms,
 1174                                           pre->dsk.lvm[j].io_ms);
 1175         dev->dsk.lvm[i].avque  = subcount(cur->dsk.lvm[i].avque,
 1176                                           pre->dsk.lvm[j].avque);
 1177 
 1178         if (cur->dsk.lvm[i].ndisc != -1)    // discards supported?
 1179         {
 1180             dev->dsk.lvm[i].ndisc  = subcount(cur->dsk.lvm[i].ndisc,
 1181                                                   pre->dsk.lvm[j].ndisc);
 1182             dev->dsk.lvm[i].ndsect = subcount(cur->dsk.lvm[i].ndsect,
 1183                                                   pre->dsk.lvm[j].ndsect);
 1184         }
 1185         else
 1186         {
 1187             dev->dsk.lvm[i].ndisc  = -1;
 1188             dev->dsk.lvm[i].ndsect = 0;
 1189         }
 1190 
 1191         /*
 1192         ** determine new j
 1193         */
 1194         if (pre->dsk.lvm[j].name)   // existing matching entry
 1195             j++;
 1196         else
 1197             j = realj;      // empty entry: stick to old j
 1198     }
 1199 
 1200     dev->dsk.lvm[i].name[0] = '\0';
 1201     dev->dsk.nlvm = i;
 1202 
 1203     /*
 1204     ** calculate deviations for NFS
 1205     */
 1206     dev->nfs.server.netcnt    = subcount(cur->nfs.server.netcnt,
 1207                                          pre->nfs.server.netcnt);
 1208     dev->nfs.server.netudpcnt = subcount(cur->nfs.server.netudpcnt,
 1209                                          pre->nfs.server.netudpcnt);
 1210     dev->nfs.server.nettcpcnt = subcount(cur->nfs.server.nettcpcnt,
 1211                                          pre->nfs.server.nettcpcnt);
 1212     dev->nfs.server.nettcpcon = subcount(cur->nfs.server.nettcpcon,
 1213                                          pre->nfs.server.nettcpcon);
 1214 
 1215     dev->nfs.server.rpccnt    = subcount(cur->nfs.server.rpccnt,
 1216                                          pre->nfs.server.rpccnt);
 1217     dev->nfs.server.rpcread   = subcount(cur->nfs.server.rpcread,
 1218                                          pre->nfs.server.rpcread);
 1219     dev->nfs.server.rpcwrite  = subcount(cur->nfs.server.rpcwrite,
 1220                                          pre->nfs.server.rpcwrite);
 1221     dev->nfs.server.rpcbadfmt = subcount(cur->nfs.server.rpcbadfmt,
 1222                                          pre->nfs.server.rpcbadfmt);
 1223     dev->nfs.server.rpcbadaut = subcount(cur->nfs.server.rpcbadaut,
 1224                                          pre->nfs.server.rpcbadaut);
 1225     dev->nfs.server.rpcbadcln = subcount(cur->nfs.server.rpcbadcln,
 1226                                          pre->nfs.server.rpcbadcln);
 1227     
 1228     dev->nfs.server.rchits    = subcount(cur->nfs.server.rchits,
 1229                                          pre->nfs.server.rchits);
 1230     dev->nfs.server.rcmiss    = subcount(cur->nfs.server.rcmiss,
 1231                                          pre->nfs.server.rcmiss);
 1232     dev->nfs.server.rcnoca    = subcount(cur->nfs.server.rcnoca,
 1233                                          pre->nfs.server.rcnoca);
 1234 
 1235     dev->nfs.server.nrbytes   = subcount(cur->nfs.server.nrbytes,
 1236                                          pre->nfs.server.nrbytes);
 1237     dev->nfs.server.nwbytes   = subcount(cur->nfs.server.nwbytes,
 1238                                          pre->nfs.server.nwbytes);
 1239 
 1240     dev->nfs.client.rpccnt        = subcount(cur->nfs.client.rpccnt,
 1241                                              pre->nfs.client.rpccnt);
 1242     dev->nfs.client.rpcread       = subcount(cur->nfs.client.rpcread,
 1243                                              pre->nfs.client.rpcread);
 1244     dev->nfs.client.rpcwrite      = subcount(cur->nfs.client.rpcwrite,
 1245                                              pre->nfs.client.rpcwrite);
 1246     dev->nfs.client.rpcretrans    = subcount(cur->nfs.client.rpcretrans,
 1247                                              pre->nfs.client.rpcretrans);
 1248     dev->nfs.client.rpcautrefresh = subcount(cur->nfs.client.rpcautrefresh,
 1249                                              pre->nfs.client.rpcautrefresh);
 1250 
 1251 
 1252     for (i=j=0; i < cur->nfs.nfsmounts.nrmounts; i++, j++)
 1253     {
 1254         /*
 1255         ** check if nfsmounts have been added or removed since
 1256         ** previous interval
 1257         */
 1258         if ( strcmp(cur->nfs.nfsmounts.nfsmnt[i].mountdev,
 1259                     pre->nfs.nfsmounts.nfsmnt[j].mountdev) != 0)
 1260         {
 1261             for (j=0; j < pre->nfs.nfsmounts.nrmounts; j++)
 1262             {
 1263                 if ( strcmp(cur->nfs.nfsmounts.nfsmnt[i].mountdev,
 1264                                 pre->nfs.nfsmounts.nfsmnt[j].mountdev)
 1265                                     == 0)
 1266                     break;
 1267             }
 1268 
 1269             /*
 1270             ** either the corresponding entry has been found
 1271             ** in the case that a container has been removed,
 1272             ** or an empty entry has been found (all counters
 1273             ** on zero) in the case that a container has
 1274             ** been added during the last sample
 1275             */
 1276         }
 1277 
 1278         strcpy(dev->nfs.nfsmounts.nfsmnt[i].mountdev,
 1279                cur->nfs.nfsmounts.nfsmnt[i].mountdev);
 1280 
 1281                 dev->nfs.nfsmounts.nfsmnt[i].age = 
 1282                                     cur->nfs.nfsmounts.nfsmnt[i].age;
 1283 
 1284         if (dev->nfs.nfsmounts.nfsmnt[i].age <= interval)
 1285             memset(&(pre->nfs.nfsmounts.nfsmnt[j]), 0, 
 1286                     sizeof(struct pernfsmount));
 1287 
 1288                 dev->nfs.nfsmounts.nfsmnt[i].bytesread = 
 1289                           subcount(cur->nfs.nfsmounts.nfsmnt[i].bytesread,
 1290                                    pre->nfs.nfsmounts.nfsmnt[j].bytesread);
 1291 
 1292                 dev->nfs.nfsmounts.nfsmnt[i].byteswrite = 
 1293                           subcount(cur->nfs.nfsmounts.nfsmnt[i].byteswrite,
 1294                                    pre->nfs.nfsmounts.nfsmnt[j].byteswrite);
 1295 
 1296                 dev->nfs.nfsmounts.nfsmnt[i].bytesdread = 
 1297                           subcount(cur->nfs.nfsmounts.nfsmnt[i].bytesdread,
 1298                                    pre->nfs.nfsmounts.nfsmnt[j].bytesdread);
 1299 
 1300                 dev->nfs.nfsmounts.nfsmnt[i].bytesdwrite = 
 1301                           subcount(cur->nfs.nfsmounts.nfsmnt[i].bytesdwrite,
 1302                                    pre->nfs.nfsmounts.nfsmnt[j].bytesdwrite);
 1303 
 1304                 dev->nfs.nfsmounts.nfsmnt[i].bytestotread = 
 1305                           subcount(cur->nfs.nfsmounts.nfsmnt[i].bytestotread,
 1306                                    pre->nfs.nfsmounts.nfsmnt[j].bytestotread);
 1307 
 1308                 dev->nfs.nfsmounts.nfsmnt[i].bytestotwrite = 
 1309                           subcount(cur->nfs.nfsmounts.nfsmnt[i].bytestotwrite,
 1310                                    pre->nfs.nfsmounts.nfsmnt[j].bytestotwrite);
 1311 
 1312                 dev->nfs.nfsmounts.nfsmnt[i].pagesmread = 
 1313                           subcount(cur->nfs.nfsmounts.nfsmnt[i].pagesmread,
 1314                                    pre->nfs.nfsmounts.nfsmnt[j].pagesmread);
 1315 
 1316                 dev->nfs.nfsmounts.nfsmnt[i].pagesmwrite = 
 1317                           subcount(cur->nfs.nfsmounts.nfsmnt[i].pagesmwrite,
 1318                                    pre->nfs.nfsmounts.nfsmnt[j].pagesmwrite);
 1319     }
 1320 
 1321     dev->nfs.nfsmounts.nrmounts = cur->nfs.nfsmounts.nrmounts;
 1322 
 1323     /*
 1324     ** calculate deviations for containers
 1325     */
 1326     for (i=j=0; i < cur->cfs.nrcontainer; i++, j++)
 1327     {
 1328         /*
 1329         ** check if containers have been added or removed since
 1330         ** previous interval
 1331         */
 1332         if (cur->cfs.cont[i].ctid != pre->cfs.cont[j].ctid)
 1333         {
 1334             for (j=0; j < pre->cfs.nrcontainer; j++)
 1335             {
 1336                 if (cur->cfs.cont[i].ctid ==
 1337                         pre->cfs.cont[j].ctid)
 1338                     break;
 1339             }
 1340 
 1341             /*
 1342             ** either the corresponding entry has been found
 1343             ** in the case that a container has been removed,
 1344             ** or an empty entry has been found (all counters
 1345             ** on zero) in the case that a container has
 1346             ** been added during the last sample
 1347             */
 1348         }
 1349 
 1350         dev->cfs.cont[i].ctid    = cur->cfs.cont[i].ctid;
 1351         dev->cfs.cont[i].numproc = cur->cfs.cont[i].numproc;
 1352         dev->cfs.cont[i].physpages = cur->cfs.cont[i].physpages;
 1353 
 1354         dev->cfs.cont[i].system  = subcount(cur->cfs.cont[i].system,
 1355                                             pre->cfs.cont[j].system);
 1356         dev->cfs.cont[i].user    = subcount(cur->cfs.cont[i].user,
 1357                                             pre->cfs.cont[j].user);
 1358         dev->cfs.cont[i].nice    = subcount(cur->cfs.cont[i].nice,
 1359                                             pre->cfs.cont[j].nice);
 1360         dev->cfs.cont[i].uptime  = subcount(cur->cfs.cont[i].uptime,
 1361                                             pre->cfs.cont[j].uptime);
 1362     }
 1363 
 1364     dev->cfs.nrcontainer = cur->cfs.nrcontainer;
 1365 
 1366     /*
 1367     ** calculate deviations for GPUs
 1368     */
 1369     for (i=0; i < cur->gpu.nrgpus; i++)
 1370     {
 1371         dev->gpu.gpu[i].gpunr      = i;
 1372 
 1373         strcpy(dev->gpu.gpu[i].type,  cur->gpu.gpu[i].type);
 1374         strcpy(dev->gpu.gpu[i].busid, cur->gpu.gpu[i].busid);
 1375 
 1376         dev->gpu.gpu[i].taskstats  = cur->gpu.gpu[i].taskstats;
 1377         dev->gpu.gpu[i].nrprocs    = cur->gpu.gpu[i].nrprocs;
 1378 
 1379         dev->gpu.gpu[i].gpupercnow = cur->gpu.gpu[i].gpupercnow;
 1380         dev->gpu.gpu[i].mempercnow = cur->gpu.gpu[i].mempercnow;
 1381         dev->gpu.gpu[i].memtotnow  = cur->gpu.gpu[i].memtotnow;
 1382         dev->gpu.gpu[i].memusenow  = cur->gpu.gpu[i].memusenow;
 1383 
 1384         dev->gpu.gpu[i].samples    = subcount(cur->gpu.gpu[i].samples,
 1385                                               pre->gpu.gpu[i].samples);
 1386 
 1387         if (cur->gpu.gpu[i].gpuperccum >= 0)
 1388          dev->gpu.gpu[i].gpuperccum = subcount(cur->gpu.gpu[i].gpuperccum,
 1389                                                pre->gpu.gpu[i].gpuperccum);
 1390         else
 1391          dev->gpu.gpu[i].gpuperccum = -1;
 1392 
 1393         if (cur->gpu.gpu[i].memusecum >= 0)
 1394          dev->gpu.gpu[i].memusecum  = subcount(cur->gpu.gpu[i].memusecum,
 1395                                                pre->gpu.gpu[i].memusecum);
 1396         else
 1397          dev->gpu.gpu[i].memusecum  = -1;
 1398 
 1399         if (cur->gpu.gpu[i].memperccum >= 0)
 1400          dev->gpu.gpu[i].memperccum = subcount(cur->gpu.gpu[i].memperccum,
 1401                                                pre->gpu.gpu[i].memperccum);
 1402         else
 1403          dev->gpu.gpu[i].memperccum = -1;
 1404     }
 1405 
 1406     dev->gpu.nrgpus = cur->gpu.nrgpus;
 1407 
 1408     /*
 1409     ** calculate deviations for InfiniBand
 1410     */
 1411     for (i=0; i < cur->ifb.nrports; i++)
 1412     {
 1413         strcpy(dev->ifb.ifb[i].ibname, cur->ifb.ifb[i].ibname);
 1414 
 1415         dev->ifb.ifb[i].portnr = cur->ifb.ifb[i].portnr;
 1416         dev->ifb.ifb[i].lanes  = cur->ifb.ifb[i].lanes;
 1417         dev->ifb.ifb[i].rate   = cur->ifb.ifb[i].rate;
 1418 
 1419         dev->ifb.ifb[i].rcvb   = cur->ifb.ifb[i].rcvb -
 1420                                  pre->ifb.ifb[i].rcvb;
 1421         dev->ifb.ifb[i].sndb   = cur->ifb.ifb[i].sndb -
 1422                                  pre->ifb.ifb[i].sndb;
 1423         dev->ifb.ifb[i].rcvp   = cur->ifb.ifb[i].rcvp -
 1424                                  pre->ifb.ifb[i].rcvp;
 1425         dev->ifb.ifb[i].sndp   = cur->ifb.ifb[i].sndp -
 1426                                  pre->ifb.ifb[i].sndp;
 1427     }
 1428 
 1429     dev->ifb.nrports = cur->ifb.nrports;
 1430 
 1431     /*
 1432     ** calculate deviations for Last Level Cache
 1433     */
 1434     for (i = 0; i < cur->llc.nrllcs; i++)
 1435     {
 1436         dev->llc.perllc[i].id        = cur->llc.perllc[i].id;
 1437         dev->llc.perllc[i].occupancy = cur->llc.perllc[i].occupancy;
 1438         dev->llc.perllc[i].mbm_local = cur->llc.perllc[i].mbm_local -
 1439                            pre->llc.perllc[i].mbm_local;
 1440         dev->llc.perllc[i].mbm_total = cur->llc.perllc[i].mbm_total -
 1441                            pre->llc.perllc[i].mbm_total;
 1442     }
 1443     
 1444     dev->llc.nrllcs = cur->llc.nrllcs;
 1445 
 1446 #if HTTPSTATS
 1447     /*
 1448     ** application-specific counters
 1449     */
 1450     if (cur->www.uptime >= pre->www.uptime)
 1451     {
 1452         dev->www.accesses  = subcount(cur->www.accesses,
 1453                                               pre->www.accesses);
 1454         dev->www.totkbytes = subcount(cur->www.totkbytes,
 1455                                               pre->www.totkbytes);
 1456     }
 1457     else
 1458     {
 1459         dev->www.accesses  = cur->www.accesses;
 1460         dev->www.totkbytes = cur->www.totkbytes;
 1461     }
 1462 
 1463     dev->www.bworkers  = cur->www.bworkers;
 1464     dev->www.iworkers  = cur->www.iworkers;
 1465 #endif
 1466 }
 1467 
 1468 /*
 1469 ** add the values of a new sample to a structure holding the totals
 1470 ** for the indicated category (c=cpu, m=memory, d=disk, n=network).
 1471 */
 1472 void
 1473 totalsyst(char category, struct sstat *new, struct sstat *tot)
 1474 {
 1475     register int    i;
 1476     count_t     *ctot, *cnew;
 1477 
 1478     switch (category)
 1479     {
 1480        case 'c':    /* accumulate cpu-related counters */
 1481         tot->cpu.nrcpu      = new->cpu.nrcpu;
 1482         tot->cpu.devint    += new->cpu.devint;
 1483         tot->cpu.csw       += new->cpu.csw;
 1484         tot->cpu.nprocs    += new->cpu.nprocs;
 1485 
 1486         tot->cpu.all.stime += new->cpu.all.stime;
 1487         tot->cpu.all.utime += new->cpu.all.utime;
 1488         tot->cpu.all.ntime += new->cpu.all.ntime;
 1489         tot->cpu.all.itime += new->cpu.all.itime;
 1490         tot->cpu.all.wtime += new->cpu.all.wtime;
 1491         tot->cpu.all.Itime += new->cpu.all.Itime;
 1492         tot->cpu.all.Stime += new->cpu.all.Stime;
 1493         tot->cpu.all.steal += new->cpu.all.steal;
 1494         tot->cpu.all.guest += new->cpu.all.guest;
 1495 
 1496         if (new->cpu.nrcpu == 1)
 1497         {
 1498             tot->cpu.cpu[0] = tot->cpu.all;
 1499         }
 1500         else
 1501         {
 1502             for (i=0; i < new->cpu.nrcpu; i++)
 1503             {
 1504                 tot->cpu.cpu[i].cpunr  = new->cpu.cpu[i].cpunr;
 1505                 tot->cpu.cpu[i].stime += new->cpu.cpu[i].stime;
 1506                 tot->cpu.cpu[i].utime += new->cpu.cpu[i].utime;
 1507                 tot->cpu.cpu[i].ntime += new->cpu.cpu[i].ntime;
 1508                 tot->cpu.cpu[i].itime += new->cpu.cpu[i].itime;
 1509                 tot->cpu.cpu[i].wtime += new->cpu.cpu[i].wtime;
 1510                 tot->cpu.cpu[i].Itime += new->cpu.cpu[i].Itime;
 1511                 tot->cpu.cpu[i].Stime += new->cpu.cpu[i].Stime;
 1512                 tot->cpu.cpu[i].steal += new->cpu.cpu[i].steal;
 1513                 tot->cpu.cpu[i].guest += new->cpu.cpu[i].guest;
 1514             }
 1515         }
 1516 
 1517         tot->cpu.lavg1   = new->cpu.lavg1;
 1518         tot->cpu.lavg5   = new->cpu.lavg5;
 1519         tot->cpu.lavg15  = new->cpu.lavg15;
 1520         break;
 1521 
 1522        case 'm':    /* accumulate memory-related counters */
 1523         tot->mem.physmem     = new->mem.physmem;
 1524         tot->mem.freemem     = new->mem.freemem;
 1525         tot->mem.buffermem   = new->mem.buffermem;
 1526         tot->mem.slabmem     = new->mem.slabmem;
 1527         tot->mem.slabreclaim     = new->mem.slabreclaim;
 1528         tot->mem.committed   = new->mem.committed;
 1529         tot->mem.commitlim   = new->mem.commitlim;
 1530         tot->mem.cachemem    = new->mem.cachemem;
 1531         tot->mem.cachedrt    = new->mem.cachedrt;
 1532         tot->mem.totswap     = new->mem.totswap;
 1533         tot->mem.freeswap    = new->mem.freeswap;
 1534         tot->mem.swapcached  = new->mem.swapcached;
 1535         tot->mem.pagetables  = new->mem.pagetables;
 1536 
 1537         tot->mem.shmem       = new->mem.shmem;
 1538         tot->mem.shmrss      = new->mem.shmrss;
 1539         tot->mem.shmswp      = new->mem.shmswp;
 1540 
 1541         tot->mem.tcpsock    = new->mem.tcpsock;
 1542         tot->mem.udpsock    = new->mem.udpsock;
 1543 
 1544         tot->mem.pgouts     += new->mem.pgouts;
 1545         tot->mem.pgins      += new->mem.pgins;
 1546         tot->mem.swouts     += new->mem.swouts;
 1547         tot->mem.swins      += new->mem.swins;
 1548         tot->mem.pgscans    += new->mem.pgscans;
 1549         tot->mem.allocstall += new->mem.allocstall;
 1550         tot->mem.compactstall   += new->mem.compactstall;
 1551         break;
 1552 
 1553        case 'n':    /* accumulate network-related counters */
 1554         tot->nfs.server.rpccnt     += new->nfs.server.rpccnt;
 1555         tot->nfs.server.rpcread    += new->nfs.server.rpcread;
 1556         tot->nfs.server.rpcwrite   += new->nfs.server.rpcwrite;
 1557         tot->nfs.server.rpcbadfmt  += new->nfs.server.rpcbadfmt;
 1558         tot->nfs.server.rpcbadaut  += new->nfs.server.rpcbadaut;
 1559         tot->nfs.server.rpcbadcln  += new->nfs.server.rpcbadcln;
 1560 
 1561         tot->nfs.server.netcnt     += new->nfs.server.netcnt;
 1562         tot->nfs.server.nettcpcnt  += new->nfs.server.nettcpcnt;
 1563         tot->nfs.server.netudpcnt  += new->nfs.server.netudpcnt;
 1564         tot->nfs.server.nettcpcon  += new->nfs.server.nettcpcon;
 1565 
 1566         tot->nfs.server.rchits     += new->nfs.server.rchits;
 1567         tot->nfs.server.rcmiss     += new->nfs.server.rcmiss;
 1568         tot->nfs.server.rcnoca     += new->nfs.server.rcnoca;
 1569 
 1570         tot->nfs.server.nrbytes    += new->nfs.server.nrbytes;
 1571         tot->nfs.server.nwbytes    += new->nfs.server.nwbytes;
 1572 
 1573         tot->nfs.client.rpccnt        += new->nfs.client.rpccnt;
 1574         tot->nfs.client.rpcread       += new->nfs.client.rpcread;
 1575         tot->nfs.client.rpcwrite      += new->nfs.client.rpcwrite;
 1576         tot->nfs.client.rpcretrans    += new->nfs.client.rpcretrans;
 1577         tot->nfs.client.rpcautrefresh += new->nfs.client.rpcautrefresh;
 1578 
 1579         /*
 1580         ** other structures with network counters are considered
 1581         ** as tables of frequency-counters that will be accumulated;
 1582         ** values that do not represent a frequency are corrected
 1583         ** afterwards
 1584         */
 1585         for (ctot = (count_t *)&tot->net.ipv4,
 1586              cnew = (count_t *)&new->net.ipv4, i = 0;
 1587             i < (sizeof tot->net.ipv4 / sizeof(count_t));
 1588                     ctot++, cnew++, i++)
 1589                     *ctot += *cnew;
 1590 
 1591         tot->net.ipv4.Forwarding = new->net.ipv4.Forwarding;
 1592         tot->net.ipv4.DefaultTTL = new->net.ipv4.DefaultTTL;
 1593     
 1594             /* ------------- */
 1595     
 1596         for (ctot = (count_t *)&tot->net.icmpv4,
 1597              cnew = (count_t *)&new->net.icmpv4, i = 0;
 1598             i < (sizeof tot->net.icmpv4 / sizeof(count_t));
 1599                     ctot++, cnew++, i++)
 1600                     *ctot += *cnew;
 1601     
 1602             /* ------------- */
 1603     
 1604         for (ctot = (count_t *)&tot->net.udpv4,
 1605              cnew = (count_t *)&new->net.udpv4, i = 0;
 1606             i < (sizeof tot->net.udpv4 / sizeof(count_t));
 1607                     ctot++, cnew++, i++)
 1608                     *ctot += *cnew;
 1609     
 1610             /* ------------- */
 1611     
 1612         for (ctot = (count_t *)&tot->net.ipv6,
 1613              cnew = (count_t *)&new->net.ipv6, i = 0;
 1614             i < (sizeof tot->net.ipv6 / sizeof(count_t));
 1615                     ctot++, cnew++, i++)
 1616                     *ctot += *cnew;
 1617     
 1618             /* ------------- */
 1619     
 1620         for (ctot = (count_t *)&tot->net.icmpv6,
 1621              cnew = (count_t *)&new->net.icmpv6, i = 0;
 1622             i < (sizeof tot->net.icmpv6 / sizeof(count_t));
 1623                     ctot++, cnew++, i++)
 1624                     *ctot += *cnew;
 1625     
 1626             /* ------------- */
 1627     
 1628         for (ctot = (count_t *)&tot->net.udpv6,
 1629              cnew = (count_t *)&new->net.udpv6, i = 0;
 1630             i < (sizeof tot->net.udpv6 / sizeof(count_t));
 1631                     ctot++, cnew++, i++)
 1632                     *ctot += *cnew;
 1633     
 1634             /* ------------- */
 1635     
 1636         for (ctot = (count_t *)&tot->net.tcp,
 1637              cnew = (count_t *)&new->net.tcp, i = 0;
 1638             i < (sizeof tot->net.tcp / sizeof(count_t));
 1639                     ctot++, cnew++, i++)
 1640                     *ctot += *cnew;
 1641     
 1642         tot->net.tcp.RtoAlgorithm = new->net.tcp.RtoAlgorithm;
 1643         tot->net.tcp.RtoMin       = new->net.tcp.RtoMin;
 1644         tot->net.tcp.RtoMax       = new->net.tcp.RtoMax;
 1645         tot->net.tcp.MaxConn      = new->net.tcp.MaxConn;
 1646         tot->net.tcp.CurrEstab    = new->net.tcp.CurrEstab;
 1647     
 1648         for (i=0; new->intf.intf[i].name[0]; i++)
 1649         {
 1650             /*
 1651             ** check if an interface has been added or removed;
 1652             ** in that case, zero all counters
 1653             */
 1654             if (strcmp(new->intf.intf[i].name,
 1655                        tot->intf.intf[i].name) != 0)
 1656             {
 1657                 tot->intf.intf[i].rbyte    = 0;
 1658                 tot->intf.intf[i].rpack    = 0;
 1659                 tot->intf.intf[i].rerrs    = 0;
 1660                 tot->intf.intf[i].rdrop    = 0;
 1661                 tot->intf.intf[i].rfifo    = 0;
 1662                 tot->intf.intf[i].rframe   = 0;
 1663                 tot->intf.intf[i].rcompr   = 0;
 1664                 tot->intf.intf[i].rmultic  = 0;
 1665     
 1666                 tot->intf.intf[i].sbyte    = 0;
 1667                 tot->intf.intf[i].spack    = 0;
 1668                 tot->intf.intf[i].serrs    = 0;
 1669                 tot->intf.intf[i].sdrop    = 0;
 1670                 tot->intf.intf[i].sfifo    = 0;
 1671                 tot->intf.intf[i].scollis  = 0;
 1672                 tot->intf.intf[i].scarrier = 0;
 1673                 tot->intf.intf[i].scompr   = 0;
 1674             }
 1675     
 1676             /*
 1677             ** accumulate counters for this sample
 1678             */
 1679             strcpy(tot->intf.intf[i].name, new->intf.intf[i].name);
 1680     
 1681             tot->intf.intf[i].rbyte   += new->intf.intf[i].rbyte;
 1682             tot->intf.intf[i].rpack   += new->intf.intf[i].rpack;
 1683             tot->intf.intf[i].rerrs   += new->intf.intf[i].rerrs;
 1684             tot->intf.intf[i].rdrop   += new->intf.intf[i].rdrop;
 1685             tot->intf.intf[i].rfifo   += new->intf.intf[i].rfifo;
 1686             tot->intf.intf[i].rframe  += new->intf.intf[i].rframe;
 1687             tot->intf.intf[i].rcompr  += new->intf.intf[i].rcompr;
 1688             tot->intf.intf[i].rmultic += new->intf.intf[i].rmultic;
 1689     
 1690             tot->intf.intf[i].sbyte   += new->intf.intf[i].sbyte;
 1691             tot->intf.intf[i].spack   += new->intf.intf[i].spack;
 1692             tot->intf.intf[i].serrs   += new->intf.intf[i].serrs;
 1693             tot->intf.intf[i].sdrop   += new->intf.intf[i].sdrop;
 1694             tot->intf.intf[i].sfifo   += new->intf.intf[i].sfifo;
 1695             tot->intf.intf[i].scollis += new->intf.intf[i].scollis;
 1696             tot->intf.intf[i].scarrier+= new->intf.intf[i].scarrier;
 1697             tot->intf.intf[i].scompr  += new->intf.intf[i].scompr;
 1698     
 1699             tot->intf.intf[i].type     = new->intf.intf[i].type;
 1700             tot->intf.intf[i].speed    = new->intf.intf[i].speed;
 1701             tot->intf.intf[i].duplex   = new->intf.intf[i].duplex;
 1702         }
 1703     
 1704         tot->intf.intf[i].name[0] = '\0';
 1705         tot->intf.nrintf          = i;
 1706 
 1707 #if     HTTPSTATS
 1708         tot->www.accesses  += new->www.accesses;
 1709         tot->www.totkbytes += new->www.totkbytes;
 1710         tot->www.bworkers   = new->www.bworkers;
 1711         tot->www.iworkers   = new->www.iworkers;
 1712 #endif
 1713         break;
 1714 
 1715        case 'd':    /* accumulate disk-related counters */
 1716         for (i=0; new->dsk.dsk[i].name[0]; i++)
 1717         {
 1718             strcpy(tot->dsk.dsk[i].name, new->dsk.dsk[i].name);
 1719     
 1720             tot->dsk.dsk[i].nread  += new->dsk.dsk[i].nread;
 1721             tot->dsk.dsk[i].nrsect += new->dsk.dsk[i].nrsect;
 1722             tot->dsk.dsk[i].nwrite += new->dsk.dsk[i].nwrite;
 1723             tot->dsk.dsk[i].nwsect += new->dsk.dsk[i].nwsect;
 1724             tot->dsk.dsk[i].io_ms  += new->dsk.dsk[i].io_ms;
 1725             tot->dsk.dsk[i].avque  += new->dsk.dsk[i].avque;
 1726 
 1727             if (new->dsk.dsk[i].ndisc != -1) // discards?
 1728             {
 1729                 tot->dsk.dsk[i].ndisc  += new->dsk.dsk[i].ndisc;
 1730                 tot->dsk.dsk[i].ndsect += new->dsk.dsk[i].ndsect;
 1731             }
 1732             
 1733         }
 1734     
 1735         tot->dsk.dsk[i].name[0] = '\0';
 1736         tot->dsk.ndsk = i;
 1737 
 1738         for (i=0; new->dsk.lvm[i].name[0]; i++)
 1739         {
 1740             strcpy(tot->dsk.lvm[i].name, new->dsk.lvm[i].name);
 1741     
 1742             tot->dsk.lvm[i].nread  += new->dsk.lvm[i].nread;
 1743             tot->dsk.lvm[i].nrsect += new->dsk.lvm[i].nrsect;
 1744             tot->dsk.lvm[i].nwrite += new->dsk.lvm[i].nwrite;
 1745             tot->dsk.lvm[i].nwsect += new->dsk.lvm[i].nwsect;
 1746             tot->dsk.lvm[i].io_ms  += new->dsk.lvm[i].io_ms;
 1747             tot->dsk.lvm[i].avque  += new->dsk.lvm[i].avque;
 1748 
 1749             if (new->dsk.lvm[i].ndisc != -1) // discards?
 1750             {
 1751                 tot->dsk.lvm[i].ndisc  += new->dsk.lvm[i].ndisc;
 1752                 tot->dsk.lvm[i].ndsect += new->dsk.lvm[i].ndsect;
 1753             }
 1754         }
 1755     
 1756         tot->dsk.lvm[i].name[0] = '\0';
 1757         tot->dsk.nlvm = i;
 1758 
 1759         for (i=0; new->dsk.mdd[i].name[0]; i++)
 1760         {
 1761             strcpy(tot->dsk.mdd[i].name, new->dsk.mdd[i].name);
 1762     
 1763             tot->dsk.mdd[i].nread  += new->dsk.mdd[i].nread;
 1764             tot->dsk.mdd[i].nrsect += new->dsk.mdd[i].nrsect;
 1765             tot->dsk.mdd[i].nwrite += new->dsk.mdd[i].nwrite;
 1766             tot->dsk.mdd[i].nwsect += new->dsk.mdd[i].nwsect;
 1767             tot->dsk.mdd[i].io_ms  += new->dsk.mdd[i].io_ms;
 1768             tot->dsk.mdd[i].avque  += new->dsk.mdd[i].avque;
 1769 
 1770             if (new->dsk.mdd[i].ndisc != -1) // discards?
 1771             {
 1772                 tot->dsk.mdd[i].ndisc  += new->dsk.lvm[i].ndisc;
 1773                 tot->dsk.mdd[i].ndsect += new->dsk.lvm[i].ndsect;
 1774             }
 1775         }
 1776     
 1777         tot->dsk.mdd[i].name[0] = '\0';
 1778         tot->dsk.nmdd = i;
 1779         break;
 1780     }
 1781 }
 1782 
 1783 
 1784 /*
 1785 ** Generic function to subtract two counters taking into 
 1786 ** account the possibility that the counter is invalid
 1787 ** (i.e. non-existing).
 1788 */
 1789 static inline count_t
 1790 subcount(count_t newval, count_t oldval)
 1791 {
 1792     if (newval == -1)   // invalid counter?
 1793         return -1;
 1794 
 1795     if (newval >= oldval)   // normal situation
 1796         return newval - oldval;
 1797     else            // counter seems to be reset
 1798         return newval;
 1799 }