/* * Copyright (c) 2013-2014 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * Import collectl raw data file and create a PCP archive. * Mark Goodwin May 2013. */ #include #include #include #include #include "metrics.h" #define BUFSIZE 1048576 handler_t handlers[] = { { ">>>", timestamp_handler }, /* /proc/PID/... */ { "proc:*", proc_handler }, /* /proc/stat */ { "cpu*", cpu_handler }, { "processes", generic1_handler, "kernel.all.nprocs" }, { "intr", generic1_handler, "kernel.all.intr" }, { "ctxt", generic1_handler, "kernel.all.pswitch" }, /* /proc/diskstats */ { "disk", disk_handler }, /* /proc/net/dev */ { "Net", net_handler }, /* /proc/loadavg */ { "load", loadavg_handler }, /* /proc/meminfo */ { "MemTotal:", generic1_handler, "mem.physmem" }, { "MemFree:", generic1_handler, "mem.util.free" }, { "Buffers:", generic1_handler, "mem.util.bufmem" }, { "Cached:", generic1_handler, "mem.util.cached" }, { "SwapCached:", generic1_handler, "mem.util.swapCached" }, { "Active:", generic1_handler, "mem.util.active" }, { "Inactive:", generic1_handler, "mem.util.inactive" }, { "Active(anon):", generic1_handler, "mem.util.active_anon" }, { "Inactive(anon):", generic1_handler, "mem.util.inactive_anon" }, { "Active(file):", generic1_handler, "mem.util.active_file" }, { "Inactive(file):", generic1_handler, "mem.util.inactive_file" }, { "Unevictable:", generic1_handler, "mem.util.unevictable" }, { "Mlocked:", generic1_handler, "mem.util.mlocked" }, { "SwapTotal:", generic1_handler, "mem.util.swapTotal" }, { "SwapFree:", generic1_handler, "mem.util.swapFree" }, { "Dirty:", generic1_handler, "mem.util.dirty" }, { "Writeback:", generic1_handler, "mem.util.writeback" }, { "AnonPages:", generic1_handler, "mem.util.anonpages" }, { "Mapped:", generic1_handler, "mem.util.mapped" }, { "Shmem:", generic1_handler, "mem.util.shmem" }, { "Slab:", generic1_handler, "mem.util.slab" }, { "SReclaimable:", generic1_handler, "mem.util.slabReclaimable" }, { "SUnreclaim:", generic1_handler, "mem.util.slabUnreclaimable" }, { "KernelStack:", generic1_handler, "mem.util.kernelStack" }, { "PageTables:", generic1_handler, "mem.util.pageTables" }, { "NFS_Unstable:", generic1_handler, "mem.util.NFS_Unstable" }, { "Bounce:", generic1_handler, "mem.util.bounce" }, { "WritebackTmp:", generic1_handler, "unknown" }, { "CommitLimit:", generic1_handler, "mem.util.commitLimit" }, { "Committed_AS:", generic1_handler, "mem.util.committed_AS" }, { "VmallocTotal:", generic1_handler, "mem.util.vmallocTotal" }, { "VmallocUsed:", generic1_handler, "mem.util.vmallocUsed" }, { "VmallocChunk:", generic1_handler, "mem.util.vmallocChunk" }, { "HardwareCorrupted:", generic1_handler, "mem.util.corrupthardware" }, { "AnonHugePages:", generic1_handler, "mem.util.anonhugepages" }, { "HugePages_Total:", generic1_handler, "mem.util.hugepagesTotal" }, { "HugePages_Free:", generic1_handler, "mem.util.hugepagesFree" }, { "HugePages_Rsvd:", generic1_handler, "mem.util.hugepagesRsvd" }, { "HugePages_Surp:", generic1_handler, "mem.util.hugepagesSurp" }, { "Hugepagesize:", generic1_handler, "unknown" }, { "DirectMap4k:", generic1_handler, "mem.util.directMap4k" }, { "DirectMap2M:", generic1_handler, "mem.util.directMap2M" }, { NULL } }; int indom_cnt[NUM_INDOMS]; /* global options */ int vflag; int Fflag; int kernel_all_hz; int utc_offset; static pmLongOptions longopts[] = { PMAPI_OPTIONS_HEADER("Options"), PMOPT_DEBUG, { "force", 0, 'f', 0, "forces overwrite of 'archive' if it already exists" }, { "verbose", 0, 'v', 0, "enables increasingly verbose messages" }, PMOPT_HELP, PMAPI_OPTIONS_END }; static pmOptions opts = { .short_options = "FD:v?", .long_options = longopts, .short_usage = "inputfile [inputfile ...] archive\n" "Each 'inputfile' is a collectl archive, must be for the same host (may be gzipped).\n" "'archive' is the base name for the PCP archive to be created." }; int main(int argc, char *argv[]) { int sts; int ctx; int c; char *infile; int nfilelist; int filenum; char *archive = NULL; int j; char *buf; fields_t *f; char *s; int gzipped; FILE *fp; metric_t *m; handler_t *h; int unhandled_metric_cnt = 0; while ((c = pmGetOptions(argc, argv, &opts)) != EOF) { switch (c) { case 'F': Fflag = 1; break; case 'v': vflag++; break; } } nfilelist = argc - opts.optind - 1; if (nfilelist < 1) opts.errors++; else archive = argv[argc - 1]; if (opts.errors) { pmUsageMessage(&opts); exit(1); } if ((buf = malloc(BUFSIZE)) == NULL) { perror("Error: out of memory:"); exit(1); } if (Fflag) { snprintf(buf, BUFSIZE, "%s.meta", archive); unlink(buf); snprintf(buf, BUFSIZE, "%s.index", archive); unlink(buf); for (j=0;; j++) { snprintf(buf, BUFSIZE, "%s.%d", archive, j); if (unlink(buf) < 0) break; } } ctx = pmiStart(archive, 0); if ((sts = pmiUseContext(ctx)) < 0) { fprintf(stderr, "Error: pmiUseContext failed: %s\n", pmiErrStr(sts)); exit(1); } /* * Define the metrics name space, see metrics.c (generated by pmdesc) */ for (m = metrics; m->name; m++) { pmDesc *d = &m->desc; sts = pmiAddMetric(m->name, d->pmid, d->type, d->indom, d->sem, d->units); if (sts < 0) { fprintf(stderr, "Error: failed to add metric %s: %s\n", m->name, pmiErrStr(sts)); exit(1); } } /* * Populate special case instance domains */ pmiAddInstance(pmInDom_build(LINUX_DOMAIN, LOADAVG_INDOM), "1 minute", 1); pmiAddInstance(pmInDom_build(LINUX_DOMAIN, LOADAVG_INDOM), "5 minute", 5); pmiAddInstance(pmInDom_build(LINUX_DOMAIN, LOADAVG_INDOM), "15 minute", 15); indom_cnt[LOADAVG_INDOM] = 3; for (filenum=0; filenum < nfilelist; filenum++) { infile = argv[opts.optind + filenum]; gzipped = strstr(infile, ".gz") != NULL; if (gzipped) { snprintf(buf, BUFSIZE, "gzip -c -d %s", infile); if ((fp = popen(buf, "r")) == NULL) perror(buf); } else if ((fp = fopen(infile, "r")) == NULL) perror(infile); if (fp == NULL) { pmUsageMessage(&opts); exit(1); } /* * parse the header */ sts = header_handler(fp, infile, buf, BUFSIZE); /* * Parse remaining data stream for this input file */ while(fgets(buf, BUFSIZE, fp)) { if ((s = strrchr(buf, '\n')) != NULL) *s = '\0'; if (!buf[0]) continue; f = fields_new(buf, strlen(buf)+1); if (f->nfields > 0) { if ((h = find_handler(f->fields[0])) == NULL) { unhandled_metric_cnt++; if (vflag > 1) printf("Unhandled tag: \"%s\"\n", f->fields[0]); } else { sts = h->handler(h, f); if (sts < 0 && h->handler == timestamp_handler) { fprintf(stderr, "Error: %s\n", pmiErrStr(sts)); exit(1); } } } fields_free(f); } /* final flush for this file */ if ((sts = timestamp_flush()) < 0) { fprintf(stderr, "Error: failed to write final timestamp: %s\n", pmiErrStr(sts)); exit(1); } if (gzipped) pclose(fp); else fclose(fp); } sts = pmiEnd(); if (unhandled_metric_cnt && vflag) fprintf(stderr, "Warning: %d unhandled metric/values\n", unhandled_metric_cnt); exit(0); }