"Fossies" - the Fresh Open Source Software Archive

Member "atop-2.8.1/atop.c" (7 Jan 2023, 35359 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 "atop.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 the main-function, which verifies the
    8 ** calling-parameters and takes care of initialization. 
    9 ** The engine-function drives the main sample-loop in which after the
   10 ** indicated interval-time a snapshot is taken of the system-level and
   11 ** process-level counters and the deviations are calculated and
   12 ** visualized for the user.
   13 ** ==========================================================================
   14 ** Author:      Gerlof Langeveld
   15 ** E-mail:      gerlof.langeveld@atoptool.nl
   16 ** Date:        November 1996
   17 ** Linux-port:  June 2000
   18 ** Modified:    May 2001 - Ported to kernel 2.4
   19 ** --------------------------------------------------------------------------
   20 ** Copyright (C) 2000-2018 Gerlof Langeveld
   21 **
   22 ** This program is free software; you can redistribute it and/or modify it
   23 ** under the terms of the GNU General Public License as published by the
   24 ** Free Software Foundation; either version 2, or (at your option) any
   25 ** later version.
   26 **
   27 ** This program is distributed in the hope that it will be useful, but
   28 ** WITHOUT ANY WARRANTY; without even the implied warranty of
   29 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   30 ** See the GNU General Public License for more details.
   31 **
   32 ** You should have received a copy of the GNU General Public License
   33 ** along with this program; if not, write to the Free Software
   34 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   35 ** --------------------------------------------------------------------------
   36 **
   37 ** After initialization, the main-function calls the ENGINE.
   38 ** For every cycle (so after another interval) the ENGINE calls various 
   39 ** functions as shown below:
   40 **
   41 ** +---------------------------------------------------------------------+
   42 ** |                           E  N  G  I  N  E                          |
   43 ** |                                                                     |
   44 ** |                                                                     |
   45 ** |    _____________________await interval-timer_____________________   |
   46 ** |   |                                                              ^  |
   47 ** |   |      ________       ________      ________      ________     |  |
   48 ** |   |     ^        |     ^        |    ^        |    ^        |    |  |
   49 ** +---|-----|--------|-----|--------|----|--------|----|--------|----|--+
   50 **     |     |        |     |        |    |        |    |        |    |
   51 **  +--V-----|--+  +--V-----|--+  +--V----|--+  +--V----|--+  +--V----|-+  
   52 **  |           |  |           |  |          |  |          |  |         |
   53 **  | photosyst |  | photoproc |  |   acct   |  | deviate  |  |  print  |
   54 **  |           |  |           |  |photoproc |  |  ...syst |  |         |
   55 **  |           |  |           |  |          |  |  ...proc |  |         |
   56 **  +-----------+  +-----------+  +----------+  +----------+  +---------+  
   57 **        ^              ^             ^              ^            |
   58 **        |              |             |              |            |
   59 **        |              |             |              V            V 
   60 **      ______       _________     __________     ________     _________
   61 **     /      \     /         \   /          \   /        \   /         \
   62 **      /proc          /proc       accounting       task       screen or
   63 **                                    file        database        file
   64 **     \______/     \_________/   \__________/   \________/   \_________/
   65 **
   66 **    - photosyst()
   67 **  Takes a snapshot of the counters related to resource-usage on
   68 **  system-level (cpu, disk, memory, network).
   69 **  This code is UNIX-flavor dependent; in case of Linux the counters
   70 **  are retrieved from /proc.
   71 **
   72 **    - photoproc()
   73 **  Takes a snapshot of the counters related to resource-usage of
   74 **  tasks which are currently active. For this purpose the whole
   75 **  task-list is read.
   76 **  This code is UNIX-flavor dependent; in case of Linux the counters
   77 **  are retrieved from /proc.
   78 **
   79 **    - acctphotoproc()
   80 **  Takes a snapshot of the counters related to resource-usage of
   81 **  tasks which have been finished during the last interval.
   82 **  For this purpose all new records in the accounting-file are read.
   83 **
   84 ** When all counters have been gathered, functions are called to calculate
   85 ** the difference between the current counter-values and the counter-values
   86 ** of the previous cycle. These functions operate on the system-level
   87 ** as well as on the task-level counters. 
   88 ** These differences are stored in a new structure(-table). 
   89 **
   90 **    - deviatsyst()
   91 **  Calculates the differences between the current system-level
   92 **  counters and the corresponding counters of the previous cycle.
   93 **
   94 **    - deviattask()
   95 **  Calculates the differences between the current task-level
   96 **  counters and the corresponding counters of the previous cycle.
   97 **  The per-task counters of the previous cycle are stored in the
   98 **  task-database; this "database" is implemented as a linked list
   99 **  of taskinfo structures in memory (so no disk-accesses needed).
  100 **  Within this linked list hash-buckets are maintained for fast searches.
  101 **  The entire task-database is handled via a set of well-defined 
  102 **  functions from which the name starts with "pdb_..." (see the
  103 **  source-file procdbase.c).
  104 **  The processes which have been finished during the last cycle
  105 **  are also treated by deviattask() in order to calculate what their
  106 **  resource-usage was before they finished.
  107 **
  108 ** All information is ready to be visualized now.
  109 ** There is a structure which holds the start-address of the
  110 ** visualization-function to be called. Initially this structure contains
  111 ** the address of the generic visualization-function ("generic_samp"), but
  112 ** these addresses can be modified in the main-function depending on particular
  113 ** flags. In this way various representation-layers (ASCII, graphical, ...)
  114 ** can be linked with 'atop'; the one to use can eventually be chosen
  115 ** at runtime. 
  116 **
  117 ** $Log: atop.c,v $
  118 ** Revision 1.49  2010/10/23 14:01:00  gerlof
  119 ** Show counters for total number of running and sleep (S and D) threads.
  120 **
  121 ** Revision 1.48  2010/10/23 08:18:15  gerlof
  122 ** Catch signal SIGUSR2 to take a final sample and stop.
  123 ** Needed for improved of suspend/hibernate.
  124 **
  125 ** Revision 1.47  2010/04/23 12:20:19  gerlof
  126 ** Modified mail-address in header.
  127 **
  128 ** Revision 1.46  2010/04/23 09:57:28  gerlof
  129 ** Version (flag -V) handled earlier after startup.
  130 **
  131 ** Revision 1.45  2010/04/17 17:19:41  gerlof
  132 ** Allow modifying the layout of the columns in the system lines.
  133 **
  134 ** Revision 1.44  2010/04/16 13:00:23  gerlof
  135 ** Automatically start another version of atop if the logfile to
  136 ** be read has not been created by the current version.
  137 **
  138 ** Revision 1.43  2010/03/04 10:51:10  gerlof
  139 ** Support I/O-statistics on logical volumes and MD devices.
  140 **
  141 ** Revision 1.42  2009/12/31 11:33:33  gerlof
  142 ** Sanity-check to bypass kernel-bug showing 497 days of CPU-consumption.
  143 **
  144 ** Revision 1.41  2009/12/17 10:51:31  gerlof
  145 ** Allow own defined process line with key 'o' and a definition
  146 ** in the atoprc file.
  147 **
  148 ** Revision 1.40  2009/12/17 08:15:15  gerlof
  149 ** Introduce branch-key to go to specific time in raw file.
  150 **
  151 ** Revision 1.39  2009/12/10 13:34:32  gerlof
  152 ** Cosmetical changes.
  153 **
  154 ** Revision 1.38  2009/12/10 11:55:38  gerlof
  155 ** Introduce -L flag for line length.
  156 **
  157 ** Revision 1.37  2009/12/10 10:43:33  gerlof
  158 ** Correct calculation of node name.
  159 **
  160 ** Revision 1.36  2009/12/10 09:19:06  gerlof
  161 ** Various changes related to redesign of user-interface.
  162 ** Made by JC van Winkel.
  163 **
  164 ** Revision 1.35  2009/11/27 15:11:55  gerlof
  165 ** *** empty log message ***
  166 **
  167 ** Revision 1.34  2009/11/27 15:07:25  gerlof
  168 ** Give up root-privileges at a earlier stage.
  169 **
  170 ** Revision 1.33  2009/11/27 14:01:01  gerlof
  171 ** Introduce system-wide configuration file /etc/atoprc
  172 **
  173 ** Revision 1.32  2008/01/07 10:16:13  gerlof
  174 ** Implement summaries for atopsar.
  175 **
  176 ** Revision 1.31  2007/11/06 09:16:05  gerlof
  177 ** Add keyword atopsarflags to configuration-file ~/.atoprc
  178 **
  179 ** Revision 1.30  2007/08/16 11:58:35  gerlof
  180 ** Add support for atopsar reporting.
  181 **
  182 ** Revision 1.29  2007/03/20 13:01:36  gerlof
  183 ** Introduction of variable supportflags.
  184 **
  185 ** Revision 1.28  2007/03/20 12:13:00  gerlof
  186 ** Be sure that all tstat struct's are initialized with binary zeroes.
  187 **
  188 ** Revision 1.27  2007/02/19 11:55:04  gerlof
  189 ** Bug-fix: flag -S was not recognized any more.
  190 **
  191 ** Revision 1.26  2007/02/13 10:34:20  gerlof
  192 ** Support parseable output with flag -P
  193 **
  194 ** Revision 1.25  2007/01/26 12:10:40  gerlof
  195 ** Add configuration-value 'swoutcritsec'.
  196 **
  197 ** Revision 1.24  2007/01/18 10:29:22  gerlof
  198 ** Improved syntax-checking for ~/.atoprc file.
  199 ** Support for network-interface busy-percentage.
  200 **
  201 ** Revision 1.23  2006/02/07 08:27:04  gerlof
  202 ** Cosmetic changes.
  203 **
  204 ** Revision 1.22  2005/10/28 09:50:29  gerlof
  205 ** All flags/subcommands are defined as macro's.
  206 **
  207 ** Revision 1.21  2005/10/21 09:48:48  gerlof
  208 ** Per-user accumulation of resource consumption.
  209 **
  210 ** Revision 1.20  2004/12/14 15:05:38  gerlof
  211 ** Implementation of patch-recognition for disk and network-statistics.
  212 **
  213 ** Revision 1.19  2004/10/26 13:42:49  gerlof
  214 ** Also lock current physical pages in memory.
  215 **
  216 ** Revision 1.18  2004/09/15 08:23:42  gerlof
  217 ** Set resource limit for locked memory to infinite, because
  218 ** in certain environments it is set to 32K (causes atop-malloc's
  219 ** to fail).
  220 **
  221 ** Revision 1.17  2004/05/06 09:45:44  gerlof
  222 ** Ported to kernel-version 2.6.
  223 **
  224 ** Revision 1.16  2003/07/07 09:18:22  gerlof
  225 ** Cleanup code (-Wall proof).
  226 **
  227 ** Revision 1.15  2003/07/03 11:16:14  gerlof
  228 ** Implemented subcommand `r' (reset).
  229 **
  230 ** Revision 1.14  2003/06/30 11:29:12  gerlof
  231 ** Handle configuration file ~/.atoprc
  232 **
  233 ** Revision 1.13  2003/01/14 09:01:10  gerlof
  234 ** Explicit clearing of malloced space for exited processes.
  235 **
  236 ** Revision 1.12  2002/10/30 13:44:51  gerlof
  237 ** Generate notification for statistics since boot.
  238 **
  239 ** Revision 1.11  2002/10/08 11:34:52  gerlof
  240 ** Modified storage of raw filename.
  241 **
  242 ** Revision 1.10  2002/09/26 13:51:47  gerlof
  243 ** Limit header lines by not showing disks.
  244 **
  245 ** Revision 1.9  2002/09/17 10:42:00  gerlof
  246 ** Copy functions rawread() and rawwrite() to separate source-file rawlog.c
  247 **
  248 ** Revision 1.8  2002/08/30 07:49:35  gerlof
  249 ** Implement possibility to store and retrieve atop-data in raw format.
  250 **
  251 ** Revision 1.7  2002/08/27 12:09:16  gerlof
  252 ** Allow raw data file to be written and to be read (with compression).
  253 **
  254 ** Revision 1.6  2002/07/24 11:12:07  gerlof
  255 ** Redesigned to ease porting to other UNIX-platforms.
  256 **
  257 ** Revision 1.5  2002/07/11 09:15:53  root
  258 ** *** empty log message ***
  259 **
  260 ** Revision 1.4  2002/07/08 09:20:45  root
  261 ** Bug solution: flag list overflow.
  262 **
  263 ** Revision 1.3  2001/11/07 09:17:41  gerlof
  264 ** Use /proc instead of /dev/kmem for process-level statistics.
  265 **
  266 ** Revision 1.2  2001/10/04 13:03:15  gerlof
  267 ** Separate kopen() function called i.s.o. implicit with first kmem-read
  268 **
  269 ** Revision 1.1  2001/10/02 10:43:19  gerlof
  270 ** Initial revision
  271 **
  272 */
  273 
  274 #include <sys/types.h>
  275 #include <sys/param.h>
  276 #include <sys/mman.h>
  277 #include <sys/stat.h>
  278 #include <time.h>
  279 #include <stdio.h>
  280 #include <errno.h>
  281 #include <fcntl.h>
  282 #include <unistd.h>
  283 #include <stdlib.h>
  284 #include <signal.h>
  285 #include <sys/utsname.h>
  286 #include <string.h>
  287 #include <sys/time.h>
  288 #include <sys/resource.h>
  289 #include <regex.h>
  290 
  291 #include "atop.h"
  292 #include "acctproc.h"
  293 #include "ifprop.h"
  294 #include "photoproc.h"
  295 #include "photosyst.h"
  296 #include "showgeneric.h"
  297 #include "parseable.h"
  298 #include "json.h"
  299 #include "gpucom.h"
  300 
  301 #define allflags  "ab:cde:fghijklmnopqrstuvwxyz1ABCDEFGHIJ:KL:MNOP:QRSTUVWXYZ"
  302 #define MAXFL       64      /* maximum number of command-line flags  */
  303 
  304 /*
  305 ** declaration of global variables
  306 */
  307 struct utsname  utsname;
  308 int     utsnodenamelen;
  309 time_t      pretime;    /* timing info              */
  310 time_t      curtime;    /* timing info              */
  311 unsigned long   interval = 10;
  312 unsigned long   sampcnt;
  313 char        screen;
  314 int     linelen  = 80;
  315 char        acctreason; /* accounting not active (return val)   */
  316 char        rawname[RAWNAMESZ];
  317 char        rawreadflag;
  318 time_t      begintime, endtime, cursortime; // epoch or time in day
  319 char        flaglist[MAXFL];
  320 char        deviatonly = 1;
  321 char        usecolors  = 1;  /* boolean: colors for high occupation  */
  322 char        threadview = 0;  /* boolean: show individual threads     */
  323 char        calcpss    = 0;  /* boolean: read/calculate process PSS  */
  324 char        getwchan   = 0;  /* boolean: obtain wchan string         */
  325 char        rmspaces   = 0;  /* boolean: remove spaces from command  */
  326                          /* name in case of parseable output     */
  327 
  328 unsigned short  hertz;
  329 unsigned int    pidwidth;
  330 unsigned int    pagesize;
  331 unsigned int    nrgpus;
  332 int         osrel;
  333 int         osvers;
  334 int         ossub;
  335 
  336 int     supportflags;   /* supported features               */
  337 char        **argvp;
  338 
  339 
  340 struct visualize vis = {generic_samp, generic_error,
  341             generic_end,  generic_usage};
  342 
  343 /*
  344 ** argument values
  345 */
  346 static char     awaittrigger;   /* boolean: awaiting trigger */
  347 static unsigned int     nsamples = 0xffffffff;
  348 static char     midnightflag;
  349 static char     rawwriteflag;
  350 
  351 /*
  352 ** interpretation of defaults-file /etc/atoprc and $HOME/.atop
  353 */
  354 static void     readrc(char *, int);
  355 
  356 void do_flags(char *, char *);
  357 void do_interval(char *, char *);
  358 void do_linelength(char *, char *);
  359 void do_username(char *, char *);
  360 void do_procname(char *, char *);
  361 void do_maxcpu(char *, char *);
  362 void do_maxgpu(char *, char *);
  363 void do_maxdisk(char *, char *);
  364 void do_maxmdd(char *, char *);
  365 void do_maxlvm(char *, char *);
  366 void do_maxintf(char *, char *);
  367 void do_maxifb(char *, char *);
  368 void do_maxnfsm(char *, char *);
  369 void do_maxcont(char *, char *);
  370 void do_maxnuma(char *, char *);
  371 void do_maxllc(char *, char *);
  372 void do_colinfo(char *, char *);
  373 void do_colalmost(char *, char *);
  374 void do_colcrit(char *, char *);
  375 void do_colthread(char *, char *);
  376 void do_ownsysprcline(char *, char *);
  377 void do_ownallcpuline(char *, char *);
  378 void do_ownindivcpuline(char *, char *);
  379 void do_owncplline(char *, char *);
  380 void do_ownmemline(char *, char *);
  381 void do_ownswpline(char *, char *);
  382 void do_ownpagline(char *, char *);
  383 void do_ownmemnumaline(char *, char *);
  384 void do_owncpunumaline(char *, char *);
  385 void do_ownllcline(char *, char *);
  386 void do_owndskline(char *, char *);
  387 void do_ownnettransportline(char *, char *);
  388 void do_ownnetnetline(char *, char *);
  389 void do_ownnetinterfaceline(char *, char *);
  390 void do_owninfinibandline(char *, char *);
  391 void do_ownprocline(char *, char *);
  392 void do_cpucritperc(char *, char *);
  393 void do_gpucritperc(char *, char *);
  394 void do_memcritperc(char *, char *);
  395 void do_swpcritperc(char *, char *);
  396 void do_dskcritperc(char *, char *);
  397 void do_netcritperc(char *, char *);
  398 void do_swoutcritsec(char *, char *);
  399 void do_almostcrit(char *, char *);
  400 void do_atopsarflags(char *, char *);
  401 void do_pacctdir(char *, char *);
  402 void do_perfevents(char *, char *);
  403 
  404 static struct {
  405     char    *tag;
  406     void    (*func)(char *, char *);
  407     int sysonly;
  408 } manrc[] = {
  409     {   "flags",        do_flags,       0, },
  410     {   "interval",     do_interval,        0, },
  411     {   "linelen",      do_linelength,      0, },
  412     {   "username",     do_username,        0, },
  413     {   "procname",     do_procname,        0, },
  414     {   "maxlinecpu",       do_maxcpu,      0, },
  415     {   "maxlinegpu",       do_maxgpu,      0, },
  416     {   "maxlinedisk",      do_maxdisk,     0, },
  417     {   "maxlinemdd",       do_maxmdd,      0, },
  418     {   "maxlinelvm",       do_maxlvm,      0, },
  419     {   "maxlineintf",      do_maxintf,     0, },
  420     {   "maxlineifb",       do_maxifb,      0, },
  421     {   "maxlinenfsm",      do_maxnfsm,     0, },
  422     {   "maxlinecont",      do_maxcont,     0, },
  423     {   "maxlinenuma",      do_maxnuma,     0, },
  424     {   "maxlinellc",       do_maxllc,      0, },
  425     {   "colorinfo",        do_colinfo,     0, },
  426     {   "coloralmost",      do_colalmost,       0, },
  427     {   "colorcritical",    do_colcrit,     0, },
  428     {   "colorthread",      do_colthread,       0, },
  429     {   "ownallcpuline",    do_ownallcpuline,   0, },
  430     {   "ownonecpuline",    do_ownindivcpuline, 0, },
  431     {   "owncplline",       do_owncplline,      0, },
  432     {   "ownmemline",       do_ownmemline,      0, },
  433     {   "ownswpline",       do_ownswpline,      0, },
  434     {   "ownpagline",       do_ownpagline,      0, },
  435     {   "ownmemnumaline",   do_ownmemnumaline,  0, },
  436     {   "ownnumacpuline",   do_owncpunumaline,  0, },
  437     {   "ownllcline",       do_ownllcline,      0, },
  438     {   "owndskline",       do_owndskline,      0, },
  439     {   "ownnettrline",     do_ownnettransportline, 0, },
  440     {   "ownnetnetline",    do_ownnetnetline,   0, },
  441     {   "ownnetifline",         do_ownnetinterfaceline, 0, },
  442     {   "ownifbline",           do_owninfinibandline,   0, },
  443     {   "ownprocline",      do_ownprocline,     0, },
  444     {   "ownsysprcline",    do_ownsysprcline,   0, },
  445     {   "owndskline",           do_owndskline,      0, },
  446     {   "cpucritperc",      do_cpucritperc,     0, },
  447     {   "gpucritperc",      do_gpucritperc,     0, },
  448     {   "memcritperc",      do_memcritperc,     0, },
  449     {   "swpcritperc",      do_swpcritperc,     0, },
  450     {   "dskcritperc",      do_dskcritperc,     0, },
  451     {   "netcritperc",      do_netcritperc,     0, },
  452     {   "swoutcritsec",     do_swoutcritsec,    0, },
  453     {   "almostcrit",       do_almostcrit,      0, },
  454     {   "atopsarflags",     do_atopsarflags,    0, },
  455     {   "perfevents",       do_perfevents,      0, },
  456     {   "pacctdir",     do_pacctdir,        1, },
  457 };
  458 
  459 /*
  460 ** internal prototypes
  461 */
  462 static void engine(void);
  463 
  464 int
  465 main(int argc, char *argv[])
  466 {
  467     register int    i;
  468     int     c;
  469     char        *p;
  470     struct rlimit   rlim;
  471 
  472     /*
  473     ** since privileged actions will be done later on, at this stage
  474     ** the root-privileges are dropped by switching effective user-id
  475     ** to real user-id (security reasons)
  476     */
  477         if (! droprootprivs() )
  478     {
  479         fprintf(stderr, "not possible to drop root privs\n");
  480                 exit(42);
  481     }
  482 
  483     /*
  484     ** preserve command arguments to allow restart of other version
  485     */
  486     argvp = argv;
  487 
  488     /*
  489     ** read defaults-files /etc/atoprc en $HOME/.atoprc (if any)
  490     */
  491     readrc("/etc/atoprc", 1);
  492 
  493     if ( (p = getenv("HOME")) )
  494     {
  495         char path[1024];
  496 
  497         snprintf(path, sizeof path, "%s/.atoprc", p);
  498 
  499         readrc(path, 0);
  500     }
  501 
  502     /*
  503     ** check if we are supposed to behave as 'atopsar'
  504     ** i.e. system statistics only
  505     */
  506     if ( (p = strrchr(argv[0], '/')))
  507         p++;
  508     else
  509         p = argv[0];
  510 
  511     if ( memcmp(p, "atopsar", 7) == 0)
  512         return atopsar(argc, argv);
  513 
  514     /* 
  515     ** interpret command-line arguments & flags 
  516     */
  517     if (argc > 1)
  518     {
  519         /* 
  520         ** gather all flags for visualization-functions
  521         **
  522         ** generic flags will be handled here;
  523         ** unrecognized flags are passed to the print-routines
  524         */
  525         i = 0;
  526 
  527         while (i < MAXFL-1 && (c=getopt(argc, argv, allflags)) != EOF)
  528         {
  529             switch (c)
  530             {
  531                case '?':        /* usage wanted ?             */
  532                 prusage(argv[0]);
  533                 break;
  534 
  535                case 'V':        /* version wanted ?           */
  536                 printf("%s\n", getstrvers());
  537                 exit(0);
  538 
  539                case 'w':        /* writing of raw data ?      */
  540                 rawwriteflag++;
  541                 if (optind >= argc)
  542                     prusage(argv[0]);
  543 
  544                 strncpy(rawname, argv[optind++], RAWNAMESZ-1);
  545                 vis.show_samp = rawwrite;
  546                 break;
  547 
  548                case 'r':        /* reading of raw data ?      */
  549                 if (optind < argc)
  550                 {
  551                     if (*(argv[optind]) == '-')
  552                     {
  553                         if (strlen(argv[optind]) == 1)
  554                         {
  555                             strcpy(rawname,
  556                                 "/dev/stdin");
  557                             optind++;
  558                         }
  559                     }
  560                     else
  561                     {
  562                         strncpy(rawname, argv[optind],
  563                                 RAWNAMESZ-1);
  564                         optind++;
  565                     }
  566                 }
  567 
  568                 rawreadflag++;
  569                 break;
  570 
  571                case 'S':        /* midnight limit ?           */
  572                 midnightflag++;
  573                 break;
  574 
  575                            case 'b':        /* begin time ?               */
  576                 if ( !getbranchtime(optarg, &begintime) )
  577                     prusage(argv[0]);
  578                 break;
  579 
  580                            case 'e':        /* end   time ?               */
  581                 if ( !getbranchtime(optarg, &endtime) )
  582                     prusage(argv[0]);
  583                 break;
  584 
  585                            case 'P':        /* parseable output?          */
  586                 if ( !parsedef(optarg) )
  587                     prusage(argv[0]);
  588 
  589                 vis.show_samp = parseout;
  590                 break;
  591 
  592                            case 'J':        /* json output?          */
  593                 if ( !jsondef(optarg) )
  594                     prusage(argv[0]);
  595 
  596                 vis.show_samp = jsonout;
  597                 break;
  598 
  599                            case 'L':        /* line length                */
  600                 if ( !numeric(optarg) )
  601                     prusage(argv[0]);
  602 
  603                 linelen = atoi(optarg);
  604                 break;
  605 
  606                            case MALLPROC:   /* all processes per sample ? */
  607                 deviatonly = 0;
  608                 break;
  609 
  610                            case MCALCPSS:   /* calculate PSS per sample ? */
  611                 calcpss = 1;
  612                 break;
  613 
  614                            case MGETWCHAN:  /* obtain wchan string?       */
  615                 getwchan = 1;
  616                 break;
  617 
  618                            case MRMSPACES:  /* remove spaces from command */
  619                 rmspaces = 1;
  620                 break;
  621 
  622                default:     /* gather other flags */
  623                 flaglist[i++] = c;
  624             }
  625         }
  626 
  627         /*
  628         ** get optional interval-value and optional number of samples   
  629         */
  630         if (optind < argc && optind < MAXFL)
  631         {
  632             if (!numeric(argv[optind]))
  633                 prusage(argv[0]);
  634     
  635             interval = atoi(argv[optind]);
  636     
  637             optind++;
  638     
  639             if (optind < argc)
  640             {
  641                 if (!numeric(argv[optind]) )
  642                     prusage(argv[0]);
  643 
  644                 if ( (nsamples = atoi(argv[optind])) < 1)
  645                     prusage(argv[0]);
  646             }
  647         }
  648     }
  649 
  650     /*
  651     ** determine the name of this node (without domain-name)
  652     ** and the kernel-version
  653     */
  654     (void) uname(&utsname);
  655 
  656     if ( (p = strchr(utsname.nodename, '.')) )
  657         *p = '\0';
  658 
  659     utsnodenamelen = strlen(utsname.nodename);
  660 
  661     sscanf(utsname.release, "%d.%d.%d", &osrel, &osvers, &ossub);
  662 
  663     /*
  664     ** determine the clock rate and memory page size for this machine
  665     */
  666     hertz       = sysconf(_SC_CLK_TCK);
  667     pagesize    = sysconf(_SC_PAGESIZE);
  668     pidwidth    = getpidwidth();
  669 
  670     /*
  671     ** check if raw data from a file must be viewed
  672     */
  673     if (rawreadflag)
  674     {
  675         rawread();
  676         cleanstop(0);
  677     }
  678 
  679     /*
  680     ** determine start-time for gathering current statistics
  681     */
  682     curtime = getboot() / hertz;
  683 
  684     /*
  685     ** be sure to be leader of an own process group when
  686     ** running as a daemon (or at least: when not interactive);
  687     ** needed for systemd
  688     */
  689     if (rawwriteflag)
  690         (void) setpgid(0, 0);
  691 
  692     /*
  693     ** catch signals for proper close-down
  694     */
  695     signal(SIGHUP,  cleanstop);
  696     signal(SIGTERM, cleanstop);
  697 
  698     /*
  699     ** regain the root-privileges that we dropped at the beginning
  700     ** to do some privileged work
  701     */
  702     regainrootprivs();
  703 
  704     /*
  705     ** lock ATOP in memory to get reliable samples (also when
  706     ** memory is low and swapping is going on);
  707     ** ignored if not running under superuser privileges!
  708     */
  709     rlim.rlim_cur   = RLIM_INFINITY;
  710     rlim.rlim_max   = RLIM_INFINITY;
  711 
  712     if (setrlimit(RLIMIT_MEMLOCK, &rlim) == 0)
  713         (void) mlockall(MCL_CURRENT|MCL_FUTURE);
  714 
  715     /*
  716     ** increment CPU scheduling-priority to get reliable samples (also
  717     ** during heavy CPU load);
  718     ** ignored if not running under superuser privileges!
  719     */
  720     if ( nice(-20) == -1)
  721         ;
  722 
  723     set_oom_score_adj();
  724 
  725     /*
  726     ** switch-on the process-accounting mechanism to register the
  727     ** (remaining) resource-usage by processes which have finished
  728     */
  729     acctreason = acctswon();
  730 
  731     /*
  732     ** determine properties (like speed) of all interfaces
  733     */
  734     initifprop();
  735 
  736     /*
  737     ** open socket to the IP layer to issue getsockopt() calls later on
  738     */
  739     netatop_ipopen();
  740 
  741     /*
  742     ** since privileged activities are finished now, there is no
  743     ** need to keep running under root-privileges, so switch
  744     ** effective user-id to real user-id
  745     */
  746         if (! droprootprivs() )
  747         mcleanstop(42, "failed to drop root privs\n");
  748 
  749     /*
  750     ** start the engine now .....
  751     */
  752     engine();
  753 
  754     cleanstop(0);
  755 
  756     return 0;   /* never reached */
  757 }
  758 
  759 /*
  760 ** The engine() drives the main-loop of the program
  761 */
  762 static void
  763 engine(void)
  764 {
  765     struct sigaction    sigact;
  766     static time_t       timelimit;
  767     void            getusr1(int), getusr2(int);
  768 
  769     /*
  770     ** reserve space for system-level statistics
  771     */
  772     static struct sstat *cursstat; /* current   */
  773     static struct sstat *presstat; /* previous  */
  774     static struct sstat *devsstat; /* deviation */
  775     static struct sstat *hlpsstat;
  776 
  777     /*
  778     ** reserve space for task-level statistics
  779     */
  780     static struct tstat *curtpres;  /* current present list      */
  781     static unsigned long     curtlen;   /* size of present list      */
  782     struct tstat        *curpexit;  /* exited process list       */
  783 
  784     static struct devtstat  devtstat;   /* deviation info        */
  785 
  786     unsigned long       ntaskpres;  /* number of tasks present   */
  787     unsigned long       nprocexit;  /* number of exited procs    */
  788     unsigned long       nprocexitnet;   /* number of exited procs    */
  789                         /* via netatopd daemon       */
  790 
  791     unsigned long       noverflow;
  792 
  793     int                 nrgpuproc=0,    /* number of GPU processes    */
  794                 gpupending=0;   /* boolean: request sent      */
  795 
  796     struct gpupidstat   *gp = NULL;
  797 
  798     /*
  799     ** initialization: allocate required memory dynamically
  800     */
  801     cursstat = calloc(1, sizeof(struct sstat));
  802     presstat = calloc(1, sizeof(struct sstat));
  803     devsstat = calloc(1, sizeof(struct sstat));
  804 
  805     ptrverify(cursstat, "Malloc failed for current sysstats\n");
  806     ptrverify(presstat, "Malloc failed for prev    sysstats\n");
  807     ptrverify(devsstat, "Malloc failed for deviate sysstats\n");
  808 
  809     /*
  810     ** install the signal-handler for ALARM, USR1 and USR2 (triggers
  811     * for the next sample)
  812     */
  813     memset(&sigact, 0, sizeof sigact);
  814     sigact.sa_handler = getusr1;
  815     sigaction(SIGUSR1, &sigact, (struct sigaction *)0);
  816 
  817     memset(&sigact, 0, sizeof sigact);
  818     sigact.sa_handler = getusr2;
  819     sigaction(SIGUSR2, &sigact, (struct sigaction *)0);
  820 
  821     memset(&sigact, 0, sizeof sigact);
  822     sigact.sa_handler = getalarm;
  823     sigaction(SIGALRM, &sigact, (struct sigaction *)0);
  824 
  825     if (interval > 0)
  826         alarm(interval);
  827 
  828     if (midnightflag)
  829     {
  830         time_t      timenow = time(0);
  831         struct tm   *tp = localtime(&timenow);
  832 
  833         tp->tm_hour = 23;
  834         tp->tm_min  = 59;
  835         tp->tm_sec  = 59;
  836 
  837         timelimit = mktime(tp);
  838     }
  839 
  840     /*
  841     ** open socket to the atopgpud daemon for GPU statistics
  842     */
  843         nrgpus = gpud_init();
  844 
  845     if (nrgpus)
  846         supportflags |= GPUSTAT;
  847 
  848     /*
  849     ** MAIN-LOOP:
  850     **    - Wait for the requested number of seconds or for other trigger
  851     **
  852     **    - System-level counters
  853     **      get current counters
  854     **      calculate the differences with the previous sample
  855     **
  856     **    - Process-level counters
  857     **      get current counters from running & exited processes
  858     **      calculate the differences with the previous sample
  859     **
  860     **    - Call the print-function to visualize the differences
  861     */
  862     for (sampcnt=0; sampcnt < nsamples; sampcnt++)
  863     {
  864         char    lastcmd;
  865 
  866         /*
  867         ** if the limit-flag is specified:
  868         **  check if the next sample is expected before midnight;
  869         **  if not, stop atop now 
  870         */
  871         if (midnightflag && (curtime+interval) > timelimit)
  872             break;
  873 
  874         /*
  875         ** wait for alarm-signal to arrive (except first sample)
  876         ** or wait for SIGUSR1/SIGUSR2
  877         */
  878         if (sampcnt > 0 && awaittrigger)
  879             pause();
  880 
  881         awaittrigger = 1;
  882 
  883         /*
  884         ** gather time info for this sample
  885         */
  886         pretime  = curtime;
  887         curtime  = time(0);     /* seconds since 1-1-1970 */
  888 
  889         /*
  890         ** send request for statistics to atopgpud 
  891         */
  892         if (nrgpus)
  893             gpupending = gpud_statrequest();
  894 
  895         /*
  896         ** take a snapshot of the current system-level statistics 
  897         ** and calculate the deviations (i.e. calculate the activity
  898         ** during the last sample)
  899         */
  900         hlpsstat = cursstat;    /* swap current/prev. stats */
  901         cursstat = presstat;
  902         presstat = hlpsstat;
  903 
  904         photosyst(cursstat);    /* obtain new counters      */
  905 
  906         /*
  907         ** receive and parse response from atopgpud
  908         */
  909         if (nrgpus && gpupending)
  910         {
  911             nrgpuproc = gpud_statresponse(nrgpus, cursstat->gpu.gpu, &gp);
  912 
  913             gpupending = 0;
  914 
  915             // connection lost or timeout on receive?
  916             if (nrgpuproc == -1)
  917             {
  918                 int ng;
  919 
  920                 // try to reconnect
  921                     ng = gpud_init();
  922 
  923                 if (ng != nrgpus)   // no success
  924                     nrgpus = 0;
  925 
  926                 if (nrgpus)
  927                 {
  928                     // request for stats again
  929                     if (gpud_statrequest())
  930                     {
  931                         // receive stats response
  932                         nrgpuproc = gpud_statresponse(nrgpus,
  933                              cursstat->gpu.gpu, &gp);
  934 
  935                         // persistent failure?
  936                         if (nrgpuproc == -1)
  937                             nrgpus = 0;
  938                     }
  939                 }
  940             }
  941 
  942             cursstat->gpu.nrgpus = nrgpus;
  943         }
  944 
  945         deviatsyst(cursstat, presstat, devsstat,
  946                 curtime-pretime > 0 ? curtime-pretime : 1);
  947 
  948         /*
  949         ** take a snapshot of the current task-level statistics 
  950         ** and calculate the deviations (i.e. calculate the activity
  951         ** during the last sample)
  952         **
  953         ** first register active tasks
  954         */
  955         curtpres  = NULL;
  956 
  957         do
  958         {
  959             curtlen   = counttasks();   // worst-case value
  960             curtpres  = realloc(curtpres,
  961                     curtlen * sizeof(struct tstat));
  962 
  963             ptrverify(curtpres, "Malloc failed for %lu tstats\n",
  964                                 curtlen);
  965 
  966             memset(curtpres, 0, curtlen * sizeof(struct tstat));
  967         }
  968         while ( (ntaskpres = photoproc(curtpres, curtlen)) == curtlen);
  969 
  970         /*
  971         ** register processes that exited during last sample;
  972         ** first determine how many processes exited
  973         **
  974         ** the number of exited processes is limited to avoid
  975         ** that atop explodes in memory and introduces OOM killing
  976         */
  977         nprocexit = acctprocnt();   /* number of exited processes */
  978 
  979         if (nprocexit > MAXACCTPROCS)
  980         {
  981             noverflow = nprocexit - MAXACCTPROCS;
  982             nprocexit = MAXACCTPROCS;
  983         }
  984         else
  985             noverflow = 0;
  986 
  987         /*
  988         ** determine how many processes have been exited
  989         ** for the netatop module (only processes that have
  990         ** used the network)
  991         */
  992         if (nprocexit > 0 && (supportflags & NETATOPD))
  993             nprocexitnet = netatop_exitstore();
  994         else
  995             nprocexitnet = 0;
  996 
  997         /*
  998         ** reserve space for the exited processes and read them
  999         */
 1000         if (nprocexit > 0)
 1001         {
 1002             curpexit = malloc(nprocexit * sizeof(struct tstat));
 1003 
 1004             ptrverify(curpexit,
 1005                       "Malloc failed for %lu exited processes\n",
 1006                       nprocexit);
 1007 
 1008             memset(curpexit, 0, nprocexit * sizeof(struct tstat));
 1009 
 1010             nprocexit = acctphotoproc(curpexit, nprocexit);
 1011 
 1012             /*
 1013             ** reposition offset in accounting file when not
 1014             ** all exited processes have been read (i.e. skip
 1015             ** those processes)
 1016             */
 1017             if (noverflow)
 1018                 acctrepos(noverflow);
 1019         }
 1020         else
 1021         {
 1022             curpexit    = NULL;
 1023         }
 1024 
 1025         /*
 1026         ** merge GPU per-process stats with other per-process stats
 1027         */
 1028         if (nrgpus && nrgpuproc)
 1029             gpumergeproc(curtpres, ntaskpres,
 1030                              curpexit, nprocexit,
 1031                          gp,       nrgpuproc);
 1032 
 1033         /*
 1034         ** calculate deviations
 1035         */
 1036         deviattask(curtpres,  ntaskpres, curpexit,  nprocexit,
 1037                               &devtstat, devsstat);
 1038 
 1039         /*
 1040         ** activate the installed print-function to visualize
 1041         ** the deviations
 1042         */
 1043         lastcmd = (vis.show_samp)( curtime,
 1044                      curtime-pretime > 0 ? curtime-pretime : 1,
 1045                          &devtstat, devsstat, 
 1046                              nprocexit, noverflow, sampcnt==0);
 1047 
 1048         /*
 1049         ** release dynamically allocated memory
 1050         */
 1051         if (nprocexit > 0)
 1052             free(curpexit);
 1053 
 1054         free(curtpres);
 1055 
 1056         if (nprocexitnet > 0)
 1057             netatop_exiterase();
 1058 
 1059         if (gp)
 1060              free(gp);
 1061 
 1062         if (lastcmd == 'r') /* reset requested ? */
 1063         {
 1064             sampcnt = -1;
 1065 
 1066             curtime = getboot() / hertz;    // reset current time
 1067 
 1068             /* set current (will be 'previous') counters to 0 */
 1069             memset(cursstat, 0,           sizeof(struct sstat));
 1070 
 1071             /* remove all tasks in database */
 1072             pdb_makeresidue();
 1073             pdb_cleanresidue();
 1074         }
 1075     } /* end of main-loop */
 1076 }
 1077 
 1078 /*
 1079 ** print usage of this command
 1080 */
 1081 void
 1082 prusage(char *myname)
 1083 {
 1084     printf("Usage: %s [-flags] [interval [samples]]\n",
 1085                     myname);
 1086     printf("\t\tor\n");
 1087     printf("Usage: %s -w  file  [-S] [-%c] [interval [samples]]\n",
 1088                     myname, MALLPROC);
 1089     printf("       %s -r [file] [-b [YYYYMMDD]hhmm] [-e [YYYYMMDD]hhmm] [-flags]\n",
 1090                     myname);
 1091     printf("\n");
 1092     printf("\tgeneric flags:\n");
 1093     printf("\t  -%c  show version information\n", MVERSION);
 1094     printf("\t  -%c  show or log all processes (i.s.o. active processes "
 1095                     "only)\n", MALLPROC);
 1096     printf("\t  -%c  calculate proportional set size (PSS) per process\n", 
 1097                     MCALCPSS);
 1098     printf("\t  -%c  determine WCHAN (string) per thread\n", MGETWCHAN);
 1099     printf("\t  -P  generate parseable output for specified label(s)\n");
 1100     printf("\t  -J  generate JSON output for specified label(s)\n");
 1101     printf("\t  -%c  no spaces in parseable output for command (line)\n",
 1102             MRMSPACES);
 1103     printf("\t  -L  alternate line length (default 80) in case of "
 1104             "non-screen output\n");
 1105 
 1106     if (vis.show_usage)
 1107         (*vis.show_usage)();
 1108 
 1109     printf("\n");
 1110     printf("\tspecific flags for raw logfiles:\n");
 1111     printf("\t  -w  write raw data to   file (compressed)\n");
 1112     printf("\t  -r  read  raw data from file (compressed)\n");
 1113     printf("\t      symbolic file: y[y...] for yesterday (repeated)\n");
 1114     printf("\t      file name '-': read raw data from stdin\n");
 1115     printf("\t  -S  finish atop automatically before midnight "
 1116                     "(i.s.o. #samples)\n");
 1117     printf("\t  -b  begin showing data from specified date/time\n");
 1118     printf("\t  -e  finish showing data after specified date/time\n");
 1119     printf("\n");
 1120     printf("\tinterval: number of seconds   (minimum 0)\n");
 1121     printf("\tsamples:  number of intervals (minimum 1)\n");
 1122     printf("\n");
 1123     printf("If the interval-value is zero, a new sample can be\n");
 1124     printf("forced manually by sending signal USR1"
 1125             " (kill -USR1 pid_atop)\n");
 1126     printf("or with the keystroke '%c' in interactive mode.\n", MSAMPNEXT);
 1127     printf("\n");
 1128     printf("Please refer to the man-page of 'atop' for more details.\n");
 1129 
 1130     cleanstop(1);
 1131 }
 1132 
 1133 /*
 1134 ** handler for ALRM-signal
 1135 */
 1136 void
 1137 getalarm(int sig)
 1138 {
 1139     awaittrigger=0;
 1140 
 1141     if (interval > 0)
 1142         alarm(interval);    /* restart the timer */
 1143 }
 1144 
 1145 /*
 1146 ** handler for USR1-signal
 1147 */
 1148 void
 1149 getusr1(int sig)
 1150 {
 1151     awaittrigger=0;
 1152 }
 1153 
 1154 /*
 1155 ** handler for USR2-signal
 1156 */
 1157 void
 1158 getusr2(int sig)
 1159 {
 1160     awaittrigger=0;
 1161     nsamples = sampcnt; // force stop after next sample
 1162 }
 1163 
 1164 /*
 1165 ** functions to handle a particular tag in the .atoprc file
 1166 */
 1167 extern int get_posval(char *name, char *val);
 1168 
 1169 void
 1170 do_interval(char *name, char *val)
 1171 {
 1172     interval = get_posval(name, val);
 1173 }
 1174 
 1175 void
 1176 do_linelength(char *name, char *val)
 1177 {
 1178     linelen = get_posval(name, val);
 1179 }
 1180 
 1181 /*
 1182 ** read RC-file and modify defaults accordingly
 1183 */
 1184 static void
 1185 readrc(char *path, int syslevel)
 1186 {
 1187     int i, nr, line=0, errorcnt = 0;
 1188 
 1189     /*
 1190     ** check if this file is readable with the user's
 1191     ** *real uid/gid* with syscall access()
 1192     */
 1193     if ( access(path, R_OK) == 0)
 1194     {
 1195         FILE    *fp;
 1196         char    linebuf[256], tagname[20], tagvalue[256];
 1197 
 1198         fp = fopen(path, "r");
 1199 
 1200         while ( fgets(linebuf, sizeof linebuf, fp) )
 1201         {
 1202             line++;
 1203 
 1204             i = strlen(linebuf);
 1205 
 1206             if (i <= 1) // empty line?
 1207                 continue;
 1208 
 1209             if (linebuf[i-1] == '\n')
 1210                 linebuf[i-1] = 0;
 1211 
 1212             nr = sscanf(linebuf, "%19s %255[^#]",
 1213                         tagname, tagvalue);
 1214 
 1215             switch (nr)
 1216             {
 1217                case 0:
 1218                 continue;
 1219 
 1220                case 1:
 1221                 if (tagname[0] == '#')
 1222                     continue;
 1223 
 1224                 mcleanstop(1,
 1225                     "%s: syntax error line "
 1226                     "%d (no value specified)\n",
 1227                     path, line);
 1228 
 1229                 break;      /* not reached */
 1230 
 1231                default:
 1232                 if (tagname[0] == '#')
 1233                     continue;
 1234                 
 1235                 if (tagvalue[0] != '#')
 1236                     break;
 1237 
 1238                 mcleanstop(1,
 1239                     "%s: syntax error line "
 1240                     "%d (no value specified)\n",
 1241                     path, line);
 1242             }
 1243 
 1244             /*
 1245             ** tag name and tag value found
 1246             ** try to recognize tag name
 1247             */
 1248             for (i=0; i < sizeof manrc/sizeof manrc[0]; i++)
 1249             {
 1250                 if ( strcmp(tagname, manrc[i].tag) == 0)
 1251                 {
 1252                     if (manrc[i].sysonly && !syslevel)
 1253                     {
 1254                         fprintf(stderr,
 1255                            "%s: warning at line %2d "
 1256                            "- tag name %s not allowed "
 1257                            "in private atoprc\n",
 1258                             path, line, tagname);
 1259 
 1260                         errorcnt++;
 1261                         break;
 1262                     }
 1263 
 1264                     manrc[i].func(tagname, tagvalue);
 1265                     break;
 1266                 }
 1267             }
 1268 
 1269             /*
 1270             ** tag name not recognized
 1271             */
 1272             if (i == sizeof manrc/sizeof manrc[0])
 1273             {
 1274                 fprintf(stderr,
 1275                     "%s: warning at line %2d "
 1276                     "- tag name %s not valid\n",
 1277                     path, line, tagname);
 1278 
 1279                 errorcnt++;
 1280             }
 1281         }
 1282 
 1283         if (errorcnt)
 1284             sleep(2);
 1285 
 1286         fclose(fp);
 1287     }
 1288 }