void perf_start(const char* kname) { if (!enabled) return; char* prof_envvar = getenv("MXPA_PROFILE"); int tids[32]; int ntid; get_tids(tids, &ntid); g_nthreads = ntid; int n; for (n = 0; n < ntid; n++) { int ret; ret = perf_setup_list_events(prof_envvar, &(g_fds[n]), &num_fds); perf_event_desc_t *fds = g_fds[n]; int cpu = -1; int group_fd = -1; int pid = tids[n]; fds[0].fd = -1; int i; for(i=0; i < num_fds; i++) { fds[i].hw.read_format = PERF_FORMAT_SCALE; fds[i].hw.disabled = 1; /* do not start now */ fds[i].hw.inherit = 1; /* XXX child process will inherit, when forked only? */ /* each event is in an independent group (multiplexing likely) */ fds[i].fd = perf_event_open(&fds[i].hw, pid, cpu, group_fd, 0); if (fds[i].fd == -1) { fprintf(stderr, "cannot open event %d\n", i); exit(2); } } } prctl(PR_TASK_PERF_EVENTS_ENABLE); }
void perfevent_initialize(char*events) { int i, ret; perfevent_events = strdup(events); /* * Initialize pfm library (required before we can use it) */ ret = pfm_initialize(); if (ret != PFM_SUCCESS) errx(1, "Cannot initialize library: %s", pfm_strerror(ret)); ret = perf_setup_list_events(events, &perfevent_fds, &perfevent_num_fds); if (ret || !perfevent_num_fds) errx(1, "cannot setup events"); perfevent_fds[0].fd = -1; for(i=0; i < perfevent_num_fds; i++) { /* request timing information necessary for scaling */ perfevent_fds[i].hw.read_format = PERF_FORMAT_SCALE; perfevent_fds[i].hw.disabled = (i == 0); /* do not start now */ perfevent_fds[i].hw.inherit = 1; /* pass on to child threads */ /* each event is in an independent group (multiplexing likely) */ perfevent_fds[i].fd = perf_event_open(&perfevent_fds[i].hw, 0, -1, perfevent_fds[0].fd, 0); if (perfevent_fds[i].fd == -1) err(1, "cannot open event %d", i); } }
int measure(pid_t pid) { perf_event_desc_t *fds = NULL; int i, ret, num_fds = 0; char fn[32]; if (pfm_initialize() != PFM_SUCCESS) errx(1, "libpfm initialization failed\n"); ret = perf_setup_list_events(options.events, &fds, &num_fds); if (ret || (num_fds == 0)) exit(1); fds[0].fd = -1; for(i=0; i < num_fds; i++) { fds[i].hw.disabled = 0; /* start immediately */ /* request timing information necessary for scaling counts */ fds[i].hw.read_format = PERF_FORMAT_SCALE; fds[i].hw.pinned = !i && options.pinned; fds[i].fd = perf_event_open(&fds[i].hw, pid, -1, (options.group? fds[0].fd : -1), 0); if (fds[i].fd == -1) errx(1, "cannot attach event %s", fds[i].name); } /* * no notification is generated by perf_counters * when the monitored thread exits. Thus we need * to poll /proc/ to detect it has disappeared, * otherwise we have to wait until the end of the * timeout */ sprintf(fn, "/proc/%d/status", pid); while(access(fn, F_OK) == 0 && options.delay) { sleep(1); options.delay--; if (options.print) print_counts(fds, num_fds, 1); } if (options.delay) warn("thread %d terminated before timeout", pid); if (!options.print) print_counts(fds, num_fds, 0); for(i=0; i < num_fds; i++) close(fds[i].fd); free(fds); /* free libpfm resources cleanly */ pfm_terminate(); return 0; }
int mainloop(char **arg) { static uint64_t ovfl_count; /* static to avoid setjmp issue */ struct pollfd pollfds[1]; sigset_t bmask; int go[2], ready[2]; size_t pgsz; size_t map_size = 0; pid_t pid; int status, ret; int i; char buf; if (pfm_initialize() != PFM_SUCCESS) errx(1, "libpfm initialization failed\n"); pgsz = sysconf(_SC_PAGESIZE); map_size = (options.mmap_pages+1)*pgsz; /* * does allocate fds */ ret = perf_setup_list_events(options.events, &fds, &num_fds); if (ret || !num_fds) errx(1, "cannot setup event list"); memset(pollfds, 0, sizeof(pollfds)); ret = pipe(ready); if (ret) err(1, "cannot create pipe ready"); ret = pipe(go); if (ret) err(1, "cannot create pipe go"); /* * Create the child task */ // if ((pid=fork()) == -1) // err(1, "cannot fork process\n"); /* if (pid == 0) { close(ready[0]); close(go[1]); */ /* * let the parent know we exist */ /* close(ready[1]); if (read(go[0], &buf, 1) == -1) err(1, "unable to read go_pipe"); exit(child(arg)); } */ int tid; pid = getpid(); tid = gettid(); printf("From C - pid : %d, tid : %d\n",pid, tid); close(ready[1]); close(go[0]); if (read(ready[0], &buf, 1) == -1) err(1, "unable to read child_ready_pipe"); close(ready[0]); fds[0].fd = -1; fds[0].hw.sample_period=10000; if (!fds[0].hw.sample_period) errx(1, "need to set sampling period or freq on first event, use :period= or :freq="); for(i=0; i < num_fds; i++) { if (i == 0) { fds[i].hw.disabled = 1; fds[i].hw.enable_on_exec = 1; /* start immediately */ } else fds[i].hw.disabled = 0; if (options.opt_inherit) fds[i].hw.inherit = 1; if (fds[i].hw.sample_period) { /* * set notification threshold to be halfway through the buffer */ fds[i].hw.wakeup_watermark = (options.mmap_pages*pgsz) / 2; fds[i].hw.watermark = 1; fds[i].hw.sample_type = PERF_SAMPLE_IP|PERF_SAMPLE_TID|PERF_SAMPLE_READ|PERF_SAMPLE_TIME|PERF_SAMPLE_PERIOD; /* * if we have more than one event, then record event identifier to help with parsing */ if (num_fds > 1) fds[i].hw.sample_type |= PERF_SAMPLE_IDENTIFIER; fprintf(options.output_file,"%s period=%"PRIu64" freq=%d\n", fds[i].name, fds[i].hw.sample_period, fds[i].hw.freq); fds[i].hw.read_format = PERF_FORMAT_SCALE; if (fds[i].hw.freq) fds[i].hw.sample_type |= PERF_SAMPLE_PERIOD; fds[i].hw.sample_period=10000; if (options.mem_mode) fds[i].hw.sample_type |= PERF_SAMPLE_WEIGHT | PERF_SAMPLE_DATA_SRC | PERF_SAMPLE_ADDR; if (options.branch_mode) { fds[i].hw.sample_type |= PERF_SAMPLE_BRANCH_STACK; fds[i].hw.branch_sample_type = PERF_SAMPLE_BRANCH_ANY; } } /* * we are grouping the events, so there may be a limit */ fds[i].fd = perf_event_open(&fds[i].hw, tid+1, options.cpu, fds[0].fd, 0); if (fds[i].fd == -1) { if (fds[i].hw.precise_ip) err(1, "cannot attach event %s: precise mode may not be supported", fds[i].name); err(1, "cannot attach event %s", fds[i].name); } } /* * kernel adds the header page to the size of the mmapped region */ fds[0].buf = mmap(NULL, map_size, PROT_READ|PROT_WRITE, MAP_SHARED, fds[0].fd, 0); if (fds[0].buf == MAP_FAILED) err(1, "cannot mmap buffer"); /* does not include header page */ fds[0].pgmsk = (options.mmap_pages*pgsz)-1; /* * send samples for all events to first event's buffer */ for (i = 1; i < num_fds; i++) { if (!fds[i].hw.sample_period) continue; ret = ioctl(fds[i].fd, PERF_EVENT_IOC_SET_OUTPUT, fds[0].fd); if (ret) err(1, "cannot redirect sampling output"); } if (num_fds > 1 && fds[0].fd > -1) { for(i = 0; i < num_fds; i++) { /* * read the event identifier using ioctl * new method replaced the trick with PERF_FORMAT_GROUP + PERF_FORMAT_ID + read() */ ret = ioctl(fds[i].fd, PERF_EVENT_IOC_ID, &fds[i].id); if (ret == -1) err(1, "cannot read ID"); fprintf(options.output_file,"ID %"PRIu64" %s\n", fds[i].id, fds[i].name); } } pollfds[0].fd = fds[0].fd; pollfds[0].events = POLLIN; for(i=0; i < num_fds; i++) { ret = ioctl(fds[i].fd, PERF_EVENT_IOC_ENABLE, 0); if (ret) err(1, "cannot enable event %s\n", fds[i].name); } signal(SIGCHLD, cld_handler); close(go[1]); if (setjmp(jbuf) == 1) goto terminate_session; sigemptyset(&bmask); sigaddset(&bmask, SIGCHLD); /* * core loop */ for(;;) { ret = poll(pollfds, 1, -1); if (ret < 0 && errno == EINTR) break; ovfl_count++; ret = sigprocmask(SIG_SETMASK, &bmask, NULL); if (ret) err(1, "setmask"); process_smpl_buf(&fds[0]); ret = sigprocmask(SIG_UNBLOCK, &bmask, NULL); if (ret) err(1, "unblock"); } printf("How was you day??\n"); terminate_session: /* * cleanup child */ wait4(pid, &status, 0, NULL); for(i=0; i < num_fds; i++) close(fds[i].fd); /* check for partial event buffer */ process_smpl_buf(&fds[0]); munmap(fds[0].buf, map_size); perf_free_fds(fds, num_fds); fprintf(options.output_file, "%"PRIu64" samples collected in %"PRIu64" poll events, %"PRIu64" lost samples\n", collected_samples, ovfl_count, lost_samples); /* free libpfm resources cleanly */ pfm_terminate(); fclose(options.output_file); return 0; }
int setup_cpu(int cpu, int fd) { uint64_t *val; int ret, flags; int i; /* * does allocate fds */ ret = perf_setup_list_events(options.events, &fds, &num_fds); if (ret || !num_fds) errx(1, "cannot setup event list"); if (!fds[0].hw.sample_period) errx(1, "need to set sampling period or freq on first event, use :period= or :freq="); fds[0].fd = -1; for(i=0; i < num_fds; i++) { fds[i].hw.disabled = !i; /* start immediately */ if (options.cgroup) { flags = PERF_FLAG_PID_CGROUP; } else { flags = 0; } if (options.pin) fds[i].hw.pinned = 1; if (fds[i].hw.sample_period) { /* * set notification threshold to be halfway through the buffer */ if (fds[i].hw.sample_period) { fds[i].hw.wakeup_watermark = (options.mmap_pages*pgsz) / 2; fds[i].hw.watermark = 1; } fds[i].hw.sample_type = PERF_SAMPLE_IP|PERF_SAMPLE_TID|PERF_SAMPLE_READ|PERF_SAMPLE_TIME|PERF_SAMPLE_PERIOD|PERF_SAMPLE_STREAM_ID|PERF_SAMPLE_CPU; printf("%s period=%"PRIu64" freq=%d\n", fds[i].name, fds[i].hw.sample_period, fds[i].hw.freq); fds[i].hw.read_format = PERF_FORMAT_SCALE; if (num_fds > 1) fds[i].hw.read_format |= PERF_FORMAT_GROUP|PERF_FORMAT_ID; if (fds[i].hw.freq) fds[i].hw.sample_type |= PERF_SAMPLE_PERIOD; } fds[i].fd = perf_event_open(&fds[i].hw, -1, cpu, fds[0].fd, flags); if (fds[i].fd == -1) { if (fds[i].hw.precise_ip) err(1, "cannot attach event %s: precise mode may not be supported", fds[i].name); err(1, "cannot attach event %s", fds[i].name); } } /* * kernel adds the header page to the size of the mmapped region */ fds[0].buf = mmap(NULL, map_size, PROT_READ|PROT_WRITE, MAP_SHARED, fds[0].fd, 0); if (fds[0].buf == MAP_FAILED) err(1, "cannot mmap buffer"); /* does not include header page */ fds[0].pgmsk = (options.mmap_pages*pgsz)-1; /* * send samples for all events to first event's buffer */ for (i = 1; i < num_fds; i++) { if (!fds[i].hw.sample_period) continue; ret = ioctl(fds[i].fd, PERF_EVENT_IOC_SET_OUTPUT, fds[0].fd); if (ret) err(1, "cannot redirect sampling output"); } /* * we are using PERF_FORMAT_GROUP, therefore the structure * of val is as follows: * * { u64 nr; * { u64 time_enabled; } && PERF_FORMAT_ENABLED * { u64 time_running; } && PERF_FORMAT_RUNNING * { u64 value; * { u64 id; } && PERF_FORMAT_ID * } cntr[nr]; * } * We are skipping the first 3 values (nr, time_enabled, time_running) * and then for each event we get a pair of values. */ if (num_fds > 1) { sz = (3+2*num_fds)*sizeof(uint64_t); val = malloc(sz); if (!val) err(1, "cannot allocated memory"); ret = read(fds[0].fd, val, sz); if (ret == -1) err(1, "cannot read id %zu", sizeof(val)); for(i=0; i < num_fds; i++) { fds[i].id = val[2*i+1+3]; printf("%"PRIu64" %s\n", fds[i].id, fds[i].name); } free(val); } return 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(); }
int mainloop(char **arg) { static uint64_t ovfl_count; /* static to avoid setjmp issue */ struct pollfd pollfds[1]; sigset_t bmask; int go[2], ready[2]; uint64_t *val; size_t sz, pgsz; size_t map_size = 0; pid_t pid; int status, ret; int i; char buf; if (pfm_initialize() != PFM_SUCCESS) errx(1, "libpfm initialization failed\n"); pgsz = sysconf(_SC_PAGESIZE); map_size = (options.mmap_pages+1)*pgsz; /* * does allocate fds */ ret = perf_setup_list_events(options.events, &fds, &num_fds); if (ret || !num_fds) errx(1, "cannot setup event list"); memset(pollfds, 0, sizeof(pollfds)); ret = pipe(ready); if (ret) err(1, "cannot create pipe ready"); ret = pipe(go); if (ret) err(1, "cannot create pipe go"); /* * Create the child task */ if ((pid=fork()) == -1) err(1, "cannot fork process\n"); if (pid == 0) { close(ready[0]); close(go[1]); /* * let the parent know we exist */ close(ready[1]); if (read(go[0], &buf, 1) == -1) err(1, "unable to read go_pipe"); exit(child(arg)); } close(ready[1]); close(go[0]); if (read(ready[0], &buf, 1) == -1) err(1, "unable to read child_ready_pipe"); close(ready[0]); fds[0].fd = -1; if (!fds[0].hw.sample_period) errx(1, "need to set sampling period or freq on first event, use :period= or :freq="); for(i=0; i < num_fds; i++) { if (i == 0) { fds[i].hw.disabled = 1; fds[i].hw.enable_on_exec = 1; /* start immediately */ } else fds[i].hw.disabled = 0; if (options.opt_inherit) fds[i].hw.inherit = 1; if (fds[i].hw.sample_period) { /* * set notification threshold to be halfway through the buffer */ fds[i].hw.wakeup_watermark = (options.mmap_pages*pgsz) / 2; fds[i].hw.watermark = 1; fds[i].hw.sample_type = PERF_SAMPLE_IP|PERF_SAMPLE_TID|PERF_SAMPLE_READ|PERF_SAMPLE_TIME|PERF_SAMPLE_PERIOD|PERF_SAMPLE_STREAM_ID; fprintf(options.output_file,"%s period=%"PRIu64" freq=%d\n", fds[i].name, fds[i].hw.sample_period, fds[i].hw.freq); fds[i].hw.read_format = PERF_FORMAT_SCALE; if (num_fds > 1) fds[i].hw.read_format |= PERF_FORMAT_GROUP|PERF_FORMAT_ID; if (fds[i].hw.freq) fds[i].hw.sample_type |= PERF_SAMPLE_PERIOD; } fds[i].fd = perf_event_open(&fds[i].hw, pid, options.cpu, fds[0].fd, 0); if (fds[i].fd == -1) { if (fds[i].hw.precise_ip) err(1, "cannot attach event %s: precise mode may not be supported", fds[i].name); err(1, "cannot attach event %s", fds[i].name); } } /* * kernel adds the header page to the size of the mmapped region */ fds[0].buf = mmap(NULL, map_size, PROT_READ|PROT_WRITE, MAP_SHARED, fds[0].fd, 0); if (fds[0].buf == MAP_FAILED) err(1, "cannot mmap buffer"); /* does not include header page */ fds[0].pgmsk = (options.mmap_pages*pgsz)-1; /* * send samples for all events to first event's buffer */ for (i = 1; i < num_fds; i++) { if (!fds[i].hw.sample_period) continue; ret = ioctl(fds[i].fd, PERF_EVENT_IOC_SET_OUTPUT, fds[0].fd); if (ret) err(1, "cannot redirect sampling output"); } /* * we are using PERF_FORMAT_GROUP, therefore the structure * of val is as follows: * * { u64 nr; * { u64 time_enabled; } && PERF_FORMAT_ENABLED * { u64 time_running; } && PERF_FORMAT_RUNNING * { u64 value; * { u64 id; } && PERF_FORMAT_ID * } cntr[nr]; * We are skipping the first 3 values (nr, time_enabled, time_running) * and then for each event we get a pair of values. */ if (num_fds > 1) { sz = (3+2*num_fds)*sizeof(uint64_t); val = malloc(sz); if (!val) err(1, "cannot allocate memory"); ret = read(fds[0].fd, val, sz); if (ret == -1) err(1, "cannot read id %zu", sizeof(val)); for(i=0; i < num_fds; i++) { fds[i].id = val[2*i+1+3]; fprintf(options.output_file,"%"PRIu64" %s\n", fds[i].id, fds[i].name); } free(val); } pollfds[0].fd = fds[0].fd; pollfds[0].events = POLLIN; for(i=0; i < num_fds; i++) { ret = ioctl(fds[i].fd, PERF_EVENT_IOC_ENABLE, 0); if (ret) err(1, "cannot enable event %s\n", fds[i].name); } signal(SIGCHLD, cld_handler); close(go[1]); if (setjmp(jbuf) == 1) goto terminate_session; sigemptyset(&bmask); sigaddset(&bmask, SIGCHLD); /* * core loop */ for(;;) { ret = poll(pollfds, 1, -1); if (ret < 0 && errno == EINTR) break; ovfl_count++; ret = sigprocmask(SIG_SETMASK, &bmask, NULL); if (ret) err(1, "setmask"); process_smpl_buf(&fds[0]); ret = sigprocmask(SIG_UNBLOCK, &bmask, NULL); if (ret) err(1, "unblock"); } terminate_session: /* * cleanup child */ wait4(pid, &status, 0, NULL); for(i=0; i < num_fds; i++) close(fds[i].fd); /* check for partial event buffer */ process_smpl_buf(&fds[0]); munmap(fds[0].buf, map_size); perf_free_fds(fds, num_fds); fprintf(options.output_file, "%"PRIu64" samples collected in %"PRIu64" poll events, %"PRIu64" lost samples\n", collected_samples, ovfl_count, lost_samples); /* free libpfm resources cleanly */ pfm_terminate(); fclose(options.output_file); return 0; }
int parent(char **arg) { perf_event_desc_t *fds = NULL; int status, ret, i, num_fds = 0, grp, group_fd; int ready[2], go[2]; char buf; pid_t pid; // output_file = fopen(file_name, "w"); //if (chroot("/home/pittdvs/cpu2006/benchspec/CPU2006/464.h264ref/run/run_base_ref_amd64-m64-gcc42-nn.0000")) // err(1, "err on chroot()"); if (pfm_initialize() != PFM_SUCCESS) errx(1, "libpfm initialization failed"); for (grp = 0; grp < options.num_groups; grp++) { int ret; ret = perf_setup_list_events(options.events[grp], &fds, &num_fds); if (ret || !num_fds) exit(1); } pid = options.pid; if (!pid) { ret = pipe(ready); if (ret) err(1, "cannot create pipe ready"); ret = pipe(go); if (ret) err(1, "cannot create pipe go"); /* * Create the child task */ if ((pid=fork()) == -1) err(1, "Cannot fork process"); /* * and launch the child code * * The pipe is used to avoid a race condition * between for() and exec(). We need the pid * of the new tak but we want to start measuring * at the first user level instruction. Thus we * need to prevent exec until we have attached * the events. */ if (pid == 0) { close(ready[0]); close(go[1]); /* * let the parent know we exist */ close(ready[1]); if (read(go[0], &buf, 1) == -1) err(1, "unable to read go_pipe"); exit(child(arg)); } close(ready[1]); close(go[0]); if (read(ready[0], &buf, 1) == -1) err(1, "unable to read child_ready_pipe"); close(ready[0]); } for(i=0; i < num_fds; i++) { int is_group_leader; /* boolean */ is_group_leader = perf_is_group_leader(fds, i); if (is_group_leader) { /* this is the group leader */ group_fd = -1; } else { group_fd = fds[fds[i].group_leader].fd; } /* * create leader disabled with enable_on-exec */ if (!options.pid) { fds[i].hw.disabled = is_group_leader; fds[i].hw.enable_on_exec = is_group_leader; } fds[i].hw.read_format = PERF_FORMAT_SCALE; /* request timing information necessary for scaling counts */ if (is_group_leader && options.format_group) fds[i].hw.read_format |= PERF_FORMAT_GROUP; if (options.inherit) fds[i].hw.inherit = 1; if (options.pin && is_group_leader) fds[i].hw.pinned = 1; fds[i].fd = perf_event_open(&fds[i].hw, pid, -1, group_fd, 0); if (fds[i].fd == -1) { warn("cannot attach event%d %s", i, fds[i].name); goto error; } } if (!options.pid) close(go[1]); if (options.print) { if (!options.pid) { while(waitpid(pid, &status, WNOHANG) == 0 && quit == 0) { //sleep(1); //usleep(10000); msleep(100); //better_sleep(0.05); // 50ms print_counts(fds, num_fds); } } else { while(quit == 0) { sleep(1); print_counts(fds, num_fds); } } } else { if (!options.pid) waitpid(pid, &status, 0); else pause(); print_counts(fds, num_fds); } for(i=0; i < num_fds; i++) close(fds[i].fd); free(fds); /* free libpfm resources cleanly */ pfm_terminate(); // fclose(output_file); return 0; error: free(fds); if (!options.pid) kill(SIGKILL, pid); /* free libpfm resources cleanly */ pfm_terminate(); // fclose(output_file); return -1; }
void setup_cpu(int cpu, int cfd) { perf_event_desc_t *fds = NULL; int old_total, total = 0, num; int i, j, n, ret, is_lead, group_fd; unsigned long flags; pid_t pid; for(i=0, j=0; i < options.num_groups; i++) { old_total = total; ret = perf_setup_list_events(options.events[i], &fds, &total); if (ret) errx(1, "cannot setup events\n"); all_fds[cpu] = fds; num = total - old_total; options.nevents[i] = num; for(n=0; n < num; n++, j++) { is_lead = perf_is_group_leader(fds, j); if (is_lead) { fds[j].hw.disabled = 1; group_fd = -1; } else { fds[j].hw.disabled = 0; group_fd = fds[fds[j].group_leader].fd; } fds[j].hw.size = sizeof(struct perf_event_attr); if (options.cgroup_name) { flags = PERF_FLAG_PID_CGROUP; pid = cfd; //fds[j].hw.cgroup = 1; //fds[j].hw.cgroup_fd = cfd; } else { flags = 0; pid = -1; } if (options.pin && is_lead) fds[j].hw.pinned = 1; if (options.excl && is_lead) fds[j].hw.exclusive = 1; /* request timing information necessary for scaling counts */ fds[j].hw.read_format = PERF_FORMAT_SCALE; fds[j].fd = perf_event_open(&fds[j].hw, pid, cpu, group_fd, flags); if (fds[j].fd == -1) { if (errno == EACCES) err(1, "you need to be root to run system-wide on this machine"); warn("cannot attach event %s to CPU%ds, skipping it", fds[j].name, cpu); goto error; } } } return; error: for (i=0; i < j; i++) { close(fds[i].fd); fds[i].fd = -1; } }
int main(int argc, char **argv) { struct sigaction act; uint64_t *val; size_t sz, pgsz; int ret, i; setlocale(LC_ALL, ""); ret = pfm_initialize(); if (ret != PFM_SUCCESS) errx(1, "Cannot initialize library: %s", pfm_strerror(ret)); pgsz = sysconf(_SC_PAGESIZE); /* * Install the signal handler (SIGIO) * need SA_SIGINFO because we need the fd * in the signal handler */ memset(&act, 0, sizeof(act)); act.sa_sigaction = sigio_handler; act.sa_flags = SA_SIGINFO; sigaction (SIGIO, &act, 0); /* * allocates fd for us */ ret = perf_setup_list_events("cycles," "instructions", &fds, &num_fds); if (ret || (num_fds == 0)) exit(1); fds[0].fd = -1; for(i=0; i < num_fds; i++) { /* want a notification for every each added to the buffer */ fds[i].hw.disabled = !i; if (!i) { fds[i].hw.wakeup_events = 1; fds[i].hw.sample_type = PERF_SAMPLE_IP|PERF_SAMPLE_READ|PERF_SAMPLE_PERIOD; fds[i].hw.sample_period = SMPL_PERIOD; /* read() returns event identification for signal handler */ fds[i].hw.read_format = PERF_FORMAT_GROUP|PERF_FORMAT_ID|PERF_FORMAT_SCALE; } fds[i].fd = perf_event_open(&fds[i].hw, 0, -1, fds[0].fd, 0); if (fds[i].fd == -1) err(1, "cannot attach event %s", fds[i].name); } sz = (3+2*num_fds)*sizeof(uint64_t); val = malloc(sz); if (!val) err(1, "cannot allocated memory"); /* * On overflow, the non lead events are stored in the sample. * However we need some key to figure the order in which they * were laid out in the buffer. The file descriptor does not * work for this. Instead, we extract a unique ID for each event. * That id will be part of the sample for each event value. * Therefore we will be able to match value to events * * PERF_FORMAT_ID: returns unique 64-bit identifier in addition * to event value. */ ret = read(fds[0].fd, val, sz); if (ret == -1) err(1, "cannot read id %zu", sizeof(val)); /* * we are using PERF_FORMAT_GROUP, therefore the structure * of val is as follows: * * { u64 nr; * { u64 time_enabled; } && PERF_FORMAT_ENABLED * { u64 time_running; } && PERF_FORMAT_RUNNING * { u64 value; * { u64 id; } && PERF_FORMAT_ID * } cntr[nr]; * We are skipping the first 3 values (nr, time_enabled, time_running) * and then for each event we get a pair of values. */ for(i=0; i < num_fds; i++) { fds[i].id = val[2*i+1+3]; printf("%"PRIu64" %s\n", fds[i].id, fds[i].name); } fds[0].buf = mmap(NULL, (buffer_pages+1)*pgsz, PROT_READ|PROT_WRITE, MAP_SHARED, fds[0].fd, 0); if (fds[0].buf == MAP_FAILED) err(1, "cannot mmap buffer"); fds[0].pgmsk = (buffer_pages * pgsz) - 1; /* * setup asynchronous notification on the file descriptor */ ret = fcntl(fds[0].fd, F_SETFL, fcntl(fds[0].fd, F_GETFL, 0) | O_ASYNC); if (ret == -1) err(1, "cannot set ASYNC"); /* * necessary if we want to get the file descriptor for * which the SIGIO is sent in siginfo->si_fd. * SA_SIGINFO in itself is not enough */ ret = fcntl(fds[0].fd, F_SETSIG, SIGIO); if (ret == -1) err(1, "cannot setsig"); /* * get ownership of the descriptor */ ret = fcntl(fds[0].fd, F_SETOWN, getpid()); if (ret == -1) err(1, "cannot setown"); /* * enable the group for one period */ ret = ioctl(fds[0].fd, PERF_EVENT_IOC_REFRESH , 1); if (ret == -1) err(1, "cannot refresh"); busyloop(); ret = ioctl(fds[0].fd, PERF_EVENT_IOC_DISABLE, 1); if (ret == -1) err(1, "cannot disable"); /* * destroy our session */ for(i=0; i < num_fds; i++) close(fds[i].fd); perf_free_fds(fds, num_fds); free(val); /* free libpfm resources cleanly */ pfm_terminate(); return 0; }