"Fossies" - the Fresh Open Source Software Archive

Member "atop-2.8.1/photosyst.c" (7 Jan 2023, 68592 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 "photosyst.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 read all relevant system-level
    8 ** figures.
    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-2012 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 #include <sys/types.h>
   33 #include <stdio.h>
   34 #include <string.h>
   35 #include <unistd.h>
   36 #include <stdlib.h>
   37 #include <errno.h>
   38 #include <regex.h>
   39 #include <sys/stat.h>
   40 #include <sys/times.h>
   41 #include <sys/wait.h>
   42 #include <time.h>
   43 #include <signal.h>
   44 #include <string.h>
   45 #include <dirent.h>
   46 #include <sys/ioctl.h>
   47 #include <sys/sysmacros.h>
   48 #include <limits.h>
   49 
   50 #define SCALINGMAXCPU   8   // threshold for scaling info per CPU
   51 
   52 
   53 #ifndef NOPERFEVENT
   54 #include <linux/perf_event.h>
   55 #include <asm/unistd.h>
   56 #endif
   57 
   58 #include <sys/socket.h>
   59 #include <netinet/in.h>
   60 #include <netdb.h>
   61 
   62 // #define  _GNU_SOURCE
   63 #include <sys/ipc.h>
   64 #include <sys/shm.h>
   65 
   66 #include "atop.h"
   67 #include "ifprop.h"
   68 #include "photosyst.h"
   69 
   70 #define MAXCNT  64
   71 
   72 /* return value of isdisk() */
   73 #define NONTYPE 0
   74 #define DSKTYPE 1
   75 #define MDDTYPE 2
   76 #define LVMTYPE 3
   77 
   78 /* recognize numa node */
   79 #define NUMADIR "/sys/devices/system/node"
   80 
   81 /* recognize LLC monitor data */
   82 #define LLCDIR  "/sys/fs/resctrl/mon_data"
   83 #define L3SIZE  "/sys/devices/system/cpu/cpu0/cache/index3/size"
   84 
   85 /* Refer to mmzone.h, the default is 11 */
   86 #define MAX_ORDER   11
   87 
   88 #ifndef NOPERFEVENT
   89 enum {
   90     PERF_EVENTS_AUTO = 0,
   91     PERF_EVENTS_ENABLE,
   92     PERF_EVENTS_DISABLE,
   93 };
   94 
   95 static int  perfevents = PERF_EVENTS_AUTO;
   96 static void getperfevents(struct cpustat *);
   97 #endif
   98 
   99 static int  get_infiniband(struct ifbstat *);
  100 static int  get_ksm(struct sstat *);
  101 static int  get_zswap(struct sstat *);
  102 
  103 static int  isdisk(unsigned int, unsigned int,
  104             char *, struct perdsk *, int);
  105 
  106 static struct ipv6_stats    ipv6_tmp;
  107 static struct icmpv6_stats  icmpv6_tmp;
  108 static struct udpv6_stats   udpv6_tmp;
  109 
  110 struct v6tab {
  111     char    *nam;
  112     count_t *val;
  113 };
  114 
  115 static struct v6tab         v6tab[] = {
  116     {"Ip6InReceives",       &ipv6_tmp.Ip6InReceives,                     },
  117     {"Ip6InHdrErrors",      &ipv6_tmp.Ip6InHdrErrors,                    },
  118     {"Ip6InTooBigErrors",   &ipv6_tmp.Ip6InTooBigErrors,                 },
  119     {"Ip6InNoRoutes",       &ipv6_tmp.Ip6InNoRoutes,                     },
  120     {"Ip6InAddrErrors",     &ipv6_tmp.Ip6InAddrErrors,                   },
  121     {"Ip6InUnknownProtos",  &ipv6_tmp.Ip6InUnknownProtos,                },
  122     {"Ip6InTruncatedPkts",  &ipv6_tmp.Ip6InTruncatedPkts,                },
  123     {"Ip6InDiscards",       &ipv6_tmp.Ip6InDiscards,                     },
  124     {"Ip6InDelivers",       &ipv6_tmp.Ip6InDelivers,                     },
  125     {"Ip6OutForwDatagrams", &ipv6_tmp.Ip6OutForwDatagrams,               },
  126     {"Ip6OutRequests",      &ipv6_tmp.Ip6OutRequests,                    },
  127     {"Ip6OutDiscards",      &ipv6_tmp.Ip6OutDiscards,                    },
  128     {"Ip6OutNoRoutes",      &ipv6_tmp.Ip6OutNoRoutes,                    },
  129     {"Ip6ReasmTimeout",     &ipv6_tmp.Ip6ReasmTimeout,                   },
  130     {"Ip6ReasmReqds",       &ipv6_tmp.Ip6ReasmReqds,                     },
  131     {"Ip6ReasmOKs",     &ipv6_tmp.Ip6ReasmOKs,                       },
  132     {"Ip6ReasmFails",       &ipv6_tmp.Ip6ReasmFails,                     },
  133     {"Ip6FragOKs",      &ipv6_tmp.Ip6FragOKs,                        },
  134     {"Ip6FragFails",        &ipv6_tmp.Ip6FragFails,                      },
  135     {"Ip6FragCreates",      &ipv6_tmp.Ip6FragCreates,                    },
  136     {"Ip6InMcastPkts",      &ipv6_tmp.Ip6InMcastPkts,                    },
  137     {"Ip6OutMcastPkts",     &ipv6_tmp.Ip6OutMcastPkts,                   },
  138  
  139     {"Icmp6InMsgs",     &icmpv6_tmp.Icmp6InMsgs,                     },
  140     {"Icmp6InErrors",       &icmpv6_tmp.Icmp6InErrors,                   },
  141     {"Icmp6InDestUnreachs", &icmpv6_tmp.Icmp6InDestUnreachs,             },
  142     {"Icmp6InPktTooBigs",   &icmpv6_tmp.Icmp6InPktTooBigs,               },
  143     {"Icmp6InTimeExcds",    &icmpv6_tmp.Icmp6InTimeExcds,                },
  144     {"Icmp6InParmProblems", &icmpv6_tmp.Icmp6InParmProblems,             },
  145     {"Icmp6InEchos",        &icmpv6_tmp.Icmp6InEchos,                    },
  146     {"Icmp6InEchoReplies",  &icmpv6_tmp.Icmp6InEchoReplies,              },
  147     {"Icmp6InGroupMembQueries", &icmpv6_tmp.Icmp6InGroupMembQueries,         },
  148     {"Icmp6InGroupMembResponses",
  149                 &icmpv6_tmp.Icmp6InGroupMembResponses,       },
  150     {"Icmp6InGroupMembReductions",
  151                 &icmpv6_tmp.Icmp6InGroupMembReductions,      },
  152     {"Icmp6InRouterSolicits",   &icmpv6_tmp.Icmp6InRouterSolicits,           },
  153     {"Icmp6InRouterAdvertisements",
  154                 &icmpv6_tmp.Icmp6InRouterAdvertisements,     },
  155     {"Icmp6InNeighborSolicits", &icmpv6_tmp.Icmp6InNeighborSolicits,         },
  156     {"Icmp6InNeighborAdvertisements",
  157                 &icmpv6_tmp.Icmp6InNeighborAdvertisements,   },
  158     {"Icmp6InRedirects",    &icmpv6_tmp.Icmp6InRedirects,                },
  159     {"Icmp6OutMsgs",        &icmpv6_tmp.Icmp6OutMsgs,                    },
  160     {"Icmp6OutDestUnreachs",    &icmpv6_tmp.Icmp6OutDestUnreachs,            },
  161     {"Icmp6OutPktTooBigs",  &icmpv6_tmp.Icmp6OutPktTooBigs,              },
  162     {"Icmp6OutTimeExcds",   &icmpv6_tmp.Icmp6OutTimeExcds,               },
  163     {"Icmp6OutParmProblems",    &icmpv6_tmp.Icmp6OutParmProblems,            },
  164     {"Icmp6OutEchoReplies", &icmpv6_tmp.Icmp6OutEchoReplies,             },
  165     {"Icmp6OutRouterSolicits",  &icmpv6_tmp.Icmp6OutRouterSolicits,          },
  166     {"Icmp6OutNeighborSolicits",&icmpv6_tmp.Icmp6OutNeighborSolicits,        },
  167     {"Icmp6OutNeighborAdvertisements",
  168                 &icmpv6_tmp.Icmp6OutNeighborAdvertisements,  },
  169     {"Icmp6OutRedirects",   &icmpv6_tmp.Icmp6OutRedirects,               },
  170     {"Icmp6OutGroupMembResponses",
  171                 &icmpv6_tmp.Icmp6OutGroupMembResponses,      },
  172     {"Icmp6OutGroupMembReductions",
  173                 &icmpv6_tmp.Icmp6OutGroupMembReductions,     },
  174 
  175     {"Udp6InDatagrams",     &udpv6_tmp.Udp6InDatagrams,                   },
  176     {"Udp6NoPorts",     &udpv6_tmp.Udp6NoPorts,                       },
  177     {"Udp6InErrors",        &udpv6_tmp.Udp6InErrors,                      },
  178     {"Udp6OutDatagrams",    &udpv6_tmp.Udp6OutDatagrams,                  },
  179 };
  180 
  181 static int  v6tab_entries = sizeof(v6tab)/sizeof(struct v6tab);
  182 
  183 // The following values are used to accumulate cpu statistics per numa.
  184 // The bitmask realization is from numactl
  185 #define CPUMASK_SZ (64 * 8)
  186 
  187 #define bitsperlong (8 * sizeof(unsigned long))
  188 #define howmany(x,y) (((x)+((y)-1))/(y))
  189 #define longsperbits(n) howmany(n, bitsperlong)
  190 
  191 #define round_up(x,y) (((x) + (y) - 1) & ~((y)-1))
  192 #define BITS_PER_LONG (sizeof(unsigned long) * 8)
  193 #define CPU_BYTES(x) (round_up(x, BITS_PER_LONG)/8)
  194 #define CPU_LONGS(x) (CPU_BYTES(x) / sizeof(long))
  195 
  196 struct bitmask {
  197     unsigned long size; /* number of bits in the map */
  198     unsigned long long *maskp;
  199 };
  200 
  201 /*
  202  * Allocate a bitmask for cpus, of a size large enough to
  203  * match the kernel's cpumask_t.
  204  */
  205 struct bitmask *
  206 numa_allocate_cpumask()
  207 {
  208     int ncpus = CPUMASK_SZ;
  209     struct bitmask *bmp;
  210 
  211     bmp = malloc(sizeof(*bmp));
  212     if (!bmp)
  213         ptrverify(bmp, "Malloc failed for numa bitmask");
  214 
  215     bmp->size = ncpus;
  216     bmp->maskp = calloc(longsperbits(ncpus), sizeof(unsigned long));
  217     ptrverify((bmp->maskp), "Malloc failed for numa maskp");
  218 
  219     return bmp;
  220 }
  221 
  222 void
  223 numa_bitmask_free(struct bitmask *bmp)
  224 {
  225     if (bmp == 0)
  226         return;
  227     free(bmp->maskp);
  228     bmp->maskp = (unsigned long long *)0xdeadcdef;  /* double free tripwire */
  229     free(bmp);
  230     return;
  231 }
  232 
  233 int
  234 numa_parse_bitmap_v2(char *line, struct bitmask *mask)
  235 {
  236     int i;
  237     char *p = strchr(line, '\n');
  238     if (!p)
  239         return -1;
  240     int ncpus = mask->size;
  241 
  242     for (i = 0; p > line;i++) {
  243         char *oldp, *endp;
  244         oldp = p;
  245         if (*p == ',')
  246             --p;
  247         while (p > line && *p != ',')
  248             --p;
  249         /* Eat two 32bit fields at a time to get longs */
  250         if (p > line && sizeof(unsigned long) == 8) {
  251             oldp--;
  252             memmove(p, p+1, oldp-p+1);
  253             while (p > line && *p != ',')
  254                 --p;
  255         }
  256         if (*p == ',')
  257             p++;
  258         if (i >= CPU_LONGS(ncpus))
  259             return -1;
  260         mask->maskp[i] = strtoul(p, &endp, 16);
  261         if (endp != oldp)
  262             return -1;
  263         p--;
  264     }
  265     return 0;
  266 }
  267 
  268 void
  269 photosyst(struct sstat *si)
  270 {
  271     static char part_stats = 1; /* per-partition statistics ? */
  272     static char ib_stats = 1;   /* InfiniBand statistics ? */
  273     static char ksm_stats = 1;  
  274     static char zswap_stats = 1;
  275 
  276     register int    i, nr, j;
  277     count_t     cnts[MAXCNT];
  278     float       lavg1, lavg5, lavg15;
  279     FILE        *fp;
  280     DIR     *dirp;
  281     struct dirent   *dentry;
  282     char        linebuf[1024], nam[64], origdir[1024];
  283     unsigned int    major, minor;
  284     struct shm_info shminfo;
  285 #if HTTPSTATS
  286     static int  wwwvalid = 1;
  287 #endif
  288 
  289     memset(si, 0, sizeof(struct sstat));
  290 
  291     if ( getcwd(origdir, sizeof origdir) == NULL)
  292         mcleanstop(54, "failed to save current dir\n");
  293 
  294     if ( chdir("/proc") == -1)
  295         mcleanstop(54, "failed to change to /proc\n");
  296 
  297     /*
  298     ** gather various general statistics from the file /proc/stat and
  299     ** store them in binary form
  300     */
  301     if ( (fp = fopen("stat", "r")) != NULL)
  302     {
  303         while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
  304         {
  305             nr = sscanf(linebuf,
  306                         "%s   %lld %lld %lld %lld %lld %lld %lld "
  307                         "%lld %lld %lld %lld %lld %lld %lld %lld ",
  308                 nam,
  309                 &cnts[0],  &cnts[1],  &cnts[2],  &cnts[3],
  310                 &cnts[4],  &cnts[5],  &cnts[6],  &cnts[7],
  311                 &cnts[8],  &cnts[9],  &cnts[10], &cnts[11],
  312                 &cnts[12], &cnts[13], &cnts[14]);
  313 
  314             if (nr < 2)     /* headerline ? --> skip */
  315                 continue;
  316 
  317             if ( strcmp("cpu", nam) == EQ)
  318             {
  319                 si->cpu.all.utime   = cnts[0];
  320                 si->cpu.all.ntime   = cnts[1];
  321                 si->cpu.all.stime   = cnts[2];
  322                 si->cpu.all.itime   = cnts[3];
  323 
  324                 if (nr > 5) /* 2.6 kernel? */
  325                 {
  326                     si->cpu.all.wtime   = cnts[4];
  327                     si->cpu.all.Itime   = cnts[5];
  328                     si->cpu.all.Stime   = cnts[6];
  329 
  330                     if (nr > 8) /* steal support */
  331                         si->cpu.all.steal = cnts[7];
  332 
  333                     if (nr > 9) /* guest support */
  334                         si->cpu.all.guest = cnts[8];
  335                 }
  336                 continue;
  337             }
  338 
  339             if ( strncmp("cpu", nam, 3) == EQ)
  340             {
  341                 i = atoi(&nam[3]);
  342 
  343                 if (i >= MAXCPU)
  344                 {
  345                     fprintf(stderr,
  346                         "cpu %s exceeds maximum of %d\n",
  347                         nam, MAXCPU);
  348                     continue;
  349                 }
  350 
  351                 si->cpu.cpu[i].cpunr    = i;
  352                 si->cpu.cpu[i].utime    = cnts[0];
  353                 si->cpu.cpu[i].ntime    = cnts[1];
  354                 si->cpu.cpu[i].stime    = cnts[2];
  355                 si->cpu.cpu[i].itime    = cnts[3];
  356 
  357                 if (nr > 5) /* 2.6 kernel? */
  358                 {
  359                     si->cpu.cpu[i].wtime    = cnts[4];
  360                     si->cpu.cpu[i].Itime    = cnts[5];
  361                     si->cpu.cpu[i].Stime    = cnts[6];
  362 
  363                     if (nr > 8) /* steal support */
  364                         si->cpu.cpu[i].steal = cnts[7];
  365 
  366                     if (nr > 9) /* guest support */
  367                         si->cpu.cpu[i].guest = cnts[8];
  368                 }
  369 
  370                 si->cpu.nrcpu++;
  371                 continue;
  372             }
  373 
  374             if ( strcmp("ctxt", nam) == EQ)
  375             {
  376                 si->cpu.csw = cnts[0];
  377                 continue;
  378             }
  379 
  380             if ( strcmp("intr", nam) == EQ)
  381             {
  382                 si->cpu.devint  = cnts[0];
  383                 continue;
  384             }
  385 
  386             if ( strcmp("processes", nam) == EQ)
  387             {
  388                 si->cpu.nprocs  = cnts[0];
  389                 continue;
  390             }
  391 
  392             if ( strcmp("swap", nam) == EQ)   /* < 2.6 */
  393             {
  394                 si->mem.swins   = cnts[0];
  395                 si->mem.swouts  = cnts[1];
  396                 continue;
  397             }
  398         }
  399 
  400         fclose(fp);
  401 
  402         if (si->cpu.nrcpu == 0)
  403             si->cpu.nrcpu = 1;
  404     }
  405 
  406     /*
  407     ** gather loadaverage values from the file /proc/loadavg and
  408     ** store them in binary form
  409     */
  410     if ( (fp = fopen("loadavg", "r")) != NULL)
  411     {
  412         if ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
  413         {
  414             if ( sscanf(linebuf, "%f %f %f",
  415                 &lavg1, &lavg5, &lavg15) == 3)
  416             {
  417                 si->cpu.lavg1   = lavg1;
  418                 si->cpu.lavg5   = lavg5;
  419                 si->cpu.lavg15  = lavg15;
  420             }
  421         }
  422 
  423         fclose(fp);
  424     }
  425 
  426     /*
  427     ** gather frequency scaling info.
  428         ** sources (in order of preference): 
  429         **     /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state
  430         ** or
  431         **     /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
  432         **     /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
  433         **
  434     ** store them in binary form
  435     */
  436         static char fn[512];
  437         int didone=0;
  438 
  439     if (si->cpu.nrcpu <= SCALINGMAXCPU)
  440     {
  441             for (i = 0; i < si->cpu.nrcpu; ++i)
  442             {
  443                 long long f=0;
  444 
  445                 snprintf(fn, sizeof fn,
  446                    "/sys/devices/system/cpu/cpu%d/cpufreq/stats/time_in_state",
  447                    i);
  448 
  449                 if ((fp=fopen(fn, "r")) != 0)
  450                 {
  451                         long long hits=0;
  452                         long long maxfreq=0;
  453                         long long cnt=0;
  454                         long long sum=0;
  455 
  456                         while (fscanf(fp, "%lld %lld", &f, &cnt) == 2)
  457                         {
  458                                 f   /= 1000;
  459                                 sum     += (f*cnt);
  460                                 hits    += cnt;
  461 
  462                                 if (f > maxfreq)
  463                                 maxfreq=f;
  464                             didone=1;
  465                         }
  466 
  467                     si->cpu.cpu[i].freqcnt.maxfreq  = maxfreq;
  468                     si->cpu.cpu[i].freqcnt.cnt  = sum;
  469                     si->cpu.cpu[i].freqcnt.ticks    = hits;
  470 
  471                         fclose(fp);
  472                 }
  473         else
  474         {    // governor statistics not available
  475                      snprintf(fn, sizeof fn, 
  476                       "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq",
  477               i);
  478 
  479                         if ((fp=fopen(fn, "r")) != 0)
  480                         {
  481                                 if (fscanf(fp, "%lld", &f) == 1)
  482                                 {
  483                     // convert KHz to MHz
  484                                     si->cpu.cpu[i].freqcnt.maxfreq =f/1000; 
  485                                 }
  486 
  487                                 fclose(fp);
  488                         }
  489                         else 
  490                         {
  491                             si->cpu.cpu[i].freqcnt.maxfreq=0;
  492                         }
  493 
  494                        snprintf(fn, sizeof fn,
  495                        "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq",
  496                i);
  497         
  498                         if ((fp=fopen(fn, "r")) != 0)
  499                         {
  500                                 if (fscanf(fp, "%lld", &f) == 1)
  501                                 {
  502                     // convert KHz to MHz
  503                                         si->cpu.cpu[i].freqcnt.cnt   = f/1000;
  504                                         si->cpu.cpu[i].freqcnt.ticks = 0;
  505                                         didone=1;
  506                                 }
  507 
  508                                 fclose(fp);
  509                         }
  510                         else
  511                         {
  512                                 si->cpu.cpu[i].freqcnt.cnt  = 0;
  513                                 si->cpu.cpu[i].freqcnt.ticks    = 0;
  514                         }
  515                 }
  516             } // for all CPUs
  517     }
  518 
  519         if (!didone)     // did not get processor freq statistics.
  520                          // use /proc/cpuinfo
  521         {
  522             if ( (fp = fopen("cpuinfo", "r")) != NULL)
  523                 {
  524                         // get information from the lines
  525                         // processor\t: 0
  526                         // cpu MHz\t\t: 800.000
  527                         
  528                         int cpuno=-1;
  529 
  530                 while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
  531                         {
  532                                 if (memcmp(linebuf, "processor", 9)== EQ)
  533                     sscanf(linebuf, "%*s %*s %d", &cpuno);
  534 
  535                                 if (memcmp(linebuf, "cpu MHz", 7) == EQ)
  536                 {
  537                                         if (cpuno >= 0 && cpuno < si->cpu.nrcpu)
  538                     {
  539                         sscanf(linebuf,
  540                             "%*s %*s %*s %lld",
  541                                                 &(si->cpu.cpu[cpuno].freqcnt.cnt));
  542                     }
  543                                 }
  544                         }
  545 
  546             fclose(fp);
  547                 }
  548 
  549         }
  550 
  551     /*
  552     ** gather virtual memory statistics from the file /proc/vmstat and
  553     ** store them in binary form (>= kernel 2.6)
  554     */
  555     si->mem.oomkills     = -1;
  556 
  557     si->mem.allocstall   = 0;
  558     si->mem.numamigrate  = 0;
  559     si->mem.pgmigrate    = 0;
  560 
  561     if ( (fp = fopen("vmstat", "r")) != NULL)
  562     {
  563         while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
  564         {
  565             nr = sscanf(linebuf, "%s %lld", nam, &cnts[0]);
  566 
  567             if (nr < 2)     /* headerline ? --> skip */
  568                 continue;
  569 
  570             /* pgpgin & pgpgout fields in KB from vmstat */
  571             if ( strcmp("pgpgin", nam) == EQ)
  572             {
  573                 si->mem.pgins   = cnts[0] * 1024 / pagesize;
  574                 continue;
  575             }
  576 
  577             if ( strcmp("pgpgout", nam) == EQ)
  578             {
  579                 si->mem.pgouts   = cnts[0] * 1024 / pagesize;
  580                 continue;
  581             }
  582 
  583             if ( strcmp("pswpin", nam) == EQ)
  584             {
  585                 si->mem.swins   = cnts[0];
  586                 continue;
  587             }
  588 
  589             if ( strcmp("pswpout", nam) == EQ)
  590             {
  591                 si->mem.swouts  = cnts[0];
  592                 continue;
  593             }
  594 
  595             if ( strncmp("pgscan_", nam, 7) == EQ)
  596             {
  597                 si->mem.pgscans += cnts[0];
  598                 continue;
  599             }
  600 
  601             if ( strncmp("pgsteal_", nam, 8) == EQ)
  602             {
  603                 si->mem.pgsteal += cnts[0];
  604                 continue;
  605             }
  606 
  607             // more counters might start with "allocstall"
  608             if ( memcmp("allocstall", nam, 10) == EQ)
  609             {
  610                 si->mem.allocstall += cnts[0];
  611                 continue;
  612             }
  613 
  614             if ( strcmp("oom_kill", nam) == EQ)
  615             {
  616                 si->mem.oomkills = cnts[0];
  617                 continue;
  618             }
  619 
  620             if ( strcmp("compact_stall", nam) == EQ) {
  621                 si->mem.compactstall = cnts[0];
  622                 continue;
  623             }
  624 
  625             if ( strcmp("numa_pages_migrated", nam) == EQ) {
  626                 si->mem.numamigrate = cnts[0];
  627                 continue;
  628             }
  629 
  630             if ( strcmp("pgmigrate_success", nam) == EQ) {
  631                 si->mem.pgmigrate = cnts[0];
  632                 continue;
  633             }
  634         }
  635 
  636         fclose(fp);
  637     }
  638 
  639     /*
  640     ** gather memory-related statistics from the file /proc/meminfo and
  641     ** store them in binary form
  642     **
  643     ** in the file /proc/meminfo a 2.4 kernel starts with two lines
  644     ** headed by the strings "Mem:" and "Swap:" containing all required
  645     ** fields, except proper value for page cache
  646         ** if these lines are present we try to skip parsing the rest
  647     ** of the lines; if these lines are not present we should get the
  648     ** required field from other lines
  649     */
  650     si->mem.physmem     = (count_t)-1; 
  651     si->mem.freemem     = (count_t)-1;
  652     si->mem.buffermem   = (count_t)-1;
  653     si->mem.cachemem    = (count_t)-1;
  654     si->mem.slabmem     = (count_t) 0;
  655     si->mem.slabreclaim = (count_t) 0;
  656     si->mem.shmem       = (count_t) 0;
  657     si->mem.totswap     = (count_t)-1;
  658     si->mem.freeswap    = (count_t)-1;
  659     si->mem.swapcached  = (count_t) 0;
  660     si->mem.committed   = (count_t) 0;
  661     si->mem.pagetables  = (count_t) 0;
  662 
  663     if ( (fp = fopen("meminfo", "r")) != NULL)
  664     {
  665         while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
  666         {
  667             nr = sscanf(linebuf,
  668                 "%s %lld %lld %lld %lld %lld %lld %lld "
  669                     "%lld %lld %lld\n",
  670                 nam,
  671                 &cnts[0],  &cnts[1],  &cnts[2],  &cnts[3],
  672                 &cnts[4],  &cnts[5],  &cnts[6],  &cnts[7],
  673                 &cnts[8],  &cnts[9]);
  674 
  675             if (nr < 2)     /* headerline ? --> skip */
  676                 continue;
  677 
  678             if ( strcmp("Mem:", nam) == EQ)
  679             {
  680                 si->mem.physmem     = cnts[0] / pagesize; 
  681                 si->mem.freemem     = cnts[2] / pagesize;
  682                 si->mem.buffermem   = cnts[4] / pagesize;
  683             }
  684             else    if ( strcmp("Swap:", nam) == EQ)
  685                 {
  686                     si->mem.totswap  = cnts[0] / pagesize;
  687                     si->mem.freeswap = cnts[2] / pagesize;
  688                 }
  689             else    if (strcmp("Cached:", nam) == EQ)
  690                 {
  691                     if (si->mem.cachemem  == (count_t)-1)
  692                     {
  693                         si->mem.cachemem  =
  694                             cnts[0]*1024/pagesize;
  695                     }
  696                 }
  697             else    if (strcmp("Dirty:", nam) == EQ)
  698                 {
  699                     si->mem.cachedrt  =
  700                             cnts[0]*1024/pagesize;
  701                 }
  702             else    if (strcmp("MemTotal:", nam) == EQ)
  703                 {
  704                     if (si->mem.physmem  == (count_t)-1)
  705                     {
  706                         si->mem.physmem  =
  707                             cnts[0]*1024/pagesize;
  708                     }
  709                 }
  710             else    if (strcmp("MemFree:", nam) == EQ)
  711                 {
  712                     if (si->mem.freemem  == (count_t)-1)
  713                     {
  714                         si->mem.freemem  =
  715                             cnts[0]*1024/pagesize;
  716                     }
  717                 }
  718             else    if (strcmp("Buffers:", nam) == EQ)
  719                 {
  720                     if (si->mem.buffermem  == (count_t)-1)
  721                     {
  722                         si->mem.buffermem  =
  723                             cnts[0]*1024/pagesize;
  724                     }
  725                 }
  726             else    if (strcmp("Shmem:", nam) == EQ)
  727                 {
  728                     si->mem.shmem = cnts[0]*1024/pagesize;
  729                 }
  730             else    if (strcmp("SwapTotal:", nam) == EQ)
  731                 {
  732                     if (si->mem.totswap  == (count_t)-1)
  733                     {
  734                         si->mem.totswap  =
  735                             cnts[0]*1024/pagesize;
  736                     }
  737                 }
  738             else    if (strcmp("SwapFree:", nam) == EQ)
  739                 {
  740                     if (si->mem.freeswap  == (count_t)-1)
  741                     {
  742                         si->mem.freeswap  =
  743                             cnts[0]*1024/pagesize;
  744                     }
  745                 }
  746             else    if (strcmp("SwapCached:", nam) == EQ)
  747                 {
  748                     si->mem.swapcached  =
  749                             cnts[0]*1024/pagesize;
  750                 }
  751             else    if (strcmp("Slab:", nam) == EQ)
  752                 {
  753                     si->mem.slabmem = cnts[0]*1024/pagesize;
  754                 }
  755             else    if (strcmp("SReclaimable:", nam) == EQ)
  756                 {
  757                     si->mem.slabreclaim = cnts[0]*1024/
  758                                 pagesize;
  759                 }
  760             else    if (strcmp("Committed_AS:", nam) == EQ)
  761                 {
  762                     si->mem.committed = cnts[0]*1024/
  763                                 pagesize;
  764                 }
  765             else    if (strcmp("CommitLimit:", nam) == EQ)
  766                 {
  767                     si->mem.commitlim = cnts[0]*1024/
  768                                 pagesize;
  769                 }
  770             else    if (strcmp("HugePages_Total:", nam) == EQ)
  771                 {
  772                     si->mem.tothugepage = cnts[0];
  773                 }
  774             else    if (strcmp("HugePages_Free:", nam) == EQ)
  775                 {
  776                     si->mem.freehugepage = cnts[0];
  777                 }
  778             else    if (strcmp("Hugepagesize:", nam) == EQ)
  779                 {
  780                     si->mem.hugepagesz = cnts[0]*1024;
  781                 }
  782             else    if (strcmp("PageTables:", nam) == EQ)
  783                 {
  784                     si->mem.pagetables = cnts[0]*1024/
  785                                 pagesize;
  786                 }
  787         }
  788 
  789         fclose(fp);
  790     }
  791 
  792     /*
  793     ** gather vmware-related statistics from /sys/kernel/debug/vmmemctl
  794     ** (only present if balloon driver enabled) or from /proc/vmmemctl
  795     ** for older balloon driver implementations
  796     */ 
  797     si->mem.vmwballoon = (count_t) -1;
  798 
  799     if ( (fp = fopen("/sys/kernel/debug/vmmemctl", "r")) != NULL ||
  800          (fp = fopen("/proc/vmmemctl",             "r")) != NULL   )
  801     {
  802         while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
  803         {
  804             nr = sscanf(linebuf, "%s %lld ", nam, &cnts[0]);
  805 
  806             if ( strcmp("current:", nam) == EQ)
  807             {
  808                 si->mem.vmwballoon = cnts[0];
  809                 break;
  810             }
  811         }
  812 
  813         fclose(fp);
  814     }
  815 
  816     /*
  817     ** ZFSonlinux: gather size of ARC cache in memory
  818     ** searching for:
  819     **  size       4    519101312
  820     */ 
  821     si->mem.zfsarcsize = (count_t) -1;
  822 
  823     if ( (fp = fopen("spl/kstat/zfs/arcstats", "r")) != NULL)
  824     {
  825         while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
  826         {
  827             nr = sscanf(linebuf,
  828                 "%s %lld %lld", nam, &cnts[0], &cnts[1]);
  829 
  830             if (nr < 3)
  831                 continue;
  832 
  833             if ( strcmp("size", nam) == EQ)
  834             {
  835                 si->mem.zfsarcsize = cnts[1] / pagesize;
  836                 break;
  837             }
  838         }
  839 
  840         fclose(fp);
  841     }
  842 
  843     /*
  844     ** gather per numa memory-related statistics from the file
  845     ** /sys/devices/system/node/node0/meminfo, and store them in binary form.
  846     */
  847     dirp = opendir(NUMADIR);
  848 
  849     if (dirp)
  850     {
  851         /*
  852         ** read every directory-entry and search for all numa nodes
  853         */
  854         while ( (dentry = readdir(dirp)) )
  855         {
  856             if (strncmp(dentry->d_name, "node", 4))
  857                 continue;
  858 
  859             j = strtoul(dentry->d_name + 4, NULL, 0);
  860 
  861             if (j >= MAXNUMA)   // too many NUMA nodes?
  862                 continue;   // skip (no break, because order unknown)
  863 
  864             si->memnuma.nrnuma++;
  865 
  866             snprintf(fn, sizeof fn, NUMADIR "/%s/meminfo", dentry->d_name);
  867 
  868             if ( (fp = fopen(fn, "r")) != NULL)
  869             {
  870                 while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
  871                 {
  872                     nr = sscanf(&linebuf[5],
  873                         "%lld %s %lld\n",
  874                         &cnts[0], nam, &cnts[1]);
  875 
  876                     if (cnts[0] != j)
  877                         continue;
  878 
  879                     si->memnuma.numa[j].numanr = j;
  880                     if ( strcmp("MemTotal:", nam) == EQ)
  881                         si->memnuma.numa[j].totmem = cnts[1]*1024/pagesize;
  882                     else if ( strcmp("MemFree:", nam) == EQ)
  883                         si->memnuma.numa[j].freemem = cnts[1]*1024/pagesize;
  884                     else if ( strcmp("FilePages:", nam) == EQ)
  885                         si->memnuma.numa[j].filepage = cnts[1]*1024/pagesize;
  886                     else if ( strcmp("Active:", nam) == EQ)
  887                         si->memnuma.numa[j].active = cnts[1]*1024/pagesize;
  888                     else if ( strcmp("Inactive:", nam) == EQ)
  889                         si->memnuma.numa[j].inactive = cnts[1]*1024/pagesize;
  890                     else if ( strcmp("Dirty:", nam) == EQ)
  891                         si->memnuma.numa[j].dirtymem = cnts[1]*1024/pagesize;
  892                     else if ( strcmp("Shmem:", nam) == EQ)
  893                         si->memnuma.numa[j].shmem = cnts[1]*1024/pagesize;
  894                     else if ( strcmp("Slab:", nam) == EQ)
  895                         si->memnuma.numa[j].slabmem = cnts[1]*1024/pagesize;
  896                     else if ( strcmp("SReclaimable:", nam) == EQ)
  897                         si->memnuma.numa[j].slabreclaim = cnts[1]*1024/pagesize;
  898                     else if ( strcmp("HugePages_Total:", nam) == EQ)
  899                         si->memnuma.numa[j].tothp = cnts[1];
  900                 }
  901                 fclose(fp);
  902             }
  903         }
  904         closedir(dirp);
  905     }
  906 
  907     /* gather fragmentation level for per numa, only for 'Normal' */
  908     if (si->memnuma.nrnuma > 0)
  909     {
  910         char tmp[64];
  911         float frag[MAX_ORDER];
  912 
  913         /* If kernel CONFIG_COMPACTION is enabled, get the percentage directly */
  914         if ( (fp = fopen("/sys/kernel/debug/extfrag/unusable_index", "r")) != NULL )
  915         {
  916             while ( fgets(linebuf, sizeof(linebuf), fp) != NULL )
  917             {
  918                 nr = sscanf(&linebuf[5],
  919                     "%lld, %s %s %f %f %f %f %f %f %f %f %f %f %f\n",
  920                     &cnts[0], tmp, nam, &frag[0], &frag[1], &frag[2],
  921                     &frag[3], &frag[4], &frag[5], &frag[6], &frag[7],
  922                     &frag[8], &frag[9], &frag[10]);
  923 
  924                 if ( nr < 3 || strcmp("Normal", nam) != 0 )
  925                     continue;
  926 
  927                 for (i = 0; i < MAX_ORDER; i++)
  928                     si->memnuma.numa[cnts[0]].frag += frag[i];
  929 
  930                 si->memnuma.numa[cnts[0]].frag /= MAX_ORDER;
  931             }
  932             fclose(fp);
  933         }
  934         /* If CONFIG_COMPACTION is not enabled, calculate from buddyinfo file */
  935         else if ( (fp = fopen("/proc/buddyinfo", "r")) != NULL )
  936         {
  937             count_t free_page[MAX_ORDER];
  938             count_t total_free, prev_free;
  939             float total_frag;
  940 
  941             while ( fgets(linebuf, sizeof(linebuf), fp) != NULL )
  942             {
  943                 nr = sscanf(&linebuf[5],
  944                     "%lld, %s %s %lld %lld %lld %lld %lld "
  945                     "%lld %lld %lld %lld %lld %lld\n",
  946                     &cnts[0], tmp, nam, &cnts[1], &cnts[2], &cnts[3],
  947                     &cnts[4], &cnts[5], &cnts[6], &cnts[7], &cnts[8],
  948                     &cnts[9], &cnts[10], &cnts[11]);
  949 
  950                 if (nr < 3 || strcmp("Normal", nam) != 0 )
  951                     continue;
  952 
  953                 /* get free pages numbers for each order, and total free pages */
  954                 total_free = 0;
  955                 total_frag = 0.00;
  956                 for (i = 0; i < MAX_ORDER; i++)
  957                 {
  958                     free_page[i] = cnts[i+1] << i;
  959                     total_free += free_page[i];
  960                 }
  961                 /* get fragmentation level for each order, then summarize */
  962                 for (i = 0; i < MAX_ORDER; i++)
  963                 {
  964                     prev_free = 0;
  965                     for (j = 0; j < i; j++)
  966                         prev_free += free_page[j];
  967                     total_frag += (float)prev_free/total_free;
  968                 }
  969 
  970                 if (cnts[0] < MAXNUMA)
  971                     si->memnuma.numa[cnts[0]].frag = total_frag/MAX_ORDER;
  972             }
  973             fclose(fp);
  974         }
  975     }
  976 
  977     /*
  978     ** accumulate each cpu statistic for per NUMA, and identify numa/cpu
  979     ** relationship from /sys/devices/system/node/node0/cpumap.
  980     */
  981     if (si->memnuma.nrnuma > 1)
  982     {
  983         char *line = NULL;
  984         size_t len = 0;
  985         struct bitmask *mask;
  986 
  987         mask = numa_allocate_cpumask();
  988 
  989         si->cpunuma.nrnuma = si->memnuma.nrnuma;
  990 
  991         for (j=0; j < si->cpunuma.nrnuma; j++)
  992         {
  993             snprintf(fn, sizeof fn, NUMADIR "/node%d/cpumap", j);
  994 
  995             if ( (fp = fopen(fn, "r")) != 0)
  996             {
  997                 if ( getdelim(&line, &len, '\n', fp) > 0 )
  998                 {
  999                     if (numa_parse_bitmap_v2(line, mask) < 0)
 1000                     {
 1001                         mcleanstop(54, "failed to parse numa bitmap\n");
 1002                     }
 1003                 }
 1004                 fclose(fp);
 1005             }
 1006 
 1007             for (i=0; i < mask->size; i++)
 1008             {
 1009                 if ( (mask->maskp[i/bitsperlong] >> (i % bitsperlong)) & 1 )
 1010                 {
 1011                     si->cpunuma.numa[j].nrcpu++;
 1012                     si->cpunuma.numa[j].utime += si->cpu.cpu[i].utime;
 1013                     si->cpunuma.numa[j].ntime += si->cpu.cpu[i].ntime;
 1014                     si->cpunuma.numa[j].stime += si->cpu.cpu[i].stime;
 1015                     si->cpunuma.numa[j].itime += si->cpu.cpu[i].itime;
 1016                     si->cpunuma.numa[j].wtime += si->cpu.cpu[i].wtime;
 1017                     si->cpunuma.numa[j].Itime += si->cpu.cpu[i].Itime;
 1018                     si->cpunuma.numa[j].Stime += si->cpu.cpu[i].Stime;
 1019                     si->cpunuma.numa[j].steal += si->cpu.cpu[i].steal;
 1020                     si->cpunuma.numa[j].guest += si->cpu.cpu[i].guest;
 1021                 }
 1022             }
 1023             si->cpunuma.numa[j].numanr = j;
 1024         }
 1025 
 1026         free(line);
 1027         numa_bitmask_free(mask);
 1028     }
 1029     else
 1030     {
 1031         si->cpunuma.nrnuma = 0;
 1032     }
 1033 
 1034     /*
 1035     ** gather network-related statistics
 1036     **  - interface stats from the file /proc/net/dev
 1037     **  - IPv4      stats from the file /proc/net/snmp
 1038     **  - IPv6      stats from the file /proc/net/snmp6
 1039     **  - sock mem  stats from the file /proc/net/sockstat
 1040     */
 1041 
 1042     /*
 1043     ** interface statistics
 1044     */
 1045     initifprop();   // periodically refresh interface properties
 1046 
 1047     if ( (fp = fopen("net/dev", "r")) != NULL)
 1048     {
 1049         struct ifprop ifprop;
 1050         char *cp;
 1051 
 1052         i = 0;
 1053 
 1054         while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 1055         {
 1056             if ( (cp = strchr(linebuf, ':')) != NULL)
 1057                 *cp = ' ';      /* substitute ':' by space */
 1058 
 1059             nr = sscanf(linebuf,
 1060                                     "%15s %lld %lld %lld %lld %lld %lld %lld "
 1061                                     "%lld %lld %lld %lld %lld %lld %lld %lld "
 1062                                     "%lld\n",
 1063                   si->intf.intf[i].name,
 1064                 &(si->intf.intf[i].rbyte),
 1065                 &(si->intf.intf[i].rpack),
 1066                 &(si->intf.intf[i].rerrs),
 1067                 &(si->intf.intf[i].rdrop),
 1068                 &(si->intf.intf[i].rfifo),
 1069                 &(si->intf.intf[i].rframe),
 1070                 &(si->intf.intf[i].rcompr),
 1071                 &(si->intf.intf[i].rmultic),
 1072                 &(si->intf.intf[i].sbyte),
 1073                 &(si->intf.intf[i].spack),
 1074                 &(si->intf.intf[i].serrs),
 1075                 &(si->intf.intf[i].sdrop),
 1076                 &(si->intf.intf[i].sfifo),
 1077                 &(si->intf.intf[i].scollis),
 1078                 &(si->intf.intf[i].scarrier),
 1079                 &(si->intf.intf[i].scompr));
 1080 
 1081             /*
 1082             ** skip header line and lines without stats
 1083             */
 1084             if (nr != 17)
 1085                 continue;
 1086 
 1087             /*
 1088             ** skip interfaces that are invalidated
 1089             ** (mainly virtual interfaces)
 1090             ** because the total number of interfaces
 1091             ** exceeds the maximum supported by atop (MAXINTF)
 1092             */
 1093             strcpy(ifprop.name, si->intf.intf[i].name);
 1094 
 1095             if (!getifprop(&ifprop))
 1096                 continue;
 1097 
 1098             /*
 1099             ** accept this interface but skip the remaining
 1100             ** interfaces because we reached the total number
 1101             ** of interfaces supported by atop (MAXINTF)
 1102             */
 1103             if (++i >= MAXINTF-1)
 1104                 break;
 1105         }
 1106 
 1107         si->intf.intf[i].name[0] = '\0'; /* set terminator for table */
 1108         si->intf.nrintf = i;
 1109 
 1110         fclose(fp);
 1111     }
 1112 
 1113     /*
 1114     ** IP version 4 statistics
 1115     */
 1116     if ( (fp = fopen("net/snmp", "r")) != NULL)
 1117     {
 1118         while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 1119         {
 1120             nr = sscanf(linebuf,
 1121              "%s   %lld %lld %lld %lld %lld %lld %lld %lld %lld "
 1122              "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld "
 1123              "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld "
 1124              "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld "
 1125              "%lld\n",
 1126                 nam,
 1127                 &cnts[0],  &cnts[1],  &cnts[2],  &cnts[3],
 1128                 &cnts[4],  &cnts[5],  &cnts[6],  &cnts[7],
 1129                 &cnts[8],  &cnts[9],  &cnts[10], &cnts[11],
 1130                 &cnts[12], &cnts[13], &cnts[14], &cnts[15],
 1131                 &cnts[16], &cnts[17], &cnts[18], &cnts[19],
 1132                 &cnts[20], &cnts[21], &cnts[22], &cnts[23],
 1133                 &cnts[24], &cnts[25], &cnts[26], &cnts[27],
 1134                 &cnts[28], &cnts[29], &cnts[30], &cnts[31],
 1135                 &cnts[32], &cnts[33], &cnts[34], &cnts[35],
 1136                 &cnts[36], &cnts[37], &cnts[38], &cnts[39]);
 1137 
 1138             if (nr < 2)     /* headerline ? --> skip */
 1139                 continue;
 1140 
 1141             if ( strcmp("Ip:", nam) == 0)
 1142             {
 1143                 memcpy(&si->net.ipv4, cnts,
 1144                         sizeof si->net.ipv4);
 1145                 continue;
 1146             }
 1147     
 1148             if ( strcmp("Icmp:", nam) == 0)
 1149             {
 1150                 memcpy(&si->net.icmpv4, cnts,
 1151                         sizeof si->net.icmpv4);
 1152                 continue;
 1153             }
 1154     
 1155             if ( strcmp("Tcp:", nam) == 0)
 1156             {
 1157                 memcpy(&si->net.tcp, cnts,
 1158                         sizeof si->net.tcp);
 1159                 continue;
 1160             }
 1161     
 1162             if ( strcmp("Udp:", nam) == 0)
 1163             {
 1164                 memcpy(&si->net.udpv4, cnts,
 1165                         sizeof si->net.udpv4);
 1166                 continue;
 1167             }
 1168         }
 1169     
 1170         fclose(fp);
 1171     }
 1172 
 1173     /*
 1174     ** IP version 6 statistics
 1175     */
 1176     memset(&ipv6_tmp,   0, sizeof ipv6_tmp);
 1177     memset(&icmpv6_tmp, 0, sizeof icmpv6_tmp);
 1178     memset(&udpv6_tmp,  0, sizeof udpv6_tmp);
 1179 
 1180     if ( (fp = fopen("net/snmp6", "r")) != NULL)
 1181     {
 1182         count_t countval;
 1183         int cur = 0;
 1184 
 1185         /*
 1186         ** one name-value pair per line
 1187         */
 1188         while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 1189         {
 1190             nr = sscanf(linebuf, "%s %lld", nam, &countval);
 1191 
 1192             if (nr < 2)     /* unexpected line ? --> skip */
 1193                 continue;
 1194 
 1195             if (strcmp(v6tab[cur].nam, nam) == 0)
 1196             {
 1197                 *(v6tab[cur].val) = countval;
 1198             }
 1199             else
 1200             {
 1201                 for (cur=0; cur < v6tab_entries; cur++)
 1202                     if (strcmp(v6tab[cur].nam, nam) == 0)
 1203                         break;
 1204 
 1205                 if (cur < v6tab_entries) /* found ? */
 1206                     *(v6tab[cur].val) = countval;
 1207             }
 1208 
 1209             if (++cur >= v6tab_entries)
 1210                 cur = 0;
 1211         }
 1212 
 1213         memcpy(&si->net.ipv6,   &ipv6_tmp,   sizeof ipv6_tmp);
 1214         memcpy(&si->net.icmpv6, &icmpv6_tmp, sizeof icmpv6_tmp);
 1215         memcpy(&si->net.udpv6,  &udpv6_tmp,  sizeof udpv6_tmp);
 1216 
 1217         fclose(fp);
 1218     }
 1219 
 1220     /*
 1221     ** IP version 4: TCP & UDP memory allocations.
 1222     */
 1223     if ( (fp = fopen("net/sockstat", "r")) != NULL)
 1224     {
 1225         char tcpmem[16], udpmem[16];
 1226 
 1227         while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 1228         {
 1229             nr = sscanf(linebuf,
 1230                 "%15s %*s %*d %s %lld %*s %*d %*s %*d %s %lld\n",
 1231                 nam, udpmem, &cnts[0], tcpmem, &cnts[1]);
 1232 
 1233             if ( strcmp("TCP:", nam) == 0)
 1234             {
 1235                 if ( strcmp("mem", tcpmem) == 0) {
 1236                     si->mem.tcpsock = cnts[1];
 1237                 }
 1238                 continue;
 1239             }
 1240 
 1241             if ( strcmp("UDP:", nam) == 0)
 1242             {
 1243                 if ( strcmp("mem", udpmem) == 0) {
 1244                     si->mem.udpsock = cnts[0];
 1245                 }
 1246                 continue;
 1247             }
 1248         }
 1249         fclose(fp);
 1250     }
 1251 
 1252     /*
 1253     ** check if extended partition-statistics are provided < kernel 2.6
 1254     */
 1255     if ( part_stats && (fp = fopen("partitions", "r")) != NULL)
 1256     {
 1257         char diskname[256];
 1258 
 1259         i = 0;
 1260 
 1261         while ( fgets(linebuf, sizeof(linebuf), fp) )
 1262         {
 1263             nr = sscanf(linebuf,
 1264                   "%*d %*d %*d %255s %lld %*d %lld %*d "
 1265                   "%lld %*d %lld %*d %lld %lld %lld",
 1266                     diskname,
 1267                 &(si->dsk.dsk[i].nread),
 1268                 &(si->dsk.dsk[i].nrsect),
 1269                 &(si->dsk.dsk[i].nwrite),
 1270                 &(si->dsk.dsk[i].nwsect),
 1271                 &(si->dsk.dsk[i].inflight),
 1272                 &(si->dsk.dsk[i].io_ms),
 1273                 &(si->dsk.dsk[i].avque) );
 1274 
 1275             /*
 1276             ** check if this line concerns the entire disk
 1277             ** or just one of the partitions of a disk (to be
 1278             ** skipped)
 1279             */
 1280             if (nr == 8)    /* full stats-line ? */
 1281             {
 1282                 if ( isdisk(0, 0, diskname,
 1283                                  &(si->dsk.dsk[i]),
 1284                          MAXDKNAM) != DSKTYPE)
 1285                        continue;
 1286             
 1287                 if (++i >= MAXDSK-1)
 1288                     break;
 1289             }
 1290         }
 1291 
 1292         si->dsk.dsk[i].name[0] = '\0'; /* set terminator for table */
 1293         si->dsk.ndsk = i;
 1294 
 1295         fclose(fp);
 1296 
 1297         if (i == 0)
 1298             part_stats = 0; /* do not try again for next cycles */
 1299     }
 1300 
 1301 
 1302     /*
 1303     ** check if disk-statistics are provided (kernel 2.6 onwards)
 1304     */
 1305     if ( (fp = fopen("diskstats", "r")) != NULL)
 1306     {
 1307         char        diskname[256];
 1308         struct perdsk   tmpdsk;
 1309 
 1310         si->dsk.ndsk = 0;
 1311         si->dsk.nmdd = 0;
 1312         si->dsk.nlvm = 0;
 1313 
 1314         while ( fgets(linebuf, sizeof(linebuf), fp) )
 1315         {
 1316             /* discards are not supported in older kernels */
 1317             tmpdsk.ndisc = -1;
 1318 
 1319             nr = sscanf(linebuf,
 1320                   "%d %d %255s "        // ident
 1321                               "%lld %*d %lld %*d "  // reads
 1322                   "%lld %*d %lld %*d "  // writes
 1323                   "%lld %lld %lld "     // misc
 1324                   "%lld %*d %lld %*d",  // discards
 1325                 &major, &minor, diskname,
 1326                 &tmpdsk.nread,  &tmpdsk.nrsect,
 1327                 &tmpdsk.nwrite, &tmpdsk.nwsect,
 1328                 &tmpdsk.inflight, &tmpdsk.io_ms, &tmpdsk.avque,
 1329                 &tmpdsk.ndisc,  &tmpdsk.ndsect);
 1330 
 1331             if (nr >= 10)   /* full stats-line ? */
 1332             {
 1333                 /*
 1334                 ** when no transfers issued, skip disk (partition)
 1335                 */
 1336                 if (tmpdsk.nread + tmpdsk.nwrite +
 1337                      (tmpdsk.ndisc == -1 ? 0 : tmpdsk.ndisc) == 0)
 1338                     continue;
 1339 
 1340                 /*
 1341                 ** check if this line concerns the entire disk
 1342                 ** or just one of the partitions of a disk (to be
 1343                 ** skipped)
 1344                 */
 1345                 switch ( isdisk(major, minor, diskname,
 1346                              &tmpdsk, MAXDKNAM) )
 1347                 {
 1348                    case NONTYPE:
 1349                        continue;
 1350 
 1351                    case DSKTYPE:
 1352                     if (si->dsk.ndsk < MAXDSK-1)
 1353                       si->dsk.dsk[si->dsk.ndsk++] = tmpdsk;
 1354                     break;
 1355 
 1356                    case MDDTYPE:
 1357                     if (si->dsk.nmdd < MAXMDD-1)
 1358                       si->dsk.mdd[si->dsk.nmdd++] = tmpdsk;
 1359                     break;
 1360 
 1361                    case LVMTYPE:
 1362                     if (si->dsk.nlvm < MAXLVM-1)
 1363                       si->dsk.lvm[si->dsk.nlvm++] = tmpdsk;
 1364                     break;
 1365                 }
 1366             }
 1367         }
 1368 
 1369         /*
 1370         ** set terminator for table
 1371         */
 1372         si->dsk.dsk[si->dsk.ndsk].name[0] = '\0';
 1373         si->dsk.mdd[si->dsk.nmdd].name[0] = '\0';
 1374         si->dsk.lvm[si->dsk.nlvm].name[0] = '\0'; 
 1375 
 1376         fclose(fp);
 1377     }
 1378 
 1379     /*
 1380     ** get information about the shared memory statistics
 1381     */
 1382     if ( shmctl(0, SHM_INFO, (struct shmid_ds *)&shminfo) != -1)
 1383     {
 1384         si->mem.shmrss = shminfo.shm_rss;
 1385         si->mem.shmswp = shminfo.shm_swp;
 1386     }
 1387 
 1388     /*
 1389     ** NFS server statistics
 1390     */
 1391     if ( (fp = fopen("net/rpc/nfsd", "r")) != NULL)
 1392     {
 1393         char    label[32];
 1394         count_t cnt[40];
 1395 
 1396         /*
 1397         ** every line starts with a small label,
 1398         ** followed by upto 60 counters
 1399         */
 1400         while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 1401         {
 1402             memset(cnt, 0, sizeof cnt);
 1403 
 1404             nr = sscanf(linebuf, "%31s %lld %lld %lld %lld %lld"
 1405                                       "%lld %lld %lld %lld %lld"
 1406                                       "%lld %lld %lld %lld %lld"
 1407                                       "%lld %lld %lld %lld %lld"
 1408                                       "%lld %lld %lld %lld %lld"
 1409                                       "%lld %lld %lld %lld %lld"
 1410                                       "%lld %lld %lld %lld %lld"
 1411                                       "%lld %lld %lld %lld %lld",
 1412                         label,
 1413                         &cnt[0],  &cnt[1],  &cnt[2],  &cnt[3],
 1414                         &cnt[4],  &cnt[5],  &cnt[6],  &cnt[7],
 1415                         &cnt[8],  &cnt[9],  &cnt[10], &cnt[11],
 1416                         &cnt[12], &cnt[13], &cnt[14], &cnt[15],
 1417                         &cnt[16], &cnt[17], &cnt[18], &cnt[19],
 1418                         &cnt[20], &cnt[21], &cnt[22], &cnt[23],
 1419                         &cnt[24], &cnt[25], &cnt[26], &cnt[27],
 1420                         &cnt[28], &cnt[29], &cnt[30], &cnt[31],
 1421                         &cnt[32], &cnt[33], &cnt[34], &cnt[35],
 1422                         &cnt[36], &cnt[37], &cnt[38], &cnt[39]);
 1423 
 1424             if (nr < 2)     // unexpected empty line ?
 1425                 continue;
 1426 
 1427             if (strcmp(label, "rc") == 0)
 1428             {
 1429                 si->nfs.server.rchits = cnt[0];
 1430                 si->nfs.server.rcmiss = cnt[1];
 1431                 si->nfs.server.rcnoca = cnt[2];
 1432 
 1433                 continue;
 1434             }
 1435 
 1436             if (strcmp(label, "io") == 0)
 1437             {
 1438                 si->nfs.server.nrbytes = cnt[0];
 1439                 si->nfs.server.nwbytes = cnt[1];
 1440 
 1441                 continue;
 1442             }
 1443 
 1444             if (strcmp(label, "net") == 0)
 1445             {
 1446                 si->nfs.server.netcnt    = cnt[0];
 1447                 si->nfs.server.netudpcnt = cnt[1];
 1448                 si->nfs.server.nettcpcnt = cnt[2];
 1449                 si->nfs.server.nettcpcon = cnt[3];
 1450 
 1451                 continue;
 1452             }
 1453 
 1454             if (strcmp(label, "rpc") == 0)
 1455             {
 1456                 si->nfs.server.rpccnt    = cnt[0];
 1457                 si->nfs.server.rpcbadfmt = cnt[1];
 1458                 si->nfs.server.rpcbadaut = cnt[2];
 1459                 si->nfs.server.rpcbadcln = cnt[3];
 1460 
 1461                 continue;
 1462             }
 1463             //
 1464             // first counter behind 'proc..' is number of
 1465             // counters that follow
 1466             if (strcmp(label, "proc2") == 0)
 1467             {
 1468                 si->nfs.server.rpcread  += cnt[7]; // offset+1
 1469                 si->nfs.server.rpcwrite += cnt[9]; // offset+1
 1470                 continue;
 1471             }
 1472             if (strcmp(label, "proc3") == 0)
 1473             {
 1474                 si->nfs.server.rpcread  += cnt[7]; // offset+1
 1475                 si->nfs.server.rpcwrite += cnt[8]; // offset+1
 1476                 continue;
 1477             }
 1478             if (strcmp(label, "proc4ops") == 0)
 1479             {
 1480                 si->nfs.server.rpcread  += cnt[26]; // offset+1
 1481                 si->nfs.server.rpcwrite += cnt[39]; // offset+1
 1482                 continue;
 1483             }
 1484         }
 1485 
 1486         fclose(fp);
 1487     }
 1488 
 1489     /*
 1490     ** NFS client statistics
 1491     */
 1492     if ( (fp = fopen("net/rpc/nfs", "r")) != NULL)
 1493     {
 1494         char    label[32];
 1495         count_t cnt[10];
 1496 
 1497         /*
 1498         ** every line starts with a small label,
 1499         ** followed by counters
 1500         */
 1501         while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 1502         {
 1503             memset(cnt, 0, sizeof cnt);
 1504 
 1505             nr = sscanf(linebuf, "%31s %lld %lld %lld %lld %lld"
 1506                                       "%lld %lld %lld %lld %lld",
 1507                         label,
 1508                         &cnt[0], &cnt[1], &cnt[2], &cnt[3],
 1509                         &cnt[4], &cnt[5], &cnt[6], &cnt[7],
 1510                         &cnt[8], &cnt[9]);
 1511 
 1512             if (nr < 2)     // unexpected empty line ?
 1513                 continue;
 1514 
 1515             if (strcmp(label, "rpc") == 0)
 1516             {
 1517                 si->nfs.client.rpccnt        = cnt[0];
 1518                 si->nfs.client.rpcretrans    = cnt[1];
 1519                 si->nfs.client.rpcautrefresh = cnt[2];
 1520                 continue;
 1521             }
 1522 
 1523             // first counter behind 'proc..' is number of
 1524             // counters that follow
 1525             if (strcmp(label, "proc2") == 0)
 1526             {
 1527                 si->nfs.client.rpcread  += cnt[7]; // offset+1
 1528                 si->nfs.client.rpcwrite += cnt[9]; // offset+1
 1529                 continue;
 1530             }
 1531             if (strcmp(label, "proc3") == 0)
 1532             {
 1533                 si->nfs.client.rpcread  += cnt[7]; // offset+1
 1534                 si->nfs.client.rpcwrite += cnt[8]; // offset+1
 1535                 continue;
 1536             }
 1537             if (strcmp(label, "proc4") == 0)
 1538             {
 1539                 si->nfs.client.rpcread  += cnt[2]; // offset+1
 1540                 si->nfs.client.rpcwrite += cnt[3]; // offset+1
 1541                 continue;
 1542             }
 1543         }
 1544 
 1545         fclose(fp);
 1546     }
 1547 
 1548     /*
 1549     ** NFS client: per-mount statistics
 1550     */
 1551     regainrootprivs();
 1552 
 1553     if ( (fp = fopen("self/mountstats", "r")) != NULL)
 1554     {
 1555         char    mountdev[128], fstype[32], label[32];
 1556                 count_t cnt[8];
 1557 
 1558         i = 0;
 1559 
 1560         while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 1561         {
 1562             // if 'device' line, just remember the mounted device
 1563             if (sscanf(linebuf,
 1564                 "device %127s mounted on %*s with fstype %31s",
 1565                 mountdev, fstype) == 2)
 1566             {
 1567                 continue;
 1568             }
 1569 
 1570             if (memcmp(fstype, "nfs", 3) != 0)
 1571                 continue;
 1572 
 1573             // this is line with NFS client stats
 1574             nr = sscanf(linebuf,
 1575                                 "%31s %lld %lld %lld %lld %lld %lld %lld %lld",
 1576                 label, &cnt[0], &cnt[1], &cnt[2], &cnt[3],
 1577                        &cnt[4], &cnt[5], &cnt[6], &cnt[7]);
 1578 
 1579             if (nr >= 2 )
 1580             {
 1581                 if (strcmp(label, "age:") == 0)
 1582                 {
 1583                     strcpy(si->nfs.nfsmounts.nfsmnt[i].mountdev,
 1584                            mountdev);
 1585 
 1586                     si->nfs.nfsmounts.nfsmnt[i].age = cnt[0];
 1587                 }
 1588 
 1589                 if (strcmp(label, "bytes:") == 0)
 1590                 {
 1591                     si->nfs.nfsmounts.nfsmnt[i].bytesread =
 1592                                     cnt[0];
 1593                     si->nfs.nfsmounts.nfsmnt[i].byteswrite =
 1594                                     cnt[1];
 1595                     si->nfs.nfsmounts.nfsmnt[i].bytesdread =
 1596                                     cnt[2];
 1597                     si->nfs.nfsmounts.nfsmnt[i].bytesdwrite =
 1598                                     cnt[3];
 1599                     si->nfs.nfsmounts.nfsmnt[i].bytestotread =
 1600                                     cnt[4];
 1601                     si->nfs.nfsmounts.nfsmnt[i].bytestotwrite =
 1602                                     cnt[5];
 1603                     si->nfs.nfsmounts.nfsmnt[i].pagesmread =
 1604                                     cnt[6];
 1605                     si->nfs.nfsmounts.nfsmnt[i].pagesmwrite =
 1606                                     cnt[7];
 1607 
 1608                     if (++i >= MAXNFSMOUNT-1)
 1609                     break;
 1610                 }
 1611             }
 1612         }
 1613 
 1614         si->nfs.nfsmounts.nrmounts = i;
 1615 
 1616         fclose(fp);
 1617     }
 1618 
 1619     if (! droprootprivs())
 1620         mcleanstop(42, "failed to drop root privs\n");
 1621 
 1622     /*
 1623     ** pressure statistics in /proc/pressure (>= 4.20)
 1624     **
 1625     ** cpu:      some avg10=0.00 avg60=1.37 avg300=3.73 total=30995960
 1626     ** io:       some avg10=0.00 avg60=8.83 avg300=22.86 total=141658568
 1627     ** io:       full avg10=0.00 avg60=8.33 avg300=21.56 total=133129045
 1628     ** memory:   some avg10=0.00 avg60=0.74 avg300=1.67 total=10663184
 1629     ** memory:   full avg10=0.00 avg60=0.45 avg300=0.94 total=6461782
 1630     **
 1631     ** verify if pressure stats supported by this system
 1632     */
 1633     if ( chdir("pressure") == 0)
 1634     {
 1635         struct psi  psitemp;
 1636         char        psitype;
 1637         char        psiformat[] =
 1638                 "%c%*s avg10=%f avg60=%f avg300=%f total=%llu";
 1639 
 1640         si->psi.present = 1;
 1641 
 1642         if ( (fp = fopen("cpu", "r")) != NULL)
 1643         {
 1644             if ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 1645             {
 1646                 nr = sscanf(linebuf, psiformat,
 1647                             &psitype,
 1648                     &psitemp.avg10, &psitemp.avg60,
 1649                     &psitemp.avg300, &psitemp.total);
 1650 
 1651                 if (nr == 5)    // complete line ?
 1652                     memmove(&(si->psi.cpusome), &psitemp,
 1653                                 sizeof psitemp);
 1654             }
 1655             fclose(fp);
 1656         }
 1657 
 1658         if ( (fp = fopen("memory", "r")) != NULL)
 1659         {
 1660             while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 1661             {
 1662                 nr = sscanf(linebuf, psiformat,
 1663                             &psitype,
 1664                     &psitemp.avg10, &psitemp.avg60,
 1665                     &psitemp.avg300, &psitemp.total);
 1666 
 1667                 if (nr == 5)
 1668                 {
 1669                     if (psitype == 's')
 1670                         memmove(&(si->psi.memsome),
 1671                             &psitemp,
 1672                             sizeof psitemp);
 1673                     else
 1674                         memmove(&(si->psi.memfull),
 1675                             &psitemp,
 1676                             sizeof psitemp);
 1677                 }
 1678             }
 1679             fclose(fp);
 1680         }
 1681 
 1682         if ( (fp = fopen("io", "r")) != NULL)
 1683         {
 1684             while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 1685             {
 1686                 nr = sscanf(linebuf, psiformat,
 1687                             &psitype,
 1688                     &psitemp.avg10, &psitemp.avg60,
 1689                     &psitemp.avg300, &psitemp.total);
 1690 
 1691                 if (nr == 5)
 1692                 {
 1693                     if (psitype == 's')
 1694                         memmove(&(si->psi.iosome),
 1695                             &psitemp,
 1696                             sizeof psitemp);
 1697                     else
 1698                         memmove(&(si->psi.iofull),
 1699                             &psitemp,
 1700                             sizeof psitemp);
 1701                 }
 1702             }
 1703             fclose(fp);
 1704         }
 1705 
 1706         if ( chdir("..") == -1)
 1707             mcleanstop(54, "failed to return to /proc\n");
 1708     }
 1709     else
 1710     {
 1711         si->psi.present = 0;
 1712     }
 1713 
 1714     /*
 1715     ** Container statistics (if any)
 1716     */
 1717     if ( (fp = fopen("user_beancounters", "r")) != NULL)
 1718     {
 1719         unsigned long   ctid;
 1720         char        label[32];
 1721         count_t     cnt;
 1722 
 1723         i = -1;
 1724 
 1725         /*
 1726         ** lines introducing a new container have an extra
 1727         ** field with the container id at the beginning.
 1728         */
 1729         while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 1730         {
 1731             nr = sscanf(linebuf, "%lu: %31s %lld",
 1732                                 &ctid, label, &cnt);
 1733 
 1734             if (nr == 3)        // new container ?
 1735             {
 1736                 if (++i >= MAXCONTAINER)
 1737                     break;
 1738 
 1739                 si->cfs.cont[i].ctid = ctid;
 1740             }
 1741             else
 1742             {
 1743                 nr = sscanf(linebuf, "%31s %lld", label, &cnt);
 1744 
 1745                 if (nr != 2)
 1746                     continue;
 1747             }
 1748 
 1749             if (i == -1)    // no container defined yet
 1750                 continue;
 1751 
 1752             if (strcmp(label, "numproc") == 0)
 1753             {
 1754                 si->cfs.cont[i].numproc = cnt;
 1755                 continue;
 1756             }
 1757 
 1758             if (strcmp(label, "physpages") == 0)
 1759             {
 1760                 si->cfs.cont[i].physpages = cnt;
 1761                 continue;
 1762             }
 1763         }
 1764 
 1765         fclose(fp);
 1766 
 1767         si->cfs.nrcontainer = i+1;
 1768 
 1769         if ( (fp = fopen("vz/vestat", "r")) != NULL)
 1770         {
 1771             unsigned long   ctid;
 1772             count_t     cnt[8];
 1773 
 1774             /*
 1775             ** relevant lines start with container id
 1776             */
 1777             while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 1778             {
 1779                 nr = sscanf(linebuf, "%lu  %lld %lld %lld %lld"
 1780                                          "%lld %lld %lld %lld %lld",
 1781                             &ctid,
 1782                     &cnt[0], &cnt[1], &cnt[2], &cnt[3],
 1783                             &cnt[4], &cnt[5], &cnt[6], &cnt[7],
 1784                     &cnt[8]);
 1785 
 1786                 if (nr < 9) // irrelevant contents
 1787                     continue;
 1788 
 1789                 // relevant stats: search for containerid
 1790                 for (i=0; i < si->cfs.nrcontainer; i++)
 1791                 {
 1792                     if (si->cfs.cont[i].ctid == ctid)
 1793                         break;
 1794                 }
 1795 
 1796                 if (i >= si->cfs.nrcontainer)
 1797                     continue;   // container not found
 1798 
 1799                 si->cfs.cont[i].user   = cnt[0];
 1800                 si->cfs.cont[i].nice   = cnt[1];
 1801                 si->cfs.cont[i].system = cnt[2];
 1802                 si->cfs.cont[i].uptime = cnt[3];
 1803             }
 1804 
 1805             fclose(fp);
 1806         }
 1807     }
 1808 
 1809     /*
 1810     ** gather per LLC related statistics from the file
 1811     ** /sys/fs/resctrl/mon_data/mon_L3_XX
 1812     */
 1813     dirp = opendir(LLCDIR);
 1814 
 1815     if (dirp)
 1816     {
 1817         static int l3_cache_size;
 1818 
 1819         if (!l3_cache_size)
 1820         {
 1821             if ( (fp = fopen(L3SIZE, "r")) != NULL)
 1822             {
 1823                 if ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 1824                 {
 1825                     sscanf(linebuf, "%uK\n", &l3_cache_size);
 1826                     l3_cache_size *= 1024;
 1827                 }
 1828 
 1829                 fclose(fp);
 1830             }
 1831         }
 1832 
 1833         /*
 1834         ** walk the LLC directory, gather each LLC
 1835         */
 1836         while ( (dentry = readdir(dirp)) )
 1837         {
 1838             struct perllc *llc = &si->llc.perllc[si->llc.nrllcs];
 1839             unsigned long llc_occupancy;
 1840 
 1841             if (strncmp(dentry->d_name, "mon_L3_", 7))
 1842                 continue;
 1843 
 1844             /* get cache id from directory name like mon_L3_00 */
 1845             sscanf(dentry->d_name + 7, "%hhd\n", &llc->id);
 1846 
 1847             snprintf(fn, sizeof fn, LLCDIR "/%s/llc_occupancy", dentry->d_name);
 1848             if ( (fp = fopen(fn, "r")) != NULL)
 1849             {
 1850                 if ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 1851                 {
 1852                     sscanf(linebuf, "%lu\n", &llc_occupancy);
 1853                     llc->occupancy = (float)llc_occupancy / l3_cache_size;
 1854                 }
 1855 
 1856                 fclose(fp);
 1857             }
 1858 
 1859             snprintf(fn, sizeof fn, LLCDIR "/%s/mbm_local_bytes", dentry->d_name);
 1860             if ( (fp = fopen(fn, "r")) != NULL)
 1861             {
 1862                 if ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 1863                 {
 1864                     sscanf(linebuf, "%llu\n", &llc->mbm_local);
 1865                 }
 1866 
 1867                 fclose(fp);
 1868             }
 1869 
 1870             snprintf(fn, sizeof fn, LLCDIR "/%s/mbm_total_bytes", dentry->d_name);
 1871             if ( (fp = fopen(fn, "r")) != NULL)
 1872             {
 1873                 if ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 1874                 {
 1875                     sscanf(linebuf, "%llu\n", &llc->mbm_total);
 1876                 }
 1877                 fclose(fp);
 1878             }
 1879 
 1880             if (++si->llc.nrllcs >= MAXLLC) /* too many LLC ? */
 1881                 break;
 1882         }
 1883 
 1884         closedir(dirp);
 1885     }
 1886 
 1887     /*
 1888     ** verify presence of InfiniBand controllers
 1889     ** warning: possibly switches to other directory
 1890     */
 1891     if (ib_stats)
 1892         ib_stats = get_infiniband(&(si->ifb));
 1893 
 1894     /*
 1895     ** get counters related to ksm
 1896     */
 1897     if (ksm_stats)
 1898         ksm_stats = get_ksm(si);
 1899 
 1900     /*
 1901     ** get counters related to zswap
 1902     */
 1903     if (zswap_stats)
 1904         zswap_stats = get_zswap(si);
 1905 
 1906     /*
 1907     ** return to original directory
 1908     */
 1909     if ( chdir(origdir) == -1)
 1910         mcleanstop(55, "failed to change to %s\n", origdir);
 1911 
 1912 #ifndef NOPERFEVENT
 1913     /*
 1914     ** get low-level CPU event counters
 1915     */
 1916         getperfevents(&(si->cpu));
 1917 #endif
 1918 
 1919     /*
 1920     ** fetch application-specific counters
 1921     */
 1922 #if HTTPSTATS
 1923     if ( wwwvalid)
 1924         wwwvalid = getwwwstat(80, &(si->www));
 1925 #endif
 1926 }
 1927 
 1928 /*
 1929 ** set of subroutines to determine which disks should be monitored
 1930 ** and to translate name strings into (shorter) name strings
 1931 */
 1932 static void
 1933 nullmodname(unsigned int major, unsigned int minor,
 1934         char *curname, struct perdsk *px, int maxlen)
 1935 {
 1936     strncpy(px->name, curname, maxlen-1);
 1937     *(px->name+maxlen-1) = 0;
 1938 }
 1939 
 1940 static void
 1941 abbrevname1(unsigned int major, unsigned int minor,
 1942         char *curname, struct perdsk *px, int maxlen)
 1943 {
 1944     char    cutype[128];
 1945     int hostnum, busnum, targetnum, lunnum;
 1946 
 1947     sscanf(curname, "%[^/]/host%d/bus%d/target%d/lun%d",
 1948             cutype, &hostnum, &busnum, &targetnum, &lunnum);
 1949 
 1950     snprintf(px->name, maxlen, "%c-h%db%dt%d", 
 1951             cutype[0], hostnum, busnum, targetnum);
 1952 }
 1953 
 1954 /*
 1955 ** recognize LVM logical volumes
 1956 */
 1957 #define NUMDMHASH   64
 1958 #define DMHASH(x,y) (((x)+(y))%NUMDMHASH)   
 1959 #define MAPDIR      "/dev/mapper"
 1960 
 1961 struct devmap {
 1962     unsigned int    major;
 1963     unsigned int    minor;
 1964     char        name[MAXDKNAM];
 1965     struct devmap   *next;
 1966 };
 1967 
 1968 static void
 1969 lvmmapname(unsigned int major, unsigned int minor,
 1970         char *curname, struct perdsk *px, int maxlen)
 1971 {
 1972     static int      firstcall = 1;
 1973     static struct devmap    *devmaps[NUMDMHASH], *dmp;
 1974     int         hashix;
 1975 
 1976     /*
 1977     ** setup a list of major-minor numbers of dm-devices with their
 1978     ** corresponding name
 1979     */
 1980     if (firstcall)
 1981     {
 1982         DIR     *dirp;
 1983         struct dirent   *dentry;
 1984         struct stat statbuf;
 1985         char        path[PATH_MAX];
 1986 
 1987         if ( (dirp = opendir(MAPDIR)) )
 1988         {
 1989             /*
 1990             ** read every directory-entry and search for
 1991             ** block devices
 1992             */
 1993             while ( (dentry = readdir(dirp)) )
 1994             {
 1995                 snprintf(path, sizeof path, "%s/%s", 
 1996                         MAPDIR, dentry->d_name);
 1997 
 1998                 if ( stat(path, &statbuf) == -1 )
 1999                     continue;
 2000 
 2001                 if ( ! S_ISBLK(statbuf.st_mode) )
 2002                     continue;
 2003                 /*
 2004                 ** allocate struct to store name
 2005                 */
 2006                 if ( !(dmp = malloc(sizeof (struct devmap))))
 2007                     continue;
 2008 
 2009                 /*
 2010                 ** store info in hash list
 2011                 */
 2012                 strncpy(dmp->name, dentry->d_name, MAXDKNAM);
 2013                 dmp->name[MAXDKNAM-1] = 0;
 2014                 dmp->major  = major(statbuf.st_rdev);
 2015                 dmp->minor  = minor(statbuf.st_rdev);
 2016 
 2017                 hashix = DMHASH(dmp->major, dmp->minor);
 2018 
 2019                 dmp->next   = devmaps[hashix];
 2020 
 2021                 devmaps[hashix] = dmp;
 2022             }
 2023 
 2024             closedir(dirp);
 2025         }
 2026 
 2027         firstcall = 0;
 2028     }
 2029 
 2030     /*
 2031     ** find info in hash list
 2032     */
 2033     hashix  = DMHASH(major, minor);
 2034     dmp = devmaps[hashix];
 2035 
 2036     while (dmp)
 2037     {
 2038         if (dmp->major == major && dmp->minor == minor)
 2039         {
 2040             /*
 2041             ** info found in hash list; fill proper name
 2042             */
 2043             strncpy(px->name, dmp->name, maxlen-1);
 2044             *(px->name+maxlen-1) = 0;
 2045             return;
 2046         }
 2047 
 2048         dmp = dmp->next;
 2049     }
 2050 
 2051     /*
 2052     ** info not found in hash list; fill original name
 2053     */
 2054     strncpy(px->name, curname, maxlen-1);
 2055     *(px->name+maxlen-1) = 0;
 2056 }
 2057 
 2058 /*
 2059 ** this table is used in the function isdisk()
 2060 **
 2061 ** table contains the names (in regexp format) of disks
 2062 ** to be recognized, together with a function to modify
 2063 ** the name-strings (i.e. to abbreviate long strings);
 2064 ** some frequently found names (like 'loop' and 'ram')
 2065 ** are also recognized to skip them as fast as possible
 2066 */
 2067 static struct {
 2068     char    *regexp;
 2069     regex_t compreg;
 2070     void    (*modname)(unsigned int, unsigned int,
 2071                 char *, struct perdsk *, int);
 2072     int retval;
 2073 } validdisk[] = {
 2074     { "^ram[0-9][0-9]*$",           {0},  (void *)0,   NONTYPE, },
 2075     { "^loop[0-9][0-9]*$",          {0},  (void *)0,   NONTYPE, },
 2076     { "^sd[a-z][a-z]*$",            {0},  nullmodname, DSKTYPE, },
 2077     { "^dm-[0-9][0-9]*$",           {0},  lvmmapname,  LVMTYPE, },
 2078     { "^md[0-9][0-9]*$",            {0},  nullmodname, MDDTYPE, },
 2079     { "^vd[a-z][a-z]*$",                    {0},  nullmodname, DSKTYPE, },
 2080     { "^nvme[0-9][0-9]*n[0-9][0-9]*$",  {0},  nullmodname, DSKTYPE, },
 2081     { "^nvme[0-9][0-9]*c[0-9][0-9]*n[0-9][0-9]*$", {0}, nullmodname, DSKTYPE, },
 2082     { "^nbd[0-9][0-9]*$",           {0},  nullmodname, DSKTYPE, },
 2083     { "^hd[a-z]$",              {0},  nullmodname, DSKTYPE, },
 2084     { "^rd/c[0-9][0-9]*d[0-9][0-9]*$",  {0},  nullmodname, DSKTYPE, },
 2085     { "^cciss/c[0-9][0-9]*d[0-9][0-9]*$",   {0},  nullmodname, DSKTYPE, },
 2086     { "^fio[a-z][a-z]*$",           {0},  nullmodname, DSKTYPE, },
 2087     { "/host.*/bus.*/target.*/lun.*/disc",  {0},  abbrevname1, DSKTYPE, },
 2088     { "^xvd[a-z][a-z]*[0-9]*$",     {0},  nullmodname, DSKTYPE, },
 2089     { "^dasd[a-z][a-z]*$",          {0},  nullmodname, DSKTYPE, },
 2090     { "^mmcblk[0-9][0-9]*$",        {0},  nullmodname, DSKTYPE, },
 2091     { "^emcpower[a-z][a-z]*$",      {0},  nullmodname, DSKTYPE, },
 2092     { "^rbd[0-9][0-9]*$",           {0},  nullmodname, DSKTYPE, },
 2093     { "^rbd[0-9][0-9]*p[0-9][0-9]*$",   {0},  nullmodname, DSKTYPE, },
 2094 };
 2095 
 2096 static int
 2097 isdisk(unsigned int major, unsigned int minor,
 2098            char *curname, struct perdsk *px, int maxlen)
 2099 {
 2100     static int  firstcall = 1;
 2101     register int    i;
 2102 
 2103     if (firstcall)      /* compile the regular expressions */
 2104     {
 2105         for (i=0; i < sizeof validdisk/sizeof validdisk[0]; i++)
 2106             regcomp(&validdisk[i].compreg, validdisk[i].regexp,
 2107                                 REG_NOSUB);
 2108         firstcall = 0;
 2109     }
 2110 
 2111     /*
 2112     ** try to recognize one of the compiled regular expressions
 2113     */
 2114     for (i=0; i < sizeof validdisk/sizeof validdisk[0]; i++)
 2115     {
 2116         if (regexec(&validdisk[i].compreg, curname, 0, NULL, 0) == 0)
 2117         {
 2118             /*
 2119             ** name-string recognized; modify name-string
 2120             */
 2121             if (validdisk[i].retval != NONTYPE)
 2122                 (*validdisk[i].modname)(major, minor,
 2123                         curname, px, maxlen);
 2124 
 2125             return validdisk[i].retval;
 2126         }
 2127     }
 2128 
 2129     return NONTYPE;
 2130 }
 2131 
 2132 /*
 2133 ** LINUX SPECIFIC:
 2134 ** Determine boot-time of this system (as number of jiffies since 1-1-1970).
 2135 */
 2136 unsigned long long
 2137 getbootlinux(long hertz)
 2138 {
 2139     int             cpid;
 2140     char            tmpbuf[1280];
 2141     FILE            *fp;
 2142     unsigned long       startticks;
 2143     unsigned long long  bootjiffies = 0;
 2144     struct timespec     ts;
 2145 
 2146     /*
 2147     ** dirty hack to get the boottime, since the
 2148     ** Linux 2.6 kernel (2.6.5) does not return a proper
 2149     ** boottime-value with the times() system call   :-(
 2150     */
 2151     if ( (cpid = fork()) == 0 )
 2152     {
 2153         /*
 2154         ** child just waiting to be killed by parent
 2155         */
 2156         pause();
 2157     }
 2158     else
 2159     {
 2160         /*
 2161         ** parent determines start-time (in jiffies since boot) 
 2162         ** of the child and calculates the boottime in jiffies
 2163         ** since 1-1-1970
 2164         */
 2165         (void) clock_gettime(CLOCK_REALTIME, &ts);  // get current
 2166         bootjiffies = 1LL * ts.tv_sec  * hertz +
 2167                       1LL * ts.tv_nsec * hertz / 1000000000LL;
 2168 
 2169         snprintf(tmpbuf, sizeof tmpbuf, "/proc/%d/stat", cpid);
 2170 
 2171         if ( (fp = fopen(tmpbuf, "r")) != NULL)
 2172         {
 2173             if ( fscanf(fp, "%*d (%*[^)]) %*c %*d %*d %*d %*d "
 2174                             "%*d %*d %*d %*d %*d %*d %*d %*d "
 2175                             "%*d %*d %*d %*d %*d %*d %lu",
 2176                             &startticks) == 1)
 2177             {
 2178                 bootjiffies -= startticks;
 2179             }
 2180 
 2181             fclose(fp);
 2182         }
 2183 
 2184         /*
 2185         ** kill the child and get rid of the zombie
 2186         */
 2187         kill(cpid, SIGKILL);
 2188         (void) wait((int *)0);
 2189     }
 2190 
 2191     return bootjiffies;
 2192 }
 2193 
 2194 
 2195 /*
 2196 ** get stats of all InfiniBand ports below
 2197 **    /sys/class/infiniband/<controller>/ports/<port#>/....
 2198 */
 2199 static struct ibcachent {
 2200     char        *ibha;      // InfiniBand Host Adaptor
 2201     unsigned short  port;       // port number
 2202     unsigned short  lanes;      // number of lanes
 2203     count_t     rate;       // transfer rate in bytes/sec
 2204     char        *pathrcvb;  // path name for received bytes
 2205     char        *pathsndb;  // path name for transmitted bytes
 2206     char        *pathrcvp;  // path name for received packets
 2207     char        *pathsndp;  // path name for transmitted packets
 2208 } ibcache[MAXIBPORT];
 2209 
 2210 static int  nib;            // number of IB ports in cache
 2211 
 2212 static void ibprep(struct ibcachent *);
 2213 static int  ibstat(struct ibcachent *, struct perifb *);
 2214 
 2215 static int
 2216 get_infiniband(struct ifbstat *si)
 2217 {
 2218     static int  firstcall = 1;
 2219     int     i;
 2220 
 2221     // verify if InfiniBand used in this system
 2222     if ( chdir("/sys/class/infiniband") == -1)
 2223         return 0;   // no path, no IB, so don't try again
 2224 
 2225     if (firstcall)
 2226     {
 2227         char        path[PATH_MAX], *p;
 2228         struct stat statbuf;
 2229         struct dirent   *contdent, *portdent;
 2230         DIR     *contp, *portp;
 2231 
 2232         firstcall = 0;
 2233 
 2234         /*
 2235         ** once setup a cache with all info that is needed
 2236         ** to gather the necessary stats with every subsequent
 2237         ** call, including  path names, etcetera.
 2238         */
 2239         if ( (contp = opendir(".")) )
 2240         {
 2241             /*
 2242             ** read every directory-entry and search for
 2243             ** subdirectories (i.e. controllers)
 2244             */
 2245             while ( (contdent = readdir(contp)) )
 2246             {
 2247                 // skip . and ..
 2248                 if (contdent->d_name[0] == '.')
 2249                     continue;
 2250 
 2251                 if ( stat(contdent->d_name, &statbuf) == -1 )
 2252                     continue;
 2253     
 2254                 if ( ! S_ISDIR(statbuf.st_mode) )
 2255                     continue;
 2256 
 2257                 // controller found
 2258                 // store controller name for cache
 2259                 //
 2260                 p = malloc( strlen(contdent->d_name)+1 );
 2261                 strcpy(p, contdent->d_name);
 2262 
 2263                 if (strlen(contdent->d_name) > MAXIBNAME-1)
 2264                     p[MAXIBNAME-1] = '\0';
 2265 
 2266                 // discover all ports
 2267                 //
 2268                 snprintf(path, sizeof path, "%s/ports",
 2269                             contdent->d_name);
 2270 
 2271                 if ( (portp = opendir(path)) )
 2272                 {
 2273                     /*
 2274                     ** read every directory-entry and
 2275                     ** search for subdirectories (i.e.
 2276                     ** port numbers)
 2277                     */
 2278                     while ( (portdent = readdir(portp)) )
 2279                     {
 2280                         int port;
 2281 
 2282                         // skip . and ..
 2283                         if (portdent->d_name[0] == '.')
 2284                             continue;
 2285 
 2286                         port = atoi(portdent->d_name);
 2287 
 2288                         if (!port)
 2289                             continue;
 2290 
 2291                         // valid port
 2292                         // fill cache info
 2293                         //
 2294                         ibcache[nib].port = port;
 2295                         ibcache[nib].ibha = p;
 2296 
 2297                         ibprep(&ibcache[nib]);
 2298 
 2299                         if (++nib >= MAXIBPORT)
 2300                             break;
 2301                     }
 2302 
 2303                     closedir(portp);
 2304 
 2305                     if (nib >= MAXIBPORT)
 2306                         break;
 2307                 }
 2308             }
 2309 
 2310             closedir(contp);
 2311         }
 2312     }
 2313 
 2314     /*
 2315     ** get static and variable metrics
 2316     */
 2317     for (i=0; i < nib; i++)
 2318     {
 2319         // static metrics from cache
 2320         strcpy(si->ifb[i].ibname, ibcache[i].ibha);
 2321 
 2322         si->ifb[i].portnr = ibcache[i].port;
 2323         si->ifb[i].lanes  = ibcache[i].lanes;
 2324         si->ifb[i].rate   = ibcache[i].rate;
 2325 
 2326         // variable metrics from sysfs
 2327         ibstat(&(ibcache[i]), &(si->ifb[i]));
 2328     }   
 2329 
 2330     si->nrports = nib;
 2331     return 1;
 2332 }
 2333 
 2334 /*
 2335 ** determine rate and number of lanes
 2336 ** from <contr>/ports/<port>/rate --> e.g. "100 Gb/sec (4X EDR)"
 2337 ** and assemble path names to be used for counters later on
 2338 */
 2339 static void
 2340 ibprep(struct ibcachent *ibc)
 2341 {
 2342     FILE    *fp;
 2343     char    path[PATH_MAX], linebuf[64], speedunit;
 2344 
 2345     // determine port rate and number of lanes
 2346     snprintf(path, sizeof path, "%s/ports/%d/rate", ibc->ibha, ibc->port); 
 2347 
 2348     if ( (fp = fopen(path, "r")) )
 2349     {
 2350         if ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 2351         {
 2352             (void) sscanf(linebuf, "%lld %c%*s (%hdX",
 2353                 &(ibc->rate), &speedunit, &(ibc->lanes));
 2354 
 2355             // calculate megabits/second
 2356             switch (speedunit)
 2357             {
 2358                case 'M':
 2359                case 'm':
 2360                 break;
 2361                case 'G':
 2362                case 'g':
 2363                 ibc->rate *= 1000;
 2364                 break;
 2365                case 'T':
 2366                case 't':
 2367                 ibc->rate *= 1000000;
 2368                 break;
 2369             }
 2370 
 2371         }
 2372         else
 2373         {
 2374             ibc->lanes = 0;
 2375             ibc->rate = 0;
 2376         }
 2377 
 2378         fclose(fp);
 2379     }
 2380 
 2381     // build all pathnames to obtain the counters
 2382     // of this port later on
 2383     snprintf(path, sizeof path, "%s/ports/%d/counters/port_rcv_data",
 2384                             ibc->ibha, ibc->port);
 2385     ibc->pathrcvb = malloc( strlen(path)+1 );
 2386     strcpy(ibc->pathrcvb, path);
 2387 
 2388     snprintf(path, sizeof path, "%s/ports/%d/counters/port_xmit_data",
 2389                             ibc->ibha, ibc->port);
 2390     ibc->pathsndb = malloc( strlen(path)+1 );
 2391     strcpy(ibc->pathsndb, path);
 2392 
 2393     snprintf(path, sizeof path, "%s/ports/%d/counters/port_rcv_packets",
 2394                             ibc->ibha, ibc->port);
 2395     ibc->pathrcvp = malloc( strlen(path)+1 );
 2396     strcpy(ibc->pathrcvp, path);
 2397 
 2398     snprintf(path, sizeof path, "%s/ports/%d/counters/port_xmit_packets",
 2399                             ibc->ibha, ibc->port);
 2400     ibc->pathsndp = malloc( strlen(path)+1 );
 2401     strcpy(ibc->pathsndp, path);
 2402 }
 2403 
 2404 /*
 2405 ** read necessary variable counters for this IB port
 2406 */
 2407 static int
 2408 ibstat(struct ibcachent *ibc, struct perifb *ifb)
 2409 {
 2410     FILE    *fp;
 2411     char    linebuf[64];
 2412 
 2413     if ( (fp = fopen(ibc->pathrcvb, "r")) )
 2414     {
 2415         if ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 2416         {
 2417             if (sscanf(linebuf, "%lld", &(ifb->rcvb)) == 0)
 2418                 ifb->rcvb = 0;
 2419         }
 2420         else
 2421         {
 2422             ifb->rcvb = 0;
 2423         }
 2424         fclose(fp);
 2425     }
 2426 
 2427     if ( (fp = fopen(ibc->pathsndb, "r")) )
 2428     {
 2429         if ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 2430         {
 2431             if (sscanf(linebuf, "%lld", &(ifb->sndb)) == 0)
 2432                 ifb->sndb = 0;
 2433         }
 2434         else
 2435         {
 2436             ifb->sndb = 0;
 2437         }
 2438         fclose(fp);
 2439     }
 2440 
 2441     if ( (fp = fopen(ibc->pathrcvp, "r")) )
 2442     {
 2443         if ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 2444         {
 2445             if (sscanf(linebuf, "%lld", &(ifb->rcvp)) == 0)
 2446                 ifb->rcvp = 0;
 2447         }
 2448         else
 2449         {
 2450             ifb->rcvp = 0;
 2451         }
 2452         fclose(fp);
 2453     }
 2454 
 2455     if ( (fp = fopen(ibc->pathsndp, "r")) )
 2456     {
 2457         if ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
 2458         {
 2459             if (sscanf(linebuf, "%lld", &(ifb->sndp)) == 0)
 2460                 ifb->sndp = 0;
 2461         }
 2462         else
 2463         {
 2464             ifb->sndp = 0;
 2465         }
 2466         fclose(fp);
 2467     }
 2468 
 2469     return 1;
 2470 }
 2471 
 2472 /*
 2473 ** retrieve ksm values (if switched on)
 2474 */
 2475 static int
 2476 get_ksm(struct sstat *si)
 2477 {
 2478     FILE *fp;
 2479     int  state;
 2480 
 2481     si->mem.ksmsharing = -1;
 2482     si->mem.ksmshared  = -1;
 2483 
 2484     if ((fp=fopen("/sys/kernel/mm/ksm/run", "r")) != 0)
 2485     {
 2486         if (fscanf(fp, "%d", &state) == 1)
 2487         {
 2488             if (state == 0)
 2489             {
 2490                 fclose(fp);
 2491                 return 0; // no more calling
 2492             }
 2493         }
 2494 
 2495         fclose(fp);
 2496     }
 2497 
 2498     if ((fp=fopen("/sys/kernel/mm/ksm/pages_sharing", "r")) != 0)
 2499     {
 2500         if (fscanf(fp, "%llu", &(si->mem.ksmsharing)) != 1)
 2501             si->mem.ksmsharing = 0;
 2502 
 2503         fclose(fp);
 2504     }
 2505 
 2506     if ((fp=fopen("/sys/kernel/mm/ksm/pages_shared", "r")) != 0)
 2507     {
 2508         if (fscanf(fp, "%llu", &(si->mem.ksmshared)) != 1)
 2509             si->mem.ksmshared = 0;
 2510 
 2511         fclose(fp);
 2512     }
 2513 
 2514     return 1;
 2515 }
 2516 
 2517 /*
 2518 ** retrieve zswap values (if switched on)
 2519 */
 2520 static int
 2521 get_zswap(struct sstat *si)
 2522 {
 2523     FILE *fp;
 2524     char  state;
 2525 
 2526     si->mem.zswtotpool = -1;
 2527     si->mem.zswstored  = -1;
 2528 
 2529     if ((fp=fopen("/sys/module/zswap/parameters/enabled", "r")) != 0)
 2530     {
 2531         if (fscanf(fp, "%c", &state) == 1)
 2532         {
 2533             if (state != 'Y')
 2534             {
 2535                 fclose(fp);
 2536                 return 0; // no more calling
 2537             }
 2538         }
 2539 
 2540         fclose(fp);
 2541     }
 2542 
 2543     regainrootprivs();
 2544 
 2545     if ((fp=fopen("/sys/kernel/debug/zswap/pool_total_size", "r")) != 0)
 2546     {
 2547         if (fscanf(fp, "%llu", &(si->mem.zswtotpool)) != 1)
 2548             si->mem.zswtotpool = 0;
 2549         else
 2550             si->mem.zswtotpool /= pagesize;
 2551 
 2552         fclose(fp);
 2553     }
 2554 
 2555     if ((fp=fopen("/sys/kernel/debug/zswap/stored_pages", "r")) != 0)
 2556     {
 2557         if (fscanf(fp, "%llu", &(si->mem.zswstored)) != 1)
 2558             si->mem.zswstored = 0;
 2559 
 2560         fclose(fp);
 2561     }
 2562 
 2563     if (! droprootprivs())
 2564         mcleanstop(42, "failed to drop root privs\n");
 2565 
 2566     return 1;
 2567 }
 2568 
 2569 
 2570 #if HTTPSTATS
 2571 /*
 2572 ** retrieve statistics from local HTTP daemons
 2573 ** via http://localhost/server-status?auto
 2574 */
 2575 int
 2576 getwwwstat(unsigned short port, struct wwwstat *wp)
 2577 {
 2578     int             sockfd, tobefound;
 2579     FILE            *sockfp;
 2580     struct sockaddr_in  sockname;
 2581     char            linebuf[4096];
 2582     char            label[512];
 2583     long long       value;
 2584 
 2585     memset(wp, 0, sizeof *wp);
 2586 
 2587     /*
 2588     ** allocate a socket and connect to the local HTTP daemon
 2589     */
 2590     if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
 2591         return 0;
 2592 
 2593     sockname.sin_family     = AF_INET;
 2594     sockname.sin_addr.s_addr    = htonl(INADDR_LOOPBACK);
 2595     sockname.sin_port       = htons(port);
 2596 
 2597     if ( connect(sockfd, (struct sockaddr *) &sockname,
 2598                         sizeof sockname) == -1)
 2599     {
 2600         close(sockfd);
 2601         return 0;
 2602     }
 2603 
 2604     /*
 2605     ** write a GET-request for /server-status
 2606     */
 2607     if ( write(sockfd, HTTPREQ, sizeof HTTPREQ) < sizeof HTTPREQ)
 2608     {
 2609         close(sockfd);
 2610         return 0;
 2611     }
 2612 
 2613     /*
 2614     ** remap socket descriptor to a stream to allow stdio calls
 2615     */
 2616     sockfp = fdopen(sockfd, "r+");
 2617 
 2618     /*
 2619     ** read response line by line
 2620     */
 2621     tobefound = 5;      /* number of values to be searched */
 2622 
 2623     while ( fgets(linebuf, sizeof linebuf, sockfp) && tobefound)
 2624     {
 2625         /*
 2626         ** handle line containing status code
 2627         */
 2628         if ( strncmp(linebuf, "HTTP/", 5) == 0)
 2629         {
 2630             sscanf(linebuf, "%511s %lld %*s\n", label, &value);
 2631 
 2632             if (value != 200)   /* HTTP-request okay? */
 2633             {
 2634                 fclose(sockfp);
 2635                 close(sockfd);
 2636                 return 0;
 2637             }
 2638 
 2639             continue;
 2640         }
 2641 
 2642         /*
 2643         ** decode line and search for the required counters
 2644         */
 2645         if (sscanf(linebuf, "%511[^:]: %lld\n", label, &value) == 2)
 2646         {
 2647             if ( strcmp(label, "Total Accesses") == 0)
 2648             {
 2649                 wp->accesses = value;
 2650                 tobefound--;
 2651             }
 2652 
 2653             if ( strcmp(label, "Total kBytes") == 0)
 2654             {
 2655                 wp->totkbytes = value;
 2656                 tobefound--;
 2657             }
 2658 
 2659             if ( strcmp(label, "Uptime") == 0)
 2660             {
 2661                 wp->uptime = value;
 2662                 tobefound--;
 2663             }
 2664 
 2665             if ( strcmp(label, "BusyWorkers") == 0)
 2666             {
 2667                 wp->bworkers = value;
 2668                 tobefound--;
 2669             }
 2670 
 2671             if ( strcmp(label, "IdleWorkers") == 0)
 2672             {
 2673                 wp->iworkers = value;
 2674                 tobefound--;
 2675             }
 2676         }
 2677     }
 2678 
 2679     fclose(sockfp);
 2680     close(sockfd);
 2681 
 2682     return 1;
 2683 }
 2684 #endif
 2685 
 2686 
 2687 
 2688 /*
 2689 ** retrieve low-level CPU events:
 2690 **  instructions and cycles per CPU
 2691 */
 2692 #ifndef NOPERFEVENT
 2693 
 2694 void
 2695 do_perfevents(char *tagname, char *tagvalue)
 2696 {
 2697     if (!strcmp("enable", tagvalue))
 2698         perfevents = PERF_EVENTS_ENABLE;
 2699     else if (!strcmp("disable", tagvalue))
 2700         perfevents = PERF_EVENTS_DISABLE;
 2701     else
 2702     {
 2703         if (run_in_guest())
 2704             perfevents = PERF_EVENTS_DISABLE;
 2705         else
 2706             perfevents = PERF_EVENTS_ENABLE;
 2707     }
 2708 }
 2709 
 2710 static int
 2711 enable_perfevents()
 2712 {
 2713     if (perfevents == PERF_EVENTS_AUTO)
 2714         do_perfevents("perfevents", "auto");
 2715 
 2716     return perfevents == PERF_EVENTS_ENABLE;
 2717 }
 2718 
 2719 long
 2720 perf_event_open(struct perf_event_attr *hwevent, pid_t pid,
 2721                 int cpu, int groupfd, unsigned long flags)
 2722 {
 2723     return syscall(__NR_perf_event_open, hwevent, pid, cpu, groupfd, flags);
 2724 }
 2725 
 2726 static void
 2727 getperfevents(struct cpustat *cs)
 2728 {
 2729     static int  firstcall = 1, cpualloced, *fdi, *fdc;
 2730     int     i;
 2731     int         liResult;
 2732 
 2733     if (!enable_perfevents())
 2734         return;
 2735 
 2736     /*
 2737     ** once initialize perf event counter retrieval
 2738     */
 2739     if (firstcall)
 2740     {
 2741         struct perf_event_attr  pea;
 2742         int         success = 0;
 2743 
 2744         firstcall = 0;
 2745 
 2746         /*
 2747         ** allocate space for per-cpu file descriptors
 2748         */
 2749         cpualloced = cs->nrcpu;
 2750         fdi        = malloc(sizeof(int) * cpualloced);
 2751         fdc        = malloc(sizeof(int) * cpualloced);
 2752 
 2753         /*
 2754         ** fill perf_event_attr struct with appropriate values
 2755         */
 2756         memset(&pea, 0, sizeof(struct perf_event_attr));
 2757 
 2758         pea.type    = PERF_TYPE_HARDWARE;
 2759         pea.size    = sizeof(struct perf_event_attr);
 2760         pea.inherit = 1;
 2761         pea.pinned  = 1;
 2762 
 2763         regainrootprivs();
 2764 
 2765         for (i=0; i < cpualloced; i++)
 2766         {
 2767             pea.config = PERF_COUNT_HW_INSTRUCTIONS;
 2768 
 2769             if ( (*(fdi+i) = perf_event_open(&pea, -1, i, -1,
 2770                         PERF_FLAG_FD_CLOEXEC)) >= 0)
 2771                 success++;
 2772 
 2773                         pea.config = PERF_COUNT_HW_CPU_CYCLES;
 2774 
 2775             if ( (*(fdc+i) = perf_event_open(&pea, -1, i, -1,
 2776                         PERF_FLAG_FD_CLOEXEC)) >= 0)
 2777                 success++;
 2778         }
 2779 
 2780         if (! droprootprivs())
 2781             mcleanstop(42, "failed to drop root privs\n");
 2782 
 2783 
 2784         /*
 2785         ** all failed (probably no kernel support)?
 2786         */
 2787         if (success == 0)   
 2788         {
 2789             free(fdi);
 2790             free(fdc);
 2791             cpualloced = 0;
 2792         }
 2793         else
 2794         {
 2795             cs->all.instr = 1;
 2796             cs->all.cycle = 1;
 2797         }
 2798 
 2799         return;     // initialization finished for first sample
 2800         }
 2801 
 2802     /*
 2803     ** every sample: check if counters available anyhow
 2804     */
 2805         if (!cpualloced)
 2806                 return;
 2807 
 2808     /*
 2809     ** retrieve counters per CPU and in total
 2810     */
 2811     cs->all.instr = 0;
 2812     cs->all.cycle = 0;
 2813 
 2814         for (i=0; i < cpualloced; i++)
 2815         {
 2816         if (*(fdi+i) != -1)
 2817         {
 2818                     liResult = read(*(fdi+i), &(cs->cpu[i].instr), sizeof(count_t));
 2819                         cs->all.instr += cs->cpu[i].instr;
 2820             if(liResult < 0)
 2821             {
 2822                 char lcMessage[64];
 2823 
 2824                 snprintf(lcMessage, sizeof(lcMessage) - 1,
 2825                           "%s:%d - Error %d reading instr counters\n",
 2826                            __FILE__, __LINE__, errno);
 2827                 fprintf(stderr, "%s", lcMessage);
 2828             }
 2829 
 2830                     liResult = read(*(fdc+i), &(cs->cpu[i].cycle), sizeof(count_t));
 2831                         cs->all.cycle += cs->cpu[i].cycle;
 2832             if(liResult < 0)
 2833             {
 2834                 char lcMessage[64];
 2835 
 2836                 snprintf(lcMessage, sizeof(lcMessage) - 1,
 2837                           "%s:%d - Error %d reading cycle counters\n",
 2838                            __FILE__, __LINE__, errno );
 2839                 fprintf(stderr, "%s", lcMessage);
 2840             }
 2841         }
 2842         }
 2843 }
 2844 
 2845 #else /* ! NOPERFEVENT */
 2846 void
 2847 do_perfevents(char *tagname, char *tagvalue)
 2848 {
 2849     if (strcmp("disable", tagvalue))
 2850         mcleanstop(1, "atop built with NOPERFEVENT, cannot use perfevents\n");
 2851 }
 2852 #endif