int photoproc(struct tstat *tasks, int *taskslen) { static int setup; static pmID pmids[TASK_NMETRICS]; static pmDesc descs[TASK_NMETRICS]; pmResult *result; char **insts; int *pids, count, i; if (!setup) { setup_metrics(procmetrics, pmids, descs, TASK_NMETRICS); setup = 1; } fetch_metrics("task", TASK_NMETRICS, pmids, &result); /* extract external process names (insts) */ count = get_instances("task", TASK_GEN_NAME, descs, &pids, &insts); if (count > *taskslen) { size_t size; int ents = (*taskslen + PROCCHUNK); if (count > ents) ents = count; size = ents * sizeof(struct tstat); tasks = (struct tstat *)realloc(tasks, size); ptrverify(tasks, "photoproc [%ld]\n", (long)size); *taskslen = ents; } for (i=0; i < count; i++) { if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "%s: updating process %d: %s\n", pmProgname, pids[i], insts[i]); update_task(&tasks[i], pids[i], insts[i], result, descs); } if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "%s: done %d processes\n", pmProgname, count); pmFreeResult(result); free(insts); free(pids); return count; }
/* ** calculate the system-activity during the last sample */ void deviatsyst(struct sstat *cur, struct sstat *pre, struct sstat *dev) { register int i, j; size_t size; count_t *cdev, *ccur, *cpre; if (cur->cpu.nrcpu != dev->cpu.nrcpu) { size = cur->cpu.nrcpu * sizeof(struct percpu); dev->cpu.cpu = (struct percpu *)realloc(dev->cpu.cpu, size); ptrverify(dev->cpu.cpu, "deviatsyst cpus [%ld]", (long)size); } if (cur->cpu.nrcpu > pre->cpu.nrcpu) { free(pre->cpu.cpu); size = cur->cpu.nrcpu * sizeof(struct percpu); pre->cpu.cpu = (struct percpu *)calloc(1, size); ptrverify(pre->cpu.cpu, "deviatsyst precpus [%ld]", (long)size); } dev->cpu.nrcpu = cur->cpu.nrcpu; dev->cpu.devint = subcount(cur->cpu.devint, pre->cpu.devint); dev->cpu.csw = subcount(cur->cpu.csw, pre->cpu.csw); dev->cpu.nprocs = subcount(cur->cpu.nprocs, pre->cpu.nprocs); dev->cpu.all.stime = subcount(cur->cpu.all.stime, pre->cpu.all.stime); dev->cpu.all.utime = subcount(cur->cpu.all.utime, pre->cpu.all.utime); dev->cpu.all.ntime = subcount(cur->cpu.all.ntime, pre->cpu.all.ntime); dev->cpu.all.itime = subcount(cur->cpu.all.itime, pre->cpu.all.itime); dev->cpu.all.wtime = subcount(cur->cpu.all.wtime, pre->cpu.all.wtime); dev->cpu.all.Itime = subcount(cur->cpu.all.Itime, pre->cpu.all.Itime); dev->cpu.all.Stime = subcount(cur->cpu.all.Stime, pre->cpu.all.Stime); dev->cpu.all.steal = subcount(cur->cpu.all.steal, pre->cpu.all.steal); dev->cpu.all.guest = subcount(cur->cpu.all.guest, pre->cpu.all.guest); for (i=0; i < dev->cpu.nrcpu; i++) { count_t ticks; dev->cpu.cpu[i].cpunr = cur->cpu.cpu[i].cpunr; dev->cpu.cpu[i].stime = subcount(cur->cpu.cpu[i].stime, pre->cpu.cpu[i].stime); dev->cpu.cpu[i].utime = subcount(cur->cpu.cpu[i].utime, pre->cpu.cpu[i].utime); dev->cpu.cpu[i].ntime = subcount(cur->cpu.cpu[i].ntime, pre->cpu.cpu[i].ntime); dev->cpu.cpu[i].itime = subcount(cur->cpu.cpu[i].itime, pre->cpu.cpu[i].itime); dev->cpu.cpu[i].wtime = subcount(cur->cpu.cpu[i].wtime, pre->cpu.cpu[i].wtime); dev->cpu.cpu[i].Itime = subcount(cur->cpu.cpu[i].Itime, pre->cpu.cpu[i].Itime); dev->cpu.cpu[i].Stime = subcount(cur->cpu.cpu[i].Stime, pre->cpu.cpu[i].Stime); dev->cpu.cpu[i].steal = subcount(cur->cpu.cpu[i].steal, pre->cpu.cpu[i].steal); dev->cpu.cpu[i].guest = subcount(cur->cpu.cpu[i].guest, pre->cpu.cpu[i].guest); ticks = cur->cpu.cpu[i].freqcnt.ticks; dev->cpu.cpu[i].freqcnt.maxfreq = cur->cpu.cpu[i].freqcnt.maxfreq; dev->cpu.cpu[i].freqcnt.cnt = ticks ? subcount(cur->cpu.cpu[i].freqcnt.cnt, pre->cpu.cpu[i].freqcnt.cnt) : cur->cpu.cpu[i].freqcnt.cnt; dev->cpu.cpu[i].freqcnt.ticks = ticks ? subcount(cur->cpu.cpu[i].freqcnt.ticks, pre->cpu.cpu[i].freqcnt.ticks) : cur->cpu.cpu[i].freqcnt.ticks; } dev->cpu.lavg1 = cur->cpu.lavg1; dev->cpu.lavg5 = cur->cpu.lavg5; dev->cpu.lavg15 = cur->cpu.lavg15; dev->mem.physmem = cur->mem.physmem; dev->mem.freemem = cur->mem.freemem; dev->mem.buffermem = cur->mem.buffermem; dev->mem.slabmem = cur->mem.slabmem; dev->mem.slabreclaim = cur->mem.slabreclaim; dev->mem.committed = cur->mem.committed; dev->mem.commitlim = cur->mem.commitlim; dev->mem.cachemem = cur->mem.cachemem; dev->mem.cachedrt = cur->mem.cachedrt; dev->mem.totswap = cur->mem.totswap; dev->mem.freeswap = cur->mem.freeswap; dev->mem.shmem = cur->mem.shmem; dev->mem.shmrss = cur->mem.shmrss; dev->mem.shmswp = cur->mem.shmswp; dev->mem.tothugepage = cur->mem.tothugepage; dev->mem.freehugepage = cur->mem.freehugepage; dev->mem.hugepagesz = cur->mem.hugepagesz; dev->mem.vmwballoon = cur->mem.vmwballoon; dev->mem.swouts = subcount(cur->mem.swouts, pre->mem.swouts); dev->mem.swins = subcount(cur->mem.swins, pre->mem.swins); dev->mem.pgscans = subcount(cur->mem.pgscans, pre->mem.pgscans); dev->mem.pgsteal = subcount(cur->mem.pgsteal, pre->mem.pgsteal); dev->mem.allocstall = subcount(cur->mem.allocstall, pre->mem.allocstall); /* ** structures with network-related counters are considered ** as tables of frequency-counters that have to be subtracted; ** values that do not represent a frequency are corrected afterwards */ for (cdev = (count_t *)&dev->net.ipv4, ccur = (count_t *)&cur->net.ipv4, cpre = (count_t *)&pre->net.ipv4, i = 0; i < (sizeof dev->net.ipv4 / sizeof(count_t)); cdev++, ccur++, cpre++, i++) *cdev = *ccur - *cpre; dev->net.ipv4.Forwarding = cur->net.ipv4.Forwarding; dev->net.ipv4.DefaultTTL = cur->net.ipv4.DefaultTTL; /* ------------- */ for (cdev = (count_t *)&dev->net.icmpv4, ccur = (count_t *)&cur->net.icmpv4, cpre = (count_t *)&pre->net.icmpv4, i = 0; i < (sizeof dev->net.icmpv4 / sizeof(count_t)); cdev++, ccur++, cpre++, i++) *cdev = *ccur - *cpre; /* ------------- */ for (cdev = (count_t *)&dev->net.udpv4, ccur = (count_t *)&cur->net.udpv4, cpre = (count_t *)&pre->net.udpv4, i = 0; i < (sizeof dev->net.udpv4 / sizeof(count_t)); cdev++, ccur++, cpre++, i++) *cdev = *ccur - *cpre; /* ------------- */ for (cdev = (count_t *)&dev->net.ipv6, ccur = (count_t *)&cur->net.ipv6, cpre = (count_t *)&pre->net.ipv6, i = 0; i < (sizeof dev->net.ipv6 / sizeof(count_t)); cdev++, ccur++, cpre++, i++) *cdev = *ccur - *cpre; /* ------------- */ for (cdev = (count_t *)&dev->net.icmpv6, ccur = (count_t *)&cur->net.icmpv6, cpre = (count_t *)&pre->net.icmpv6, i = 0; i < (sizeof dev->net.icmpv6 / sizeof(count_t)); cdev++, ccur++, cpre++, i++) *cdev = *ccur - *cpre; /* ------------- */ for (cdev = (count_t *)&dev->net.udpv6, ccur = (count_t *)&cur->net.udpv6, cpre = (count_t *)&pre->net.udpv6, i = 0; i < (sizeof dev->net.udpv6 / sizeof(count_t)); cdev++, ccur++, cpre++, i++) *cdev = *ccur - *cpre; /* ------------- */ for (cdev = (count_t *)&dev->net.tcp, ccur = (count_t *)&cur->net.tcp, cpre = (count_t *)&pre->net.tcp, i = 0; i < (sizeof dev->net.tcp / sizeof(count_t)); cdev++, ccur++, cpre++, i++) *cdev = *ccur - *cpre; dev->net.tcp.RtoAlgorithm = cur->net.tcp.RtoAlgorithm; dev->net.tcp.RtoMin = cur->net.tcp.RtoMin; dev->net.tcp.RtoMax = cur->net.tcp.RtoMax; dev->net.tcp.MaxConn = cur->net.tcp.MaxConn; dev->net.tcp.CurrEstab = cur->net.tcp.CurrEstab; /* ** calculate deviations for interfaces */ if (cur->intf.nrintf != dev->intf.nrintf) { size = (cur->intf.nrintf + 1) * sizeof(struct perintf); dev->intf.intf = (struct perintf *)realloc(dev->intf.intf, size); ptrverify(dev->intf.intf, "deviatsyst intf [%ld]\n", (long)size); } if (pre->intf.nrintf < cur->intf.nrintf) /* first sample? */ { struct ifprop ifprop; free(pre->intf.intf); size = (cur->intf.nrintf + 1) * sizeof(struct perintf); pre->intf.intf = (struct perintf *)calloc(1, size); ptrverify(pre->intf.intf, "deviatsyst preintf [%ld]\n", size); for (i=0; cur->intf.intf[i].name[0]; i++) { strcpy(pre->intf.intf[i].name, cur->intf.intf[i].name); strcpy(ifprop.name, cur->intf.intf[i].name); getifprop(&ifprop); pre->intf.intf[i].speed = ifprop.speed; pre->intf.intf[i].duplex = ifprop.fullduplex; } pre->intf.intf[i].name[0] = '\0'; } for (i=0; cur->intf.intf && cur->intf.intf[i].name[0]; i++) { /* ** check if an interface has been added or removed; ** in that case, skip further handling for this sample */ if (strcmp(cur->intf.intf[i].name, pre->intf.intf[i].name) != 0) { int j; struct ifprop ifprop; /* ** take care that interface properties are ** corrected for future samples */ initifprop(); /* refresh interface info */ for (j=0; cur->intf.intf[j].name[0]; j++) { strcpy(ifprop.name, cur->intf.intf[j].name); getifprop(&ifprop); cur->intf.intf[j].speed = ifprop.speed; cur->intf.intf[j].duplex = ifprop.fullduplex; } break; } /* ** calculate interface deviations for this sample */ strcpy(dev->intf.intf[i].name, cur->intf.intf[i].name); dev->intf.intf[i].rbyte = subcount(cur->intf.intf[i].rbyte, pre->intf.intf[i].rbyte); dev->intf.intf[i].rpack = subcount(cur->intf.intf[i].rpack, pre->intf.intf[i].rpack); dev->intf.intf[i].rerrs = subcount(cur->intf.intf[i].rerrs, pre->intf.intf[i].rerrs); dev->intf.intf[i].rdrop = subcount(cur->intf.intf[i].rdrop, pre->intf.intf[i].rdrop); dev->intf.intf[i].rfifo = subcount(cur->intf.intf[i].rfifo, pre->intf.intf[i].rfifo); dev->intf.intf[i].rframe= subcount(cur->intf.intf[i].rframe, pre->intf.intf[i].rframe); dev->intf.intf[i].rcompr= subcount(cur->intf.intf[i].rcompr, pre->intf.intf[i].rcompr); dev->intf.intf[i].rmultic=subcount(cur->intf.intf[i].rmultic, pre->intf.intf[i].rmultic); dev->intf.intf[i].sbyte = subcount(cur->intf.intf[i].sbyte, pre->intf.intf[i].sbyte); dev->intf.intf[i].spack = subcount(cur->intf.intf[i].spack, pre->intf.intf[i].spack); dev->intf.intf[i].serrs = subcount(cur->intf.intf[i].serrs, pre->intf.intf[i].serrs); dev->intf.intf[i].sdrop = subcount(cur->intf.intf[i].sdrop, pre->intf.intf[i].sdrop); dev->intf.intf[i].sfifo = subcount(cur->intf.intf[i].sfifo, pre->intf.intf[i].sfifo); dev->intf.intf[i].scollis= subcount(cur->intf.intf[i].scollis, pre->intf.intf[i].scollis); dev->intf.intf[i].scarrier= subcount(cur->intf.intf[i].scarrier, pre->intf.intf[i].scarrier); dev->intf.intf[i].scompr= subcount(cur->intf.intf[i].scompr, pre->intf.intf[i].scompr); dev->intf.intf[i].speed = pre->intf.intf[i].speed; dev->intf.intf[i].duplex = pre->intf.intf[i].duplex; /* ** save interface properties for next interval */ cur->intf.intf[i].speed = pre->intf.intf[i].speed; cur->intf.intf[i].duplex = pre->intf.intf[i].duplex; } dev->intf.intf[i].name[0] = '\0'; dev->intf.nrintf = i; /* ** calculate deviations for disks */ if (cur->dsk.ndsk != dev->dsk.ndsk) { size = (cur->dsk.ndsk + 1) * sizeof(struct perdsk); dev->dsk.dsk = (struct perdsk *)realloc(dev->dsk.dsk, size); ptrverify(dev->dsk.dsk, "deviatsyst disk [%ld]\n", (long)size); } for (i=j=0; cur->dsk.dsk && cur->dsk.dsk[i].name[0]; i++) { int realj = j; /* ** check if disk has been added or removed since ** previous interval */ if (pre->dsk.dsk[j].name[0] == '\0' || strcmp(cur->dsk.dsk[i].name, pre->dsk.dsk[j].name) != 0) { for (j=0; pre->dsk.dsk[j].name[0]; j++) { if ( strcmp(cur->dsk.dsk[i].name, pre->dsk.dsk[j].name) == 0) break; } /* ** either the corresponding entry has been found ** in the case that a disk has been removed, or ** an empty entry has been found (all counters ** on zero) in the case that a disk has been added ** during the last sample */ } strcpy(dev->dsk.dsk[i].name, cur->dsk.dsk[i].name); dev->dsk.dsk[i].nread = subcount(cur->dsk.dsk[i].nread, pre->dsk.dsk[j].nread); dev->dsk.dsk[i].nwrite = subcount(cur->dsk.dsk[i].nwrite, pre->dsk.dsk[j].nwrite); dev->dsk.dsk[i].nrsect = subcount(cur->dsk.dsk[i].nrsect, pre->dsk.dsk[j].nrsect); dev->dsk.dsk[i].nwsect = subcount(cur->dsk.dsk[i].nwsect, pre->dsk.dsk[j].nwsect); dev->dsk.dsk[i].io_ms = subcount(cur->dsk.dsk[i].io_ms, pre->dsk.dsk[j].io_ms); dev->dsk.dsk[i].avque = subcount(cur->dsk.dsk[i].avque, pre->dsk.dsk[j].avque); /* ** determine new j */ if (pre->dsk.dsk[j].name[0] != '\0') // existing matching entry j++; else j = realj; // empty entry: stick to old j } dev->dsk.dsk[i].name[0] = '\0'; dev->dsk.ndsk = i; /* ** calculate deviations for multiple devices */ if (cur->dsk.nmdd != dev->dsk.nmdd) { size = (cur->dsk.nmdd + 1) * sizeof(struct perdsk); dev->dsk.mdd = (struct perdsk *)realloc(dev->dsk.mdd, size); ptrverify(dev->dsk.mdd, "deviatsyst mdd [%ld]\n", (long)size); } for (i=j=0; cur->dsk.mdd && cur->dsk.mdd[i].name[0]; i++) { int realj = j; /* ** check if md has been added or removed since ** previous interval */ if (pre->dsk.mdd[j].name[0] == '\0' || strcmp(cur->dsk.mdd[i].name, pre->dsk.mdd[j].name) != 0) { for (j=0; pre->dsk.mdd[j].name[0]; j++) { if ( strcmp(cur->dsk.mdd[i].name, pre->dsk.mdd[j].name) == 0) break; } /* ** either the corresponding entry has been found ** in the case that a md has been removed, or ** an empty entry has been found (all counters ** on zero) in the case that a md has been added ** during the last sample */ } strcpy(dev->dsk.mdd[i].name, cur->dsk.mdd[i].name); dev->dsk.mdd[i].nread = subcount(cur->dsk.mdd[i].nread, pre->dsk.mdd[j].nread); dev->dsk.mdd[i].nwrite = subcount(cur->dsk.mdd[i].nwrite, pre->dsk.mdd[j].nwrite); dev->dsk.mdd[i].nrsect = subcount(cur->dsk.mdd[i].nrsect, pre->dsk.mdd[j].nrsect); dev->dsk.mdd[i].nwsect = subcount(cur->dsk.mdd[i].nwsect, pre->dsk.mdd[j].nwsect); dev->dsk.mdd[i].io_ms = subcount(cur->dsk.mdd[i].io_ms, pre->dsk.mdd[j].io_ms); dev->dsk.mdd[i].avque = subcount(cur->dsk.mdd[i].avque, pre->dsk.mdd[j].avque); /* ** determine new j */ if (pre->dsk.mdd[j].name[0] != '\0') // existing matching entry j++; else j = realj; // empty entry: stick to old j } dev->dsk.mdd[i].name[0] = '\0'; dev->dsk.nmdd = i; /* ** calculate deviations for LVM logical volumes */ if (cur->dsk.nlvm != dev->dsk.nlvm) { size = (cur->dsk.nlvm + 1) * sizeof(struct perdsk); dev->dsk.lvm = (struct perdsk *)realloc(dev->dsk.lvm, size); ptrverify(dev->dsk.lvm, "deviatsyst lvm [%ld]\n", (long)size); } for (i=j=0; cur->dsk.lvm && cur->dsk.lvm[i].name[0]; i++) { int realj = j; /* ** check if logical volume has been added or removed since ** previous interval */ if (pre->dsk.lvm[j].name[0] == '\0' || strcmp(cur->dsk.lvm[i].name, pre->dsk.lvm[j].name) != 0) { for (j=0; pre->dsk.lvm[j].name[0]; j++) { if ( strcmp(cur->dsk.lvm[i].name, pre->dsk.lvm[j].name) == 0) break; } /* ** either the corresponding entry has been found ** in the case that a logical volume has been removed, ** or an empty entry has been found (all counters ** on zero) in the case that a logical volume has ** been added during the last sample */ } strcpy(dev->dsk.lvm[i].name, cur->dsk.lvm[i].name); dev->dsk.lvm[i].nread = subcount(cur->dsk.lvm[i].nread, pre->dsk.lvm[j].nread); dev->dsk.lvm[i].nwrite = subcount(cur->dsk.lvm[i].nwrite, pre->dsk.lvm[j].nwrite); dev->dsk.lvm[i].nrsect = subcount(cur->dsk.lvm[i].nrsect, pre->dsk.lvm[j].nrsect); dev->dsk.lvm[i].nwsect = subcount(cur->dsk.lvm[i].nwsect, pre->dsk.lvm[j].nwsect); dev->dsk.lvm[i].io_ms = subcount(cur->dsk.lvm[i].io_ms, pre->dsk.lvm[j].io_ms); dev->dsk.lvm[i].avque = subcount(cur->dsk.lvm[i].avque, pre->dsk.lvm[j].avque); /* ** determine new j */ if (pre->dsk.lvm[j].name[0] != '\0') // existing matching entry j++; else j = realj; // empty entry: stick to old j } dev->dsk.lvm[i].name[0] = '\0'; dev->dsk.nlvm = i; /* ** application-specific counters */ if (cur->www.uptime >= pre->www.uptime) { dev->www.accesses = subcount(cur->www.accesses, pre->www.accesses); dev->www.totkbytes = subcount(cur->www.totkbytes, pre->www.totkbytes); } else { dev->www.accesses = cur->www.accesses; dev->www.totkbytes = cur->www.totkbytes; } dev->www.bworkers = cur->www.bworkers; dev->www.iworkers = cur->www.iworkers; }
/* ** calculate the process-activity during the last sample */ int deviattask(struct tstat *curtpres, int ntaskpres, struct tstat *curpexit, int nprocexit, int deviatonly, struct tstat *devtstat, struct sstat *devsstat, unsigned int *nprocdev, int *nprocpres, int *totrun, int *totslpi, int *totslpu, int *totzombie) { register int c, d; register struct tstat *curstat, *devstat, *procstat = 0; struct tstat prestat; struct pinfo *pinfo; count_t totusedcpu; char procsaved = 1, hashtype = 'p'; /* ** needed for sanity check later on... */ totusedcpu = devsstat->cpu.all.stime + devsstat->cpu.all.utime + devsstat->cpu.all.ntime + devsstat->cpu.all.itime + devsstat->cpu.all.wtime + devsstat->cpu.all.Itime + devsstat->cpu.all.Stime + devsstat->cpu.all.steal; /* ** make new list of all tasks in the process-database; ** after handling all processes, the left-overs are processes ** that have disappeared since the previous sample */ pdb_makeresidue(); /* ** calculate deviations per present process */ *nprocpres = *totrun = *totslpi = *totslpu = *totzombie = 0; for (c=0, d=0, *nprocdev=0; c < ntaskpres; c++) { char newtask = 0; curstat = curtpres+c; if (curstat->gen.isproc) { (*nprocpres)++; if (curstat->gen.state == 'Z') { (*totzombie)++; } else { *totrun += curstat->gen.nthrrun; *totslpi += curstat->gen.nthrslpi; *totslpu += curstat->gen.nthrslpu; } } /* ** get previous figures from task-database */ if ( pdb_gettask(curstat->gen.pid, curstat->gen.isproc, curstat->gen.btime, &pinfo)) { /* ** task already present during the previous sample; ** if no differences with previous sample, skip task ** unless all tasks have to be shown ** ** it might be that a process appears to have no ** differences while one its threads has differences; ** than the process will be inserted as well */ if (deviatonly && memcmp(curstat, &pinfo->tstat, sizeof(struct tstat)) == EQ) { /* remember last unsaved process */ if (curstat->gen.isproc) { procstat = curstat; procsaved = 0; } continue; } /* ** differences detected, so the task was active, ** or its status or memory-occupation has changed; ** save stats from previous sample (to use for ** further calculations) and store new statistics ** in task-database */ prestat = pinfo->tstat; /* save old */ pinfo->tstat = *curstat; /* overwrite */ } else { /* ** new task which must have been started during ** last interval */ memset(&prestat, 0, sizeof(prestat)); /* ** create new task struct */ pinfo = calloc(1, sizeof(struct pinfo)); ptrverify(pinfo, "Malloc failed for new pinfo\n"); pinfo->tstat = *curstat; /* ** add new task to task-database */ pdb_addtask(curstat->gen.pid, pinfo); newtask = 1; } /* ** active task found; do the difference calculations */ if (curstat->gen.isproc) { procsaved = 1; (*nprocdev)++; } else { /* ** active thread: check if related process registered */ if (!procsaved) { devstat = devtstat+d; calcdiff(devstat, procstat, procstat, 0, totusedcpu); procsaved = 1; (*nprocdev)++; d++; } } devstat = devtstat+d; calcdiff(devstat, curstat, &prestat, newtask, totusedcpu); d++; } /* ** calculate deviations per exited process */ if (nprocexit > 0 && supportflags&NETATOPD) { if (curpexit->gen.pid) hashtype = 'p'; else hashtype = 'b'; netatop_exithash(hashtype); } for (c=0; c < nprocexit; c++) { /* ** check if this process has been started AND ** finished since previous sample; ** if so, it has no use to check if there is still ** existing info present in the process-database */ curstat = curpexit+c; if (curstat->gen.pid) /* acctrecord contains pid? */ { if ( pdb_gettask(curstat->gen.pid, 1, curstat->gen.btime, &pinfo)) prestat = pinfo->tstat; else memset(&prestat, 0, sizeof(prestat)); } else { if ( curstat->gen.btime > pretime.tv_sec ) { /* ** process-start and -finish in same interval */ memset(&prestat, 0, sizeof(prestat)); } else { /* ** process must be known in process-database; ** try to match one of the remaining processes ** against this exited one */ if ( pdb_srchresidue(curstat, &pinfo) ) prestat = pinfo->tstat; else memset(&prestat, 0, sizeof(prestat)); } } /* ** now do the calculations */ devstat = devtstat+d; memset(devstat, 0, sizeof *devstat); devstat->gen = curstat->gen; if ( curstat->gen.pid == 0 ) devstat->gen.pid = prestat.gen.pid; if (!prestat.gen.pid) devstat->gen.excode |= ~(INT_MAX); strcpy(devstat->gen.cmdline, prestat.gen.cmdline); /* ** due to the strange exponent-type storage of values ** in the process accounting record, the resource-value ** in the exit-record might have been smaller than the ** stored value of the last registered sample; in that ** case the deviation should be set to zero */ if (curstat->cpu.stime > prestat.cpu.stime) devstat->cpu.stime = curstat->cpu.stime - prestat.cpu.stime; if (curstat->cpu.utime > prestat.cpu.utime) devstat->cpu.utime = curstat->cpu.utime - prestat.cpu.utime; if (curstat->mem.minflt > prestat.mem.minflt) devstat->mem.minflt = curstat->mem.minflt - prestat.mem.minflt; if (curstat->mem.majflt > prestat.mem.majflt) devstat->mem.majflt = curstat->mem.majflt - prestat.mem.majflt; if (curstat->dsk.rio > (prestat.dsk.rio + prestat.dsk.wio)) devstat->dsk.rio = curstat->dsk.rio - prestat.dsk.rio - prestat.dsk.wio; /* ** try to match the network counters of netatop */ if (supportflags & NETATOPD) { unsigned long val = (hashtype == 'p' ? curstat->gen.pid : curstat->gen.btime); netatop_exitfind(val, devstat, &prestat); } d++; (*nprocdev)++; if (prestat.gen.pid > 0) pdb_deltask(prestat.gen.pid, prestat.gen.isproc); } /* ** remove unused entries from RESIDUE chain */ pdb_cleanresidue(); return d; }
/* ** The engine() drives the main-loop of the program */ static void engine(void) { int i, j; struct sigaction sigact; static time_t timelimit; 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 *curpact; /* current active list */ static int curplen; /* current active size */ struct tstat *curpexit; /* exited process list */ struct tstat *devtstat; /* deviation list */ struct tstat **devpstat; /* pointers to processes*/ /* in deviation list */ unsigned int ntask, nexit, nexitnet; unsigned int noverflow, ndeviat, nactproc; int totproc, totrun, totslpi, totslpu, totzombie; /* ** initialization: allocate required memory dynamically */ cursstat = calloc(1, sizeof(struct sstat)); presstat = calloc(1, sizeof(struct sstat)); devsstat = calloc(1, sizeof(struct sstat)); curplen = countprocs() * 3 / 2; /* add 50% for threads */ curpact = calloc(curplen, sizeof(struct tstat)); ptrverify(cursstat, "Malloc failed for current sysstats\n"); ptrverify(presstat, "Malloc failed for prev sysstats\n"); ptrverify(devsstat, "Malloc failed for deviate sysstats\n"); ptrverify(curpact, "Malloc failed for %d procstats\n", curplen); /* ** 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 > 0) alarm(interval); if (midnightflag) { time_t timenow = time(0); struct tm *tp = localtime(&timenow); tp->tm_hour = 23; tp->tm_min = 59; tp->tm_sec = 59; timelimit = mktime(tp); } /* ** 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; /* ** if the limit-flag is specified: ** check if the next sample is expected before midnight; ** if not, stop atop now */ if (midnightflag && (curtime+interval) > timelimit) break; /* ** wait for alarm-signal to arrive (except first sample) ** or wait for SIGUSR1/SIGUSR2 */ if (sampcnt > 0 && awaittrigger) pause(); awaittrigger = 1; /* ** gather time info for this sample */ pretime = curtime; curtime = time(0); /* seconds since 1-1-1970 */ /* ** take a snapshot of the current system-level statistics ** and calculate the deviations (i.e. calculate the activity ** during the last sample) */ hlpsstat = cursstat; /* swap current/prev. stats */ cursstat = presstat; presstat = hlpsstat; photosyst(cursstat); /* obtain new counters */ deviatsyst(cursstat, presstat, devsstat); /* ** take a snapshot of the current task-level statistics ** and calculate the deviations (i.e. calculate the activity ** during the last sample) ** ** first register active tasks ** --> atop malloc's a minimal amount of space which is ** only extended when needed */ memset(curpact, 0, curplen * sizeof(struct tstat)); while ( (ntask = photoproc(curpact, curplen)) == curplen) { curplen += PROCCHUNK; curpact = realloc(curpact, curplen * sizeof(struct tstat)); ptrverify(curpact, "Realloc failed for %d tasks\n", curplen); memset(curpact, 0, curplen * sizeof(struct tstat)); } /* ** 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 */ nexit = acctprocnt(); /* number of exited processes */ if (nexit > MAXACCTPROCS) { noverflow = nexit - MAXACCTPROCS; nexit = MAXACCTPROCS; } else noverflow = 0; /* ** determine how many processes have been exited ** for the netatop module (only processes that have ** used the network) */ if (nexit > 0 && (supportflags & NETATOPD)) nexitnet = netatop_exitstore(); else nexitnet = 0; /* ** reserve space for the exited processes and read them */ if (nexit > 0) { curpexit = malloc(nexit * sizeof(struct tstat)); ptrverify(curpexit, "Malloc failed for %d exited processes\n", nexit); memset(curpexit, 0, nexit * sizeof(struct tstat)); acctphotoproc(curpexit, nexit); /* ** 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 deviations */ devtstat = malloc((ntask+nexit) * sizeof(struct tstat)); ptrverify(devtstat, "Malloc failed for %d modified processes\n", ntask+nexit); ndeviat = deviatproc(curpact, ntask, curpexit, nexit, deviatonly, devtstat, devsstat, &nactproc, &totproc, &totrun, &totslpi, &totslpu, &totzombie); /* ** create list of pointers specifically to the process entries ** in the task list */ devpstat = malloc(sizeof (struct tstat *) * nactproc); ptrverify(devpstat, "Malloc failed for %d process ptrs\n", nactproc); for (i=0, j=0; i < ndeviat; i++) { if ( (devtstat+i)->gen.isproc) devpstat[j++] = devtstat+i; } /* ** activate the installed print-function to visualize ** the deviations */ lastcmd = (vis.show_samp)( curtime, curtime-pretime > 0 ? curtime-pretime : 1, devsstat, devtstat, devpstat, ndeviat, ntask, nactproc, totproc, totrun, totslpi, totslpu, totzombie, nexit, noverflow, sampcnt==0); /* ** release dynamically allocated memory */ if (nexit > 0) free(curpexit); if (nexitnet > 0) netatop_exiterase(); free(devtstat); free(devpstat); if (lastcmd == 'r') /* reset requested ? */ { sampcnt = -1; curtime = getboot() / hertz; // reset current time /* set current (will be 'previous') counters to 0 */ memset(cursstat, 0, sizeof(struct sstat)); memset(curpact, 0, curplen * sizeof(struct tstat)); /* remove all tasks in database */ pdb_makeresidue(); pdb_cleanresidue(); } } /* end of main-loop */ }
/* ** 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 */ }
void rawarchive(pmOptions *opts, const char *name) { struct tm *tp; time_t timenow; char tmp[MAXPATHLEN]; char path[MAXPATHLEN]; char *logdir, *py, *host; int sep = __pmPathSeparator(); int sts, len = (name? strlen(name) : 0); if (len == 0) return rawfolio(opts); /* see if a valid archive exists as specified */ if ((sts = pmNewContext(PM_CONTEXT_ARCHIVE, name)) >= 0) { pmDestroyContext(sts); __pmAddOptArchive(opts, (char * )name); return; } /* see if a valid folio exists as specified */ strncpy(tmp, name, sizeof(tmp)); tmp[sizeof(tmp)-1] = '\0'; if (access(tmp, R_OK) == 0) { __pmAddOptArchiveFolio(opts, tmp); return; } snprintf(path, sizeof(path), "%s/%s.folio", name, basename(tmp)); path[sizeof(path)-1] = '\0'; if (access(path, R_OK) == 0) { __pmAddOptArchiveFolio(opts, path); return; } /* else go hunting in the system locations... */ if ((logdir = pmGetOptionalConfig("PCP_LOG_DIR")) == NULL) { fprintf(stderr, "%s: cannot find PCP_LOG_DIR\n", pmProgname); cleanstop(1); } host = rawlocalhost(opts); /* ** Use original rawread() algorithms for specifying dates */ if (len == 8 && lookslikedatetome(name)) { snprintf(path, sizeof(path), "%s%c%s%c%s%c%s", logdir, sep, "pmlogger", sep, host, sep, name); __pmAddOptArchive(opts, (char * )path); } /* ** if one or more 'y' (yesterday) characters are used and that ** string is not known as an existing file, the standard logfile ** is shown from N days ago (N is determined by the number ** of y's). */ else { /* ** make a string existing of y's to compare with */ py = malloc(len+1); ptrverify(py, "Malloc failed for 'yes' sequence\n"); memset(py, 'y', len); *(py+len) = '\0'; if ( strcmp(name, py) == 0 ) { timenow = time(0); timenow -= len*3600*24; tp = localtime(&timenow); snprintf(path, sizeof(path), "%s%c%s%c%s%c%04u%02u%02u", logdir, sep, "pmlogger", sep, host, sep, tp->tm_year+1900, tp->tm_mon+1, tp->tm_mday); __pmAddOptArchive(opts, (char * )path); } else { fprintf(stderr, "%s: cannot find archive from \"%s\"\n", pmProgname, name); cleanstop(1); } free(py); } }