// a := a + b for struct timevals void QedApp::timevalAdd(struct timeval *a, struct timeval *b) { __pmtimevalInc(a, b); }
/* ** The engine() drives the main-loop of the program */ void engine(void) { int i, j; struct sigaction sigact; double timed, delta; void getusr1(int), getusr2(int); /* ** reserve space for system-level statistics */ static struct sstat *cursstat; /* current */ static struct sstat *presstat; /* previous */ static struct sstat *devsstat; /* deviation */ static struct sstat *hlpsstat; /* ** reserve space for task-level statistics */ static struct tstat *curtpres; /* current present list */ static int curtlen; /* size of present list */ struct tstat *curpexit; /* exited process list */ struct tstat *devtstat; /* deviation list */ struct tstat **devpstat; /* pointers to processes */ /* in deviation list */ unsigned int ntaskpres; /* number of tasks present */ unsigned int nprocexit; /* number of exited procs */ unsigned int nprocexitnet; /* number of exited procs */ /* via netatopd daemon */ unsigned int ntaskdev; /* nr of tasks deviated */ unsigned int nprocdev; /* nr of procs deviated */ int nprocpres; /* nr of procs present */ int totrun, totslpi, totslpu, totzombie; unsigned int noverflow; /* ** initialization: allocate required memory dynamically */ cursstat = sstat_alloc("current sysstats"); presstat = sstat_alloc("prev sysstats"); devsstat = sstat_alloc("deviate sysstats"); curtlen = PROCMIN * 3 / 2; /* add 50% for threads */ curtpres = calloc(curtlen, sizeof(struct tstat)); ptrverify(curtpres, "Malloc failed for %d procstats\n", curtlen); /* ** install the signal-handler for ALARM, USR1 and USR2 (triggers ** for the next sample) */ memset(&sigact, 0, sizeof sigact); sigact.sa_handler = getusr1; sigaction(SIGUSR1, &sigact, (struct sigaction *)0); memset(&sigact, 0, sizeof sigact); sigact.sa_handler = getusr2; sigaction(SIGUSR2, &sigact, (struct sigaction *)0); memset(&sigact, 0, sizeof sigact); sigact.sa_handler = getalarm; sigaction(SIGALRM, &sigact, (struct sigaction *)0); if (interval.tv_sec || interval.tv_usec) setalarm(&interval); /* ** MAIN-LOOP: ** - Wait for the requested number of seconds or for other trigger ** ** - System-level counters ** get current counters ** calculate the differences with the previous sample ** ** - Process-level counters ** get current counters from running & exited processes ** calculate the differences with the previous sample ** ** - Call the print-function to visualize the differences */ for (sampcnt=0; sampcnt < nsamples; sampcnt++) { char lastcmd; /* ** wait for alarm-signal to arrive (except first sample) ** or wait for SIGUSR1/SIGUSR2 */ if (sampcnt > 0 && awaittrigger && !rawreadflag) pause(); awaittrigger = 1; /* ** take a snapshot of the current system-level statistics */ hlpsstat = cursstat; /* swap current/prev. stats */ cursstat = presstat; presstat = hlpsstat; photosyst(cursstat); /* obtain new counters */ /* ** take a snapshot of the current task-level statistics ** ** first register active tasks ** --> atop malloc's a minimal amount of space which is ** only extended when needed */ memset(curtpres, 0, curtlen * sizeof(struct tstat)); ntaskpres = photoproc(&curtpres, &curtlen); /* ** register processes that exited during last sample; ** first determine how many processes exited ** ** the number of exited processes is limited to avoid ** that atop explodes in memory and introduces OOM killing */ nprocexit = acctprocnt(); /* number of exited processes */ if (nprocexit > MAXACCTPROCS) { noverflow = nprocexit - MAXACCTPROCS; nprocexit = MAXACCTPROCS; } else noverflow = 0; /* ** determine how many processes have been exited ** for the netatop module (only processes that have ** used the network) */ if (nprocexit > 0 && (supportflags & NETATOPD)) nprocexitnet = netatop_exitstore(); else nprocexitnet = 0; /* ** reserve space for the exited processes and read them */ if (nprocexit > 0) { curpexit = malloc(nprocexit * sizeof(struct tstat)); ptrverify(curpexit, "Malloc failed for %d exited processes\n", nprocexit); memset(curpexit, 0, nprocexit * sizeof(struct tstat)); nprocexit = acctphotoproc(curpexit, nprocexit); /* ** reposition offset in accounting file when not ** all exited processes have been read (i.e. skip ** those processes) */ if (noverflow) acctrepos(noverflow); } else { curpexit = NULL; } /* ** calculate the deviations (i.e. calculate the activity ** during the last sample). Note for PMAPI calls we had ** to delay changing curtime until after sampling due to ** the way pmSetMode(3) works. */ pretime = curtime; /* timestamp for previous sample */ curtime = cursstat->stamp; /* timestamp for this sample */ timed = __pmtimevalToReal(&curtime); delta = timed - __pmtimevalToReal(&pretime); deviatsyst(cursstat, presstat, devsstat, delta); devtstat = malloc((ntaskpres+nprocexit) * sizeof(struct tstat)); ptrverify(devtstat, "Malloc failed for %d modified tasks\n", ntaskpres+nprocexit); ntaskdev = deviattask(curtpres, ntaskpres, curpexit, nprocexit, deviatonly, devtstat, devsstat, &nprocdev, &nprocpres, &totrun, &totslpi, &totslpu, &totzombie); /* ** create list of pointers specifically to the process entries ** in the task list */ devpstat = malloc(sizeof (struct tstat *) * nprocdev); ptrverify(devpstat, "Malloc failed for %d process ptrs\n", nprocdev); for (i=0, j=0; i < ntaskdev; i++) { if ( (devtstat+i)->gen.isproc) devpstat[j++] = devtstat+i; } /* ** activate the installed print-function to visualize ** the deviations */ lastcmd = (vis.show_samp)(timed, delta > 1.0 ? delta : 1.0, devsstat, devtstat, devpstat, ntaskdev, ntaskpres, nprocdev, nprocpres, totrun, totslpi, totslpu, totzombie, nprocexit, noverflow, sampcnt==0); if (rawreadflag) __pmtimevalInc(&curtime, &interval); /* ** release dynamically allocated memory */ if (nprocexit > 0) free(curpexit); if (nprocexitnet > 0) netatop_exiterase(); free(devtstat); free(devpstat); if (lastcmd == 'r') /* reset requested ? */ { sampcnt = -1; curtime = origin; /* set current (will be 'previous') counters to 0 */ memset(curtpres, 0, curtlen * sizeof(struct tstat)); sstat_reset(cursstat); /* remove all tasks in database */ pdb_makeresidue(); pdb_cleanresidue(); } } /* end of main-loop */ }