static void print_counts(perf_event_desc_t *fds, int num_fds, const char *msg, FILE* fp) { uint64_t val; uint64_t values[3]; double ratio; int i; ssize_t ret; #if 0 fprintf(fp, "%s ------------------------------------\n", msg); #else fprintf(fp, "method=%s", msg); #endif /* * now read the results. We use pfp_event_count because * libpfm guarantees that counters for the events always * come first. */ memset(values, 0, sizeof(values)); for (i = 0; i < num_fds; i++) { ret = read(fds[i].fd, values, sizeof(values)); if (ret < (ssize_t)sizeof(values)) { if (ret == -1) fprintf(stderr, "cannot read results: %s", strerror(errno)); else warnx("could not read event%d", i); } /* * scaling is systematic because we may be sharing the PMU and * thus may be multiplexed */ int valid; val = perf_scale_valid(values, &valid); if (valid == 0) printf ("!i=%d, v0=%llu, v1=%llu, v2=%llu, val=%llu\n", i, values[0], values[1], values[2], val); ratio = perf_scale_ratio(values); #if 0 fprintf(fp, "%s %'20"PRIu64" %s (%.2f%% scaling, raw=%'"PRIu64", ena=%'"PRIu64", run=%'"PRIu64")\n", "-", // msg, val, fds[i].name, (1.0-ratio)*100.0, values[0], values[1], values[2]); #else fprintf (fp, " %s=%llu", fds[i].name, val); // valid ? val : 0); #endif } fprintf (fp, "\n"); }
void read_cpu(int c) { perf_event_desc_t *fds; uint64_t val, delta; double ratio; int i, j, n, ret; fds = all_fds[c]; if (fds[0].fd == -1) { printf("CPU%d not monitored\n", c); return; } for(i=0, j = 0; i < options.num_groups; i++) { for(n = 0; n < options.nevents[i]; n++, j++) { ret = read(fds[j].fd, fds[j].values, sizeof(fds[j].values)); if (ret != sizeof(fds[j].values)) { if (ret == -1) err(1, "cannot read event %s : %d", fds[j].name, ret); else { warnx("CPU%d G%-2d could not read event %s, read=%d", c, i, fds[j].name, ret); continue; } } /* * scaling because we may be sharing the PMU and * thus may be multiplexed */ delta = perf_scale_delta(fds[j].values, fds[j].prev_values); val = perf_scale(fds[j].values); ratio = perf_scale_ratio(fds[j].values); printf("CPU%-3d G%-2d %'20"PRIu64" %'20"PRIu64" %s (scaling %.2f%%, ena=%'"PRIu64", run=%'"PRIu64") %s\n", c, i, val, delta, fds[j].name, (1.0-ratio)*100, fds[j].values[1], fds[j].values[2], options.cgroup_name ? options.cgroup_name : ""); fds[j].prev_values[0] = fds[j].values[0]; fds[j].prev_values[1] = fds[j].values[1]; fds[j].prev_values[2] = fds[j].values[2]; if (fds[j].values[2] > fds[j].values[1]) errx(1, "WARNING: time_running > time_enabled %"PRIu64"\n", fds[j].values[2] - fds[j].values[1]); } } }
/* Same as stop above, but without the parameter for faster calling into. */ uint64_t *pfm_pause_counters() { int ret, i; uint64_t values[3]; ret = prctl(PR_TASK_PERF_EVENTS_DISABLE); if (ret) fprintf(stderr, "prctl(disable) failed\n"); /* * now read the results. We use pfp_event_count because * libpfm guarantees that counters for the events always * come first. */ memset(values, 0, sizeof(values)); for (i=0; i < num_fds; i++) { uint64_t val; double ratio; ret = read(fds[i].fd, values, sizeof(values)); if (ret < sizeof(values)) { if (ret == -1) err(1, "cannot read results: %s", strerror(errno)); else warnx("could not read event%d", i); } /* * scaling is systematic because we may be sharing the PMU and * thus may be multiplexed */ val = perf_scale(values); ratio = perf_scale_ratio(values); counter_values[i] = val; #ifdef VERBOSE printf("%'20"PRIu64" %s (%.2f%% scaling, ena=%'"PRIu64", run=%'"PRIu64")\n", val, fds[i].name, (1.0-ratio)*100.0, values[1], values[2]); #endif } return counter_values; }
void perfevent_read() { int i, ret; uint64_t values[3]; /* * now read the results. We use pfp_event_count because * libpfm guarantees that counters for the events always * come first. */ memset(values, 0, sizeof(values)); fprintf(stderr, "============================ Tabulate Statistics ============================\n"); for (i=0; i < perfevent_num_fds; i++) { fprintf(stderr, "%s ", perfevent_fds[i].name); } fprintf(stderr, "\n"); for (i=0; i < perfevent_num_fds; i++) { uint64_t val; double ratio; ret = read(perfevent_fds[i].fd, values, sizeof(values)); if (ret < sizeof(values)) { if (ret == -1) err(1, "cannot read results: %s", strerror(errno)); else warnx("could not read event%d", i); } /* * scaling is systematic because we may be sharing the PMU and * thus may be multiplexed */ val = perf_scale(values); ratio = perf_scale_ratio(values); if (ratio == 1.0) fprintf(stderr, "%lld ", (long long int) val); else if (ratio == 0.0) fprintf(stderr, "NO_VALUE "); else fprintf(stderr, "%lld-SCALED-%.2f%% ", (long long int) val, ratio*100.0); } fprintf(stderr, "\n=============================================================================\n"); }
static void print_counts(perf_event_desc_t *fds, int num, int do_delta) { uint64_t values[3]; ssize_t ret; int i; /* * now simply read the results. */ for(i=0; i < num; i++) { uint64_t val; double ratio; ret = read(fds[i].fd, values, sizeof(values)); if (ret < (ssize_t)sizeof(values)) { if (ret == -1) err(1, "cannot read values event %s", fds[i].name); else warnx("could not read event%d", i); } /* * scaling because we may be sharing the PMU and * thus may be multiplexed */ fds[i].prev_value = fds[i].value; fds[i].value = val = perf_scale(values); ratio = perf_scale_ratio(values); val = do_delta ? (val - fds[i].prev_value): val; if (ratio == 1.0) printf("%20"PRIu64" %s\n", val, fds[i].name); else if (ratio == 0.0) printf("%20"PRIu64" %s (did not run: incompatible events, too many events in a group, competing session)\n", val, fds[i].name); else printf("%20"PRIu64" %s (scaled from %.2f%% of time)\n", val, fds[i].name, ratio*100.0); } }
static void fetch_counts(perf_event_desc_t *fds, int num_fds) { if (begins == 0) { begins = (uint64_t*) malloc(num_fds * sizeof(uint64_t)); memset(begins, 0, num_fds * sizeof(uint64_t)); } uint64_t val; uint64_t values[3]; double ratio; int i; ssize_t ret; /* * now read the results. We use pfp_event_count because * libpfm guarantees that counters for the events always * come first. */ memset(values, 0, sizeof(values)); for (i = 0; i < num_fds; i++) { ret = read(fds[i].fd, values, sizeof(values)); if (ret < (ssize_t)sizeof(values)) { if (ret == -1) fprintf(stderr, "cannot read results: %s", strerror(errno)); else warnx("could not read event%d", i); } /* * scaling is systematic because we may be sharing the PMU and * thus may be multiplexed */ int valid = 0; val = perf_scale_valid(values, &valid); if (valid == 0) printf ("@i=%d, v0=%llu, v1=%llu, v2=%llu, val=%llu\n", i, values[0], values[1], values[2], val); ratio = perf_scale_ratio(values); begins[i] = val; } }
static void print_counts(perf_event_desc_t *fds, int num) { double ratio; uint64_t val, delta; int i; read_groups(fds, num); for(i=0; i < num; i++) { val = perf_scale(fds[i].values); delta = perf_scale_delta(fds[i].values, fds[i].prev_values); ratio = perf_scale_ratio(fds[i].values); /* separate groups */ if (perf_is_group_leader(fds, i)) putchar('\n'); if (options.print) printf("%'20"PRIu64" %'20"PRIu64" %s (%.2f%% scaling, ena=%'"PRIu64", run=%'"PRIu64")\n", val, delta, fds[i].name, (1.0-ratio)*100.0, fds[i].values[1], fds[i].values[2]); else printf("%'20"PRIu64" %s (%.2f%% scaling, ena=%'"PRIu64", run=%'"PRIu64")\n", val, fds[i].name, (1.0-ratio)*100.0, fds[i].values[1], fds[i].values[2]); 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]; } }
static void print_counts(perf_event_desc_t *fds, int num, int do_delta) { ssize_t ret; int i; /* * now simply read the results. */ for(i=0; i < num; i++) { uint64_t val; double ratio; ret = read(fds[i].fd, fds[i].values, sizeof(fds[i].values)); if (ret < (ssize_t)sizeof(fds[i].values)) { if (ret == -1) err(1, "cannot read values event %s", fds[i].name); else warnx("could not read event%d", i); } val = perf_scale(fds[i].values); ratio = perf_scale_ratio(fds[i].values); val = do_delta ? perf_scale_delta(fds[i].values, fds[i].prev_values) : val; 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]; if (ratio == 1.0) printf("%20"PRIu64" %s\n", val, fds[i].name); else if (ratio == 0.0) printf("%20"PRIu64" %s (did not run: incompatible events, too many events in a group, competing session)\n", val, fds[i].name); else printf("%20"PRIu64" %s (scaled from %.2f%% of time)\n", val, fds[i].name, ratio*100.0); } }
static void measure(void) { perf_event_desc_t *fds = NULL; int num_fds = 0; uint64_t values[3]; ssize_t n; int i, ret; int pr[2], pw[2]; pid_t pid; char cc = '0'; ret = pfm_initialize(); if (ret != PFM_SUCCESS) err(1, "cannot initialize libpfm"); if (options.cpu == -1) { srandom(getpid()); options.cpu = random() % sysconf(_SC_NPROCESSORS_ONLN); } ret = pipe(pr); if (ret) err(1, "cannot create read pipe"); ret = pipe(pw); if (ret) err(1, "cannot create write pipe"); ret = perf_setup_list_events(options.events, &fds, &num_fds); if (ret || !num_fds) exit(1); for(i=0; i < num_fds; i++) { fds[i].hw.disabled = 1; fds[i].hw.read_format = PERF_FORMAT_SCALE; fds[i].fd = perf_event_open(&fds[i].hw, 0, -1, -1, 0); if (fds[i].fd == -1) err(1, "cannot open event %d", i); } /* * Pin to CPU0, inherited by child process. That will enforce * the ping-pionging and thus stress the PMU context switch * which is what we want */ ret = pin_cpu(getpid(), options.cpu); if (ret) err(1, "cannot pin to CPU%d", options.cpu); printf("Both processes pinned to CPU%d, running for %d seconds\n", options.cpu, options.delay); /* * create second process which is not monitoring at the moment */ switch(pid=fork()) { case -1: err(1, "cannot create child\n"); case 0: /* do not inherit session fd */ for(i=0; i < num_fds; i++) close(fds[i].fd); /* pr[]: write master, read child */ /* pw[]: read master, write child */ close(pr[1]); close(pw[0]); do_child(pr[0], pw[1]); exit(1); } close(pr[0]); close(pw[1]); /* * Let's roll now */ prctl(PR_TASK_PERF_EVENTS_ENABLE); signal(SIGALRM, sig_handler); alarm(options.delay); /* * ping pong loop */ while(!quit) { n = write(pr[1], "c", 1); if (n < 1) err(1, "write failed"); n = read(pw[0], &cc, 1); if (n < 1) err(1, "read failed"); } prctl(PR_TASK_PERF_EVENTS_DISABLE); for(i=0; i < num_fds; i++) { uint64_t val; double ratio; ret = read(fds[i].fd, values, sizeof(values)); if (ret == -1) err(1,"pfm_read error"); if (ret != sizeof(values)) errx(1, "did not read correct amount %d", ret); val = perf_scale(values); ratio = perf_scale_ratio(values); if (ratio == 1.0) printf("%20"PRIu64" %s\n", val, fds[i].name); else if (ratio == 0.0) printf("%20"PRIu64" %s (did not run: competing session)\n", val, fds[i].name); else printf("%20"PRIu64" %s (scaled from %.2f%% of time)\n", val, fds[i].name, ratio*100.0); } /* * kill child process */ kill(SIGKILL, pid); /* * close pipes */ close(pr[1]); close(pw[0]); /* * and destroy our session */ for(i=0; i < num_fds; i++) close(fds[i].fd); perf_free_fds(fds, num_fds); /* free libpfm resources cleanly */ pfm_terminate(); }