diff options
Diffstat (limited to 'src/collectl2pcp/collectl2pcp.c')
-rw-r--r-- | src/collectl2pcp/collectl2pcp.c | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/src/collectl2pcp/collectl2pcp.c b/src/collectl2pcp/collectl2pcp.c new file mode 100644 index 0000000..c9755af --- /dev/null +++ b/src/collectl2pcp/collectl2pcp.c @@ -0,0 +1,268 @@ +/* + * 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 <mgoodwin@redhat.com> May 2013. + */ + +#include <pcp/pmapi.h> +#include <pcp/impl.h> +#include <pcp/pmda.h> +#include <pcp/import.h> +#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); +} |