static char * rawlocalhost(pmOptions *opts) { int ctxt; char *host; if (opts->nhosts > 0) return opts->hosts[0]; if ((ctxt = pmNewContext(PM_CONTEXT_LOCAL, NULL)) < 0) { fprintf(stderr, "%s: cannot create local context: %s\n", pmProgname, pmErrStr(ctxt)); cleanstop(1); } host = (char *)pmGetContextHostName(ctxt); pmDestroyContext(ctxt); if (host[0] == '\0') { fprintf(stderr, "%s: cannot find local hostname\n", pmProgname); cleanstop(1); } return host; }
/* ** count number of processes currently running */ unsigned int countprocs(void) { unsigned int nr=0; DIR *dirp; struct dirent *entp; char origdir[1024]; if ( getcwd(origdir, sizeof origdir) == NULL) cleanstop(53); if ( chdir("/proc") == -1) cleanstop(53); dirp = opendir("."); while ( (entp = readdir(dirp)) ) { /* ** count subdirectory-names starting with a digit */ if (isdigit(entp->d_name[0])) nr++; } closedir(dirp); if ( chdir(origdir) == -1) cleanstop(53); return nr; }
int fetch_metrics(const char *purpose, int nmetrics, pmID *pmids, pmResult **result) { int sts; pmSetMode(fetchmode, &curtime, fetchstep); if ((sts = pmFetch(nmetrics, pmids, result)) < 0) { if (sts != PM_ERR_EOL) fprintf(stderr, "%s: %s query: %s\n", pmProgname, purpose, pmErrStr(sts)); cleanstop(1); } if (pmDebug & DBG_TRACE_APPL1) { pmResult *rp = *result; struct tm tmp; time_t sec; sec = (time_t)rp->timestamp.tv_sec; pmLocaltime(&sec, &tmp); fprintf(stderr, "%s: got %d %s metrics @%02d:%02d:%02d.%03d\n", pmProgname, rp->numpmid, purpose, tmp.tm_hour, tmp.tm_min, tmp.tm_sec, (int)(rp->timestamp.tv_usec / 1000)); } return sts; }
void setup_globals(pmOptions *opts) { pmID pmids[HOST_NMETRICS]; pmDesc descs[HOST_NMETRICS]; pmResult *result; setup_context(opts); setup_metrics(hostmetrics, &pmids[0], &descs[0], HOST_NMETRICS); fetch_metrics("host", HOST_NMETRICS, pmids, &result); if (HOST_NMETRICS != result->numpmid) { fprintf(stderr, "%s: pmFetch failed to fetch initial metric value(s)\n", pmProgname); cleanstop(1); } hertz = extract_integer(result, descs, HOST_HERTZ); pagesize = extract_integer(result, descs, HOST_PAGESIZE); extract_string(result, descs, HOST_RELEASE, sysname.release, sizeof(sysname.release)); extract_string(result, descs, HOST_VERSION, sysname.version, sizeof(sysname.version)); extract_string(result, descs, HOST_MACHINE, sysname.machine, sizeof(sysname.machine)); extract_string(result, descs, HOST_NODENAME, sysname.nodename, sizeof(sysname.nodename)); nodenamelen = strlen(sysname.nodename); pmFreeResult(result); }
static int procio(struct tstat *curtask) { FILE *fp; char line[4096]; count_t dskrsz=0, dskwsz=0, dskcwsz=0; if (supportflags & IOSTAT) { regainrootprivs(); if ( (fp = fopen("io", "r")) ) { while (fgets(line, sizeof line, fp)) { if (memcmp(line, IO_READ, sizeof IO_READ -1) == 0) { sscanf(line, "%*s %llu", &dskrsz); dskrsz /= 512; // in sectors continue; } if (memcmp(line, IO_WRITE, sizeof IO_WRITE -1) == 0) { sscanf(line, "%*s %llu", &dskwsz); dskwsz /= 512; // in sectors continue; } if (memcmp(line, IO_CWRITE, sizeof IO_CWRITE -1) == 0) { sscanf(line, "%*s %llu", &dskcwsz); dskcwsz /= 512; // in sectors continue; } } fclose(fp); curtask->dsk.rsz = dskrsz; curtask->dsk.rio = dskrsz; // to enable sort curtask->dsk.wsz = dskwsz; curtask->dsk.wio = dskwsz; // to enable sort curtask->dsk.cwsz = dskcwsz; } if (! droprootprivs()) cleanstop(42); } return 1; }
/* ** Extract active PCP archive file from latest archive folio, ** use pmcd.hostname by default, unless directed elsewhere. */ void rawfolio(pmOptions *opts) { int sep = __pmPathSeparator(); char path[MAXPATHLEN]; char *logdir; if ((logdir = pmGetOptionalConfig("PCP_LOG_DIR")) == NULL) { fprintf(stderr, "%s: cannot find PCP_LOG_DIR\n", pmProgname); cleanstop(1); } snprintf(path, sizeof(path), "%s%c%s%c%s%c", logdir, sep, "pmlogger", sep, rawlocalhost(opts), sep); if (chdir(path) < 0) { fprintf(stderr, "%s: cannot change to %s: %s\n", pmProgname, path, pmErrStr(-oserror())); cleanstop(1); } __pmAddOptArchiveFolio(opts, "Latest"); }
/* * PMAPI context creation and initial command line option handling. */ static int setup_context(pmOptions *opts) { char *source; int sts, ctx; if (opts->context == PM_CONTEXT_ARCHIVE) source = opts->archives[0]; else if (opts->context == PM_CONTEXT_HOST) source = opts->hosts[0]; else if (opts->context == PM_CONTEXT_LOCAL) source = NULL; else { opts->context = PM_CONTEXT_HOST; source = "local:"; } if ((sts = ctx = pmNewContext(opts->context, source)) < 0) { if (opts->context == PM_CONTEXT_HOST) pmprintf( "%s: Cannot connect to pmcd on host \"%s\": %s\n", pmProgname, source, pmErrStr(sts)); else if (opts->context == PM_CONTEXT_LOCAL) pmprintf( "%s: Cannot make standalone connection on localhost: %s\n", pmProgname, pmErrStr(sts)); else pmprintf( "%s: Cannot open archive \"%s\": %s\n", pmProgname, source, pmErrStr(sts)); } else if ((sts = pmGetContextOptions(ctx, opts)) == 0) sts = setup_origin(opts); if (sts < 0) { pmflush(); cleanstop(1); } return ctx; }
/* ** print usage of this command */ void prusage(char *myname) { printf("Usage: %s [-flags] [interval [samples]]\n", myname); printf("\t\tor\n"); printf("Usage: %s -w file [-S] [-%c] [interval [samples]]\n", myname, MALLPROC); printf(" %s -r file [-b hh:mm] [-e hh:mm] [-flags]\n", myname); printf("\n"); printf("\tgeneric flags:\n"); printf("\t -%c show or log all processes (i.s.o. active processes " "only)\n", MALLPROC); printf("\t -%c calculate proportional set size (PSS) per process\n", MCALCPSS); printf("\t -P generate parseable output for specified label(s)\n"); printf("\t -L alternate line length (default 80) in case of " "non-screen output\n"); (*vis.show_usage)(); printf("\n"); printf("\tspecific flags for raw logfiles:\n"); printf("\t -w write raw data to PCP archive folio\n"); printf("\t -r read raw data from PCP archive folio\n"); printf("\t -S finish %s automatically before midnight " "(i.s.o. #samples)\n", pmProgname); printf("\t -b begin showing data from specified time\n"); printf("\t -e finish showing data after specified time\n"); printf("\n"); printf("\tinterval: number of seconds (minimum 0)\n"); printf("\tsamples: number of intervals (minimum 1)\n"); printf("\n"); printf("If the interval-value is zero, a new sample can be\n"); printf("forced manually by sending signal USR1" " (kill -USR1 %s-pid)\n", pmProgname); printf("or with the keystroke '%c' in interactive mode.\n", MSAMPNEXT); printf("\n"); printf("Please refer to the man-page of '%s' for more details.\n", pmProgname); cleanstop(1); }
void setup_metrics(char **metrics, pmID *pmidlist, pmDesc *desclist, int nmetrics) { int i, sts; if ((sts = pmLookupName(nmetrics, metrics, pmidlist)) < 0) { fprintf(stderr, "%s: pmLookupName: %s\n", pmProgname, pmErrStr(sts)); cleanstop(1); } if (nmetrics != sts) { for (i=0; i < nmetrics; i++) { if (pmidlist[i] != PM_ID_NULL) continue; if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "%s: pmLookupName failed for %s\n", pmProgname, metrics[i]); } } for (i=0; i < nmetrics; i++) { if (pmidlist[i] == PM_ID_NULL) { desclist[i].pmid = PM_ID_NULL; continue; } if ((sts = pmLookupDesc(pmidlist[i], &desclist[i])) < 0) { if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "%s: pmLookupDesc failed for %s: %s\n", pmProgname, metrics[i], pmErrStr(sts)); pmidlist[i] = desclist[i].pmid = PM_ID_NULL; } } }
/* ** print usage of this command */ void prusage(char *myname) { printf("Usage: %s [-flags] [interval [samples]]\n", myname); printf("\t\tor\n"); printf("Usage: %s -w file [-S] [-%c] [interval [samples]]\n", myname, MALLPROC); printf(" %s -r [file] [-b hh:mm] [-e hh:mm] [-flags]\n", myname); printf("\n"); printf("\tgeneric flags:\n"); printf("\t -%c show or log all processes (i.s.o. active processes " "only)\n", MALLPROC); printf("\t -P generate parseable output for specified label(s)\n"); printf("\t -L alternate line length (default 80) in case of " "non-screen output\n"); (*vis.show_usage)(); printf("\n"); printf("\tspecific flags for raw logfiles:\n"); printf("\t -w write raw data to file (compressed)\n"); printf("\t -r read raw data from file (compressed)\n"); printf("\t special file: y[y...] for yesterday (repeated)\n"); printf("\t -S finish atop automatically before midnight " "(i.s.o. #samples)\n"); printf("\t -b begin showing data from specified time\n"); printf("\t -e finish showing data after specified time\n"); printf("\n"); printf("\tinterval: number of seconds (minimum 0)\n"); printf("\tsamples: number of intervals (minimum 1)\n"); printf("\n"); printf("If the interval-value is zero, a new sample can be\n"); printf("forced manually by sending signal USR1" " (kill -USR1 pid_atop)\n"); printf("or with the keystroke '%c' in interactive mode.\n", MSAMPNEXT); cleanstop(1); }
int get_instances(const char *purpose, int value, pmDesc *descs, int **ids, char ***insts) { int sts, i; if (descs[value].pmid == PM_ID_NULL) { /* we have no descriptor for this metric, thus no instances */ *insts = NULL; *ids = NULL; return 0; } sts = !rawreadflag ? pmGetInDom(descs[value].indom, ids, insts) : pmGetInDomArchive(descs[value].indom, ids, insts); if (sts == PM_ERR_INDOM_LOG) { /* metrics but no indom - expected sometimes, "no values" */ *insts = NULL; *ids = NULL; return 0; } if (sts < 0) { fprintf(stderr, "%s: %s instances: %s\n", pmProgname, purpose, pmErrStr(sts)); cleanstop(1); } if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "%s: got %d %s instances:\n", pmProgname, sts, purpose); for (i=0; i < sts; i++) fprintf(stderr, " [%d] %s\n", (*ids)[i], (*insts)[i]); } return sts; }
/* ** read RC-file and modify defaults accordingly */ static void readrc(char *path) { int i, nr, line=0, errorcnt = 0; /* ** check if this file is readable with the user's ** *real uid/gid* with syscall access() */ if ( access(path, R_OK) == 0) { FILE *fp; char linebuf[256], tagname[20], tagvalue[256]; fp = fopen(path, "r"); while ( fgets(linebuf, sizeof linebuf, fp) ) { line++; i = strlen(linebuf); if (i > 0 && linebuf[i-1] == '\n') linebuf[i-1] = 0; nr = sscanf(linebuf, "%19s %255[^#]", tagname, tagvalue); switch (nr) { case 0: continue; case 1: if (tagname[0] == '#') continue; fprintf(stderr, "%s: syntax error line " "%d (no value specified)\n", path, line); cleanstop(1); break; /* not reached */ default: if (tagname[0] == '#') continue; if (tagvalue[0] != '#') break; fprintf(stderr, "%s: syntax error line " "%d (no value specified)\n", path, line); cleanstop(1); } /* ** tag name and tag value found ** try to recognize tag name */ for (i=0; i < sizeof manrc/sizeof manrc[0]; i++) { if ( strcmp(tagname, manrc[i].tag) ==0) { manrc[i].func(tagname, tagvalue); break; } } /* ** tag name not recognized */ if (i == sizeof manrc/sizeof manrc[0]) { fprintf(stderr, "%s: warning at line %2d " "- tag name %s not valid\n", path, line, tagname); errorcnt++; } } if (errorcnt) sleep(2); fclose(fp); } }
int main(int argc, char *argv[]) { register int i; int c; char *p; struct rlimit rlim; /* ** since priviliged actions will be done later on, at this stage ** the root-priviliges are dropped by switching effective user-id ** to real user-id (security reasons) */ if (! droprootprivs() ) { fprintf(stderr, "not possible to drop root privs\n"); exit(42); } /* ** preserve command arguments to allow restart of other version */ argvp = argv; /* ** read defaults-files /etc/atoprc en $HOME/.atoprc (if any) */ readrc("/etc/atoprc"); if ( (p = getenv("HOME")) ) { char path[1024]; snprintf(path, sizeof path, "%s/.atoprc", p); readrc(path); } /* ** check if we are supposed to behave as 'atopsar' ** i.e. system statistics only */ if ( (p = strrchr(argv[0], '/'))) p++; else p = argv[0]; if ( memcmp(p, "atopsar", 7) == 0) return atopsar(argc, argv); /* ** interpret command-line arguments & flags */ if (argc > 1) { /* ** gather all flags for visualization-functions ** ** generic flags will be handled here; ** unrecognized flags are passed to the print-routines */ i = 0; while (i < MAXFL-1 && (c=getopt(argc, argv, allflags)) != EOF) { switch (c) { case '?': /* usage wanted ? */ prusage(argv[0]); break; case 'V': /* version wanted ? */ printf("%s\n", getstrvers()); exit(0); case 'w': /* writing of raw data ? */ if (optind >= argc) prusage(argv[0]); strncpy(rawname, argv[optind++], RAWNAMESZ-1); vis.show_samp = rawwrite; break; case 'r': /* reading of raw data ? */ if (optind < argc && *(argv[optind]) != '-') strncpy(rawname, argv[optind++], RAWNAMESZ-1); rawreadflag++; break; case 'S': /* midnight limit ? */ midnightflag++; break; case 'a': /* all processes per sample ? */ deviatonly=0; break; case 'b': /* begin time ? */ if ( !hhmm2secs(optarg, &begintime) ) prusage(argv[0]); break; case 'e': /* end time ? */ if ( !hhmm2secs(optarg, &endtime) ) prusage(argv[0]); break; case 'j': /* show disk partitions statistics */ diskpartview = 1; break; case 'P': /* parseable output? */ if ( !parsedef(optarg) ) prusage(argv[0]); vis.show_samp = parseout; break; case 'L': /* line length */ if ( !numeric(optarg) ) prusage(argv[0]); linelen = atoi(optarg); break; default: /* gather other flags */ flaglist[i++] = c; } } /* ** get optional interval-value and optional number of samples */ if (optind < argc && optind < MAXFL) { if (!numeric(argv[optind])) prusage(argv[0]); interval = atoi(argv[optind]); optind++; if (optind < argc) { if (!numeric(argv[optind]) ) prusage(argv[0]); if ( (nsamples = atoi(argv[optind])) < 1) prusage(argv[0]); } } } /* ** determine the name of this node (without domain-name) ** and the kernel-version */ (void) uname(&utsname); if ( (p = strchr(utsname.nodename, '.')) ) *p = '\0'; utsnodenamelen = strlen(utsname.nodename); sscanf(utsname.release, "%d.%d.%d", &osrel, &osvers, &ossub); /* ** determine the clock rate and memory page size for this machine */ hertz = sysconf(_SC_CLK_TCK); pagesize = sysconf(_SC_PAGESIZE); /* ** check if raw data from a file must be viewed */ if (rawreadflag) { rawread(); cleanstop(0); } /* ** determine start-time for gathering current statistics */ curtime = getboot() / hertz; /* ** catch signals for proper close-down */ signal(SIGHUP, cleanstop); signal(SIGTERM, cleanstop); /* ** regain the root-priviliges that we dropped at the beginning ** to do some priviliged work */ regainrootprivs(); /* ** lock ATOP in memory to get reliable samples (also when ** memory is low); ** ignored if not running under superuser priviliges! */ rlim.rlim_cur = RLIM_INFINITY; rlim.rlim_max = RLIM_INFINITY; (void) setrlimit(RLIMIT_MEMLOCK, &rlim); (void) mlockall(MCL_CURRENT|MCL_FUTURE); /* ** increment CPU scheduling-priority to get reliable samples (also ** during heavy CPU load); ** ignored if not running under superuser priviliges! */ if ( nice(-20) == -1) ; /* ** switch-on the process-accounting mechanism to register the ** (remaining) resource-usage by processes which have finished */ acctreason = acctswon(); /* ** determine properties (like speed) of all interfaces */ initifprop(); /* ** open socket to the IP layer to issue getsockopt() calls later on */ netatop_ipopen(); /* ** since priviliged activities are finished now, there is no ** need to keep running under root-priviliges, so switch ** effective user-id to real user-id */ if (! droprootprivs() ) cleanstop(42); /* ** start the engine now ..... */ engine(); cleanstop(0); return 0; /* never reached */ }
int photoproc(struct tstat *tasklist, int maxtask) { static int firstcall = 1; static unsigned long long bootepoch; register struct tstat *curtask; FILE *fp; DIR *dirp; struct dirent *entp; char origdir[1024]; int tval=0; /* ** one-time initialization stuff */ if (firstcall) { /* ** check if this kernel offers io-statistics per task */ regainrootprivs(); if ( (fp = fopen("/proc/1/io", "r")) ) { supportflags |= IOSTAT; fclose(fp); } if (! droprootprivs()) cleanstop(42); /* ** find epoch time of boot moment */ bootepoch = getboot(); firstcall = 0; } /* ** probe if the netatop module and (optionally) the ** netatopd daemon are active */ regainrootprivs(); netatop_probe(); if (! droprootprivs()) cleanstop(42); /* ** read all subdirectory-names below the /proc directory */ if ( getcwd(origdir, sizeof origdir) == NULL) cleanstop(53); if ( chdir("/proc") == -1) cleanstop(53); dirp = opendir("."); while ( (entp = readdir(dirp)) && tval < maxtask ) { /* ** skip non-numerical names */ if (!isdigit(entp->d_name[0])) continue; /* ** change to the process' subdirectory */ if ( chdir(entp->d_name) != 0 ) continue; /* ** gather process-level information */ curtask = tasklist+tval; if ( !procstat(curtask, bootepoch, 1)) /* from /proc/pid/stat */ { if ( chdir("..") == -1); continue; } if ( !procstatus(curtask) ) /* from /proc/pid/status */ { if ( chdir("..") == -1); continue; } if ( !procio(curtask) ) /* from /proc/pid/io */ { if ( chdir("..") == -1); continue; } proccmd(curtask); /* from /proc/pid/cmdline */ // read network stats from netatop netatop_gettask(curtask->gen.tgid, 'g', curtask); tval++; /* increment for process-level info */ /* ** if needed (when number of threads is larger than 0): ** read and fill new entries with thread-level info */ if (curtask->gen.nthr > 1) { DIR *dirtask; struct dirent *tent; curtask->gen.nthrrun = 0; curtask->gen.nthrslpi = 0; curtask->gen.nthrslpu = 0; /* ** open underlying task directory */ if ( chdir("task") == 0 ) { dirtask = opendir("."); while ((tent=readdir(dirtask)) && tval<maxtask) { struct tstat *curthr = tasklist+tval; /* ** change to the thread's subdirectory */ if ( tent->d_name[0] == '.' || chdir(tent->d_name) != 0 ) continue; if ( !procstat(curthr, bootepoch, 0)) { if ( chdir("..") == -1); continue; } if ( !procstatus(curthr) ) { if ( chdir("..") == -1); continue; } if ( !procio(curthr) ) { if ( chdir("..") == -1); continue; } switch (curthr->gen.state) { case 'R': curtask->gen.nthrrun += 1; break; case 'S': curtask->gen.nthrslpi += 1; break; case 'D': curtask->gen.nthrslpu += 1; break; } curthr->gen.nthr = 1; // read network stats from netatop netatop_gettask(curthr->gen.pid, 't', curthr); // all stats read now tval++; /* increment thread-level */ if ( chdir("..") == -1); /* thread */ } closedir(dirtask); if ( chdir("..") == -1); /* leave task */ } } if ( chdir("..") == -1); /* leave process-level directry */ } closedir(dirp); if ( chdir(origdir) == -1) cleanstop(53); return tval; }
/* ** read RC-file and modify defaults accordingly */ static void readrc(char *path, int syslevel) { int i, nr, line=0, errorcnt = 0; FILE *fp; char linebuf[256], tagname[20], tagvalue[256]; if ((fp = fopen(path, "r")) != NULL) { while ( fgets(linebuf, sizeof linebuf, fp) ) { line++; i = strlen(linebuf); if (i > 0 && linebuf[i-1] == '\n') linebuf[i-1] = 0; nr = sscanf(linebuf, "%19s %255[^#]", tagname, tagvalue); switch (nr) { case 0: continue; case 1: if (tagname[0] == '#') continue; fprintf(stderr, "%s: syntax error line " "%d (no value specified)\n", path, line); cleanstop(1); break; /* not reached */ default: if (tagname[0] == '#') continue; if (tagvalue[0] != '#') break; fprintf(stderr, "%s: syntax error line " "%d (no value specified)\n", path, line); cleanstop(1); } /* ** tag name and tag value found ** try to recognize tag name */ for (i=0; i < sizeof manrc/sizeof manrc[0]; i++) { if ( strcmp(tagname, manrc[i].tag) == 0) { if (manrc[i].sysonly && !syslevel) { fprintf(stderr, "%s: warning at line %2d " "- tag name %s not allowed " "in private atoprc\n", path, line, tagname); errorcnt++; break; } manrc[i].func(tagname, tagvalue); break; } } /* ** tag name not recognized */ if (i == sizeof manrc/sizeof manrc[0]) { fprintf(stderr, "%s: warning at line %2d " "- tag name %s not valid\n", path, line, tagname); errorcnt++; } } if (errorcnt) sleep(2); fclose(fp); } }
void rawwrite(pmOptions *opts, const char *name, struct timeval *delta, unsigned int nsamples, char midnightflag) { pmRecordHost *record; struct timeval elapsed; double duration; double interval; char args[MAXPATHLEN]; char *host; int sts; host = (opts->nhosts > 0) ? opts->hosts[0] : "local:"; interval = __pmtimevalToReal(delta); duration = interval * nsamples; if (midnightflag) { time_t now = time(NULL); struct tm *tp; tp = localtime(&now); tp->tm_hour = 23; tp->tm_min = 59; tp->tm_sec = 59; duration = (double) (mktime(tp) - now); } if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "%s: start recording, %.2fsec duration [%s].\n", pmProgname, duration, name); } if (__pmMakePath(name, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH) < 0) { fprintf(stderr, "%s: making folio path %s for recording: %s\n", pmProgname, name, osstrerror()); cleanstop(1); } if (chdir(name) < 0) { fprintf(stderr, "%s: entering folio %s for recording: %s\n", pmProgname, name, strerror(oserror())); cleanstop(1); } /* ** Non-graphical application using libpcp_gui services - never want ** to see popup dialogs from pmlogger(1) here, so force the issue. */ putenv("PCP_XCONFIRM_PROG=/bin/true"); snprintf(args, sizeof(args), "%s.folio", basename((char *)name)); args[sizeof(args)-1] = '\0'; if (pmRecordSetup(args, pmProgname, 1) == NULL) { fprintf(stderr, "%s: cannot setup recording to %s: %s\n", pmProgname, name, osstrerror()); cleanstop(1); } if ((sts = pmRecordAddHost(host, 1, &record)) < 0) { fprintf(stderr, "%s: adding host %s to recording: %s\n", pmProgname, host, pmErrStr(sts)); cleanstop(1); } rawconfig(record->f_config, interval); /* ** start pmlogger with a deadhand timer, ensuring it will stop */ snprintf(args, sizeof(args), "-T%.3fseconds", duration); args[sizeof(args)-1] = '\0'; if ((sts = pmRecordControl(record, PM_REC_SETARG, args)) < 0) { fprintf(stderr, "%s: setting loggers arguments: %s\n", pmProgname, pmErrStr(sts)); cleanstop(1); } if ((sts = pmRecordControl(NULL, PM_REC_ON, "")) < 0) { fprintf(stderr, "%s: failed to start recording: %s\n", pmProgname, pmErrStr(sts)); cleanstop(1); } __pmtimevalFromReal(duration, &elapsed); __pmtimevalSleep(elapsed); if ((sts = pmRecordControl(NULL, PM_REC_OFF, "")) < 0) { fprintf(stderr, "%s: failed to stop recording: %s\n", pmProgname, pmErrStr(sts)); cleanstop(1); } if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "%s: cleanly stopped recording.\n", pmProgname); } }
int main(int argc, char *argv[]) { register int i; int c; char *p; char path[MAXPATHLEN]; pmOptions opts = { .short_options = allflags, .flags = PM_OPTFLAG_BOUNDARIES, }; /* ** preserve command arguments to allow restart of other version */ argvp = argv; /* ** read defaults-files /etc/atoprc en $HOME/.atoprc (if any) */ readrc("/etc/atoprc", 1); if ( (p = getenv("HOME")) ) { snprintf(path, sizeof(path), "%s/.atoprc", p); path[sizeof(path)-1] = '\0'; readrc(path, 0); } /* ** check if we are supposed to behave as 'atopsar' ** i.e. system statistics only */ __pmSetProgname(argv[0]); if (strcmp(pmProgname, "pcp-atopsar") == 0) return atopsar(argc, argv); __pmStartOptions(&opts); if (opts.narchives > 0) rawreadflag++; /* ** interpret command-line arguments & flags */ if (argc > 1) { /* ** gather all flags for visualization-functions ** ** generic flags will be handled here; ** unrecognized flags are passed to the print-routines */ i = 0; while (i < MAXFL-1 && (c = pmgetopt_r(argc, argv, &opts)) != EOF) { switch (c) { case '?': /* usage wanted ? */ prusage(pmProgname); break; case 'V': /* version wanted ? */ printf("%s\n", getstrvers()); exit(0); case 'w': /* writing of raw data ? */ rawname = opts.optarg; rawwriteflag++; break; case 'r': /* reading of raw data ? */ rawarchive(&opts, opts.optarg); rawreadflag++; break; case 'S': /* midnight limit ? */ midnightflag++; break; case 'a': /* all processes per sample ? */ deviatonly = 0; break; case 'R': /* all processes per sample ? */ calcpss = 1; break; case 'b': /* begin time ? */ opts.start_optarg = abstime(opts.optarg); break; case 'e': /* end time ? */ opts.finish_optarg = abstime(opts.optarg); break; case 'P': /* parseable output? */ if ( !parsedef(opts.optarg) ) prusage(pmProgname); vis.show_samp = parseout; break; case 'L': /* line length */ if ( !numeric(opts.optarg) ) prusage(pmProgname); linelen = atoi(opts.optarg); break; default: /* gather other flags */ flaglist[i++] = c; } } /* ** get optional interval-value and optional number of samples */ if (opts.optind < argc && opts.optind < MAXFL) { char *endnum, *arg; arg = argv[opts.optind++]; if (pmParseInterval(arg, &opts.interval, &endnum) < 0) { pmprintf( "%s: %s option not in pmParseInterval(3) format:\n%s\n", pmProgname, arg, endnum); free(endnum); opts.errors++; } else interval = opts.interval; if (opts.optind < argc) { arg = argv[opts.optind]; if (!numeric(arg)) prusage(pmProgname); if ((opts.samples = atoi(arg)) < 1) prusage(pmProgname); nsamples = opts.samples; } } } __pmEndOptions(&opts); if (opts.errors) prusage(pmProgname); /* ** find local host details (no privileged access required) */ setup_globals(&opts); /* ** check if we are in data recording mode */ if (rawwriteflag) { rawwrite(&opts, rawname, &interval, nsamples, midnightflag); cleanstop(0); } /* ** catch signals for proper close-down */ signal(SIGHUP, cleanstop); signal(SIGTERM, cleanstop); /* ** switch-on the process-accounting mechanism to register the ** (remaining) resource-usage by processes which have finished */ acctreason = acctswon(); /* ** determine properties (like speed) of all interfaces */ initifprop(); /* ** open socket to the IP layer to issue getsockopt() calls later on */ netatop_ipopen(); /* ** start the engine now ..... */ engine(); cleanstop(0); return 0; /* never reached */ }
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); } }
/* ** The engine() drives the main-loop of the program */ static void engine(void) { 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 process-level statistics */ static struct pstat *curpact; /* current active list */ static int curplen; /* current active size */ struct pstat *curpexit; /* exitted process list */ struct pstat *devpstat; /* deviation list */ int npresent, nexit, n; int ntrun, ntslpi, ntslpu, nzombie; /* ** 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() + PROCCHUNK; curpact = calloc(curplen, sizeof(struct pstat)); if (!cursstat || !presstat || !devsstat || !curpact) { fprintf(stderr, "unexpected calloc-failure...\n"); cleanstop(1); } /* ** 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 process-level statistics ** and calculate the deviations (i.e. calculate the activity ** during the last sample) ** ** first register active processes ** --> atop malloc's a minimal amount of space which is ** only extended when needed */ memset(curpact, 0, curplen * sizeof(struct pstat)); while ( (npresent = photoproc(curpact, curplen)) == curplen) { curplen = countprocs() + PROCCHUNK; curpact = realloc(curpact, curplen * sizeof(struct pstat)); memset(curpact, 0, curplen * sizeof(struct pstat)); } /* ** register processes which exited during last sample; ** first determine how many processes exited and ** reserve space for them, and secondly obtain the info */ nexit = acctprocnt(); /* number of exited processes */ if (nexit > 0) { curpexit = malloc( nexit * sizeof(struct pstat)); memset(curpexit, 0, nexit * sizeof(struct pstat)); acctphotoproc(curpexit, nexit); } else curpexit = NULL; /* ** calculate deviations */ devpstat = malloc((npresent+nexit) * sizeof(struct pstat)); n = deviatproc(curpact, npresent, curpexit, nexit, deviatonly, devpstat, devsstat, &ntrun, &ntslpi, &ntslpu, &nzombie); /* ** activate the installed print-function to visualize ** the deviations */ lastcmd = (vis.show_samp)( curtime, curtime-pretime > 0 ? curtime-pretime : 1, devsstat, devpstat, n, npresent, ntrun, ntslpi, ntslpu, nzombie, nexit, sampcnt==0); /* ** release dynamically allocated memory */ if (nexit > 0) free(curpexit); free(devpstat); if (lastcmd == 'r') /* reset requested ? */ { sampcnt = -1; curtime = getboot(); /* reset current time */ /* set current (will be 'previous') counters to 0 */ memset(cursstat, 0, sizeof(struct sstat)); memset(curpact, 0, curplen * sizeof(struct pstat)); /* remove all processes in process database */ pdb_makeresidue(); pdb_cleanresidue(); } } /* end of main-loop */ }