/* * syst.c - example of a simple system wide monitoring program * * Copyright (c) 2002-2006 Hewlett-Packard Development Company, L.P. * Contributed by Stephane Eranian * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include "perf_util.h" typedef struct { const char *events; int delay; int excl; int cpu; int group; } options_t; static options_t options; static perf_event_desc_t **all_fds; static int *num_fds; void setup_cpu(int cpu) { perf_event_desc_t *fds; int i, ret; ret = perf_setup_list_events(options.events, &all_fds[cpu], &num_fds[cpu]); if (ret || (num_fds == 0)) errx(1, "cannot setup events\n"); fds = all_fds[cpu]; /* temp */ fds[0].fd = -1; for(i=0; i < num_fds[cpu]; i++) { fds[i].hw.disabled = options.group ? !i : 1; if (options.excl && ((options.group && !i) || (!options.group))) fds[i].hw.exclusive = 1; fds[i].hw.disabled = options.group ? !i : 1; /* request timing information necessary for scaling counts */ fds[i].hw.read_format = PERF_FORMAT_SCALE; fds[i].fd = perf_event_open(&fds[i].hw, -1, cpu, (options.group ? fds[0].fd : -1), 0); if (fds[i].fd == -1) err(1, "cannot attach event to CPU%d %s", cpu, fds[i].name); } } void measure(void) { perf_event_desc_t *fds; long lret; int c, cmin, cmax, ncpus; int i, ret, l; printf("\n", options.delay); cmin = 0; lret = sysconf(_SC_NPROCESSORS_ONLN); if (lret < 0) err(1, "cannot get number of online processors"); cmax = (int)lret; ncpus = cmax; if (options.cpu != -1) { cmin = options.cpu; cmax = cmin + 1; } all_fds = calloc(ncpus, sizeof(perf_event_desc_t *)); num_fds = calloc(ncpus, sizeof(int)); if (!all_fds || !num_fds) err(1, "cannot allocate memory for internal structures"); for(c=cmin ; c < cmax; c++) setup_cpu(c); /* * FIX this for hotplug CPU */ for(c=cmin ; c < cmax; c++) { fds = all_fds[c]; if (options.group) ret = ioctl(fds[0].fd, PERF_EVENT_IOC_ENABLE, 0); else for(i=0; i < num_fds[c]; i++) { ret = ioctl(fds[i].fd, PERF_EVENT_IOC_ENABLE, 0); if (ret) err(1, "cannot enable event %s\n", fds[i].name); } } for(l=0; l < options.delay; l++) { sleep(1); puts("------------------------"); for(c = cmin; c < cmax; c++) { fds = all_fds[c]; for(i=0; i < num_fds[c]; i++) { uint64_t val, delta; double ratio; ret = read(fds[i].fd, fds[i].values, sizeof(fds[i].values)); if (ret != sizeof(fds[i].values)) { if (ret == -1) err(1, "cannot read event %d:%d", i, ret); else warnx("could not read event%d", i); } /* * scaling because we may be sharing the PMU and * thus may be multiplexed */ val = perf_scale(fds[i].values); ratio = perf_scale_ratio(fds[i].values); delta = perf_scale_delta(fds[i].values, fds[i].prev_values); printf("CPU%d val=%-20"PRIu64" %-20"PRIu64" raw=%"PRIu64" ena=%"PRIu64" run=%"PRIu64" ratio=%.2f %s\n", c, val, delta, fds[i].values[0], fds[i].values[1], fds[i].values[2], ratio, fds[i].name); fds[i].prev_values[0] = fds[i].values[0]; fds[i].prev_values[1] = fds[i].values[1]; fds[i].prev_values[2] = fds[i].values[2]; } } } for(c = cmin; c < cmax; c++) { fds = all_fds[c]; for(i=0; i < num_fds[c]; i++) close(fds[i].fd); perf_free_fds(fds, num_fds[c]); } } static void usage(void) { printf("usage: syst [-c cpu] [-x] [-h] [-d delay] [-g] [-e event1,event2,...]\n"); } int main(int argc, char **argv) { int c, ret; options.cpu = -1; while ((c=getopt(argc, argv,"hc:e:d:gx")) != -1) { switch(c) { case 'x': options.excl = 1; break; case 'e': options.events = optarg; break; case 'c': options.cpu = atoi(optarg); break; case 'g': options.group = 1; break; case 'd': options.delay = atoi(optarg); break; case 'h': usage(); exit(0); default: errx(1, "unknown error"); } } if (!options.delay) options.delay = 20; if (!options.events) options.events = "cycles,instructions"; ret = pfm_initialize(); if (ret != PFM_SUCCESS) errx(1, "libpfm initialization failed: %s\n", pfm_strerror(ret)); measure(); /* free libpfm resources cleanly */ pfm_terminate(); return 0; }