/* * Copyright (c) 2015, Intel Corporation * Author: Andi Kleen * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Poor man's perf stat using jevents */ /* jstat [-a] [-p pid] [-e events] program */ /* Supports named events if downloaded first (w/ event_download.py) */ /* Run listevents to show the available events */ #include #include #include #include #include #include #include #include #include #include #include "jevents.h" #include "jsession.h" #define err(x) perror(x), exit(1) #define PAIR(x) x, sizeof(x) - 1 void print_data(struct eventlist *el) { struct event *e; int i; for (e = el->eventlist; e; e = e->next) { uint64_t v = 0; for (i = 0; i < el->num_cpus; i++) v += event_scaled_value(e, i); printf("%-30s %'10lu\n", e->event, v); } } static struct option opts[] = { { "all-cpus", no_argument, 0, 'a' }, { "events", required_argument, 0, 'e'}, {}, }; void usage(void) { fprintf(stderr, "Usage: jstat [-a] [-e events] program\n" "--all -a Measure global system\n" "-e --events list Comma separate list of events to measure. Use {} for groups\n" "Run event_download.py once first to use symbolic events\n"); exit(1); } void sigint(int sig) {} int main(int ac, char **av) { char *events = "instructions,cpu-cycles,cache-misses,cache-references"; int opt; int child_pipe[2]; struct eventlist *el; bool measure_all = false; int measure_pid = -1; int child_pid; setlocale(LC_NUMERIC, ""); el = alloc_eventlist(); while ((opt = getopt_long(ac, av, "ae:p:", opts, NULL)) != -1) { switch (opt) { case 'e': events = optarg; break; case 'a': measure_all = true; break; default: usage(); } } if (parse_events(el, events) < 0) exit(1); pipe(child_pipe); signal(SIGCHLD, SIG_IGN); child_pid = measure_pid = fork(); if (measure_pid < 0) err("fork"); if (measure_pid == 0) { char buf; /* Wait for events to be set up */ read(child_pipe[0], &buf, 1); execvp(av[optind], av + optind); write(2, PAIR("Cannot execute program\n")); _exit(1); } setup_events(el, measure_all, measure_pid); signal(SIGINT, sigint); if (child_pid >= 0) { write(child_pipe[1], "x", 1); waitpid(measure_pid, NULL, 0); } else { pause(); } read_all_events(el); print_data(el); return 0; }