Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf tools: Introduce event selectors

Out of ad-hoc code and global arrays with hard coded sizes.

This is the first step on having a library that will be first
used on regression tests in the 'perf test' tool.

[acme@felicio linux]$ size /tmp/perf.before
text data bss dec hex filename
1273776 97384 5104416 6475576 62cf38 /tmp/perf.before
[acme@felicio linux]$ size /tmp/perf.new
text data bss dec hex filename
1275422 97416 1392416 2765254 2a31c6 /tmp/perf.new

Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

+432 -244
+4
tools/perf/Makefile
··· 396 396 LIB_H += util/debug.h 397 397 LIB_H += util/debugfs.h 398 398 LIB_H += util/event.h 399 + LIB_H += util/evsel.h 399 400 LIB_H += util/exec_cmd.h 400 401 LIB_H += util/types.h 401 402 LIB_H += util/levenshtein.h ··· 405 404 LIB_H += util/parse-events.h 406 405 LIB_H += util/quote.h 407 406 LIB_H += util/util.h 407 + LIB_H += util/xyarray.h 408 408 LIB_H += util/header.h 409 409 LIB_H += util/help.h 410 410 LIB_H += util/session.h ··· 435 433 LIB_OBJS += $(OUTPUT)util/debugfs.o 436 434 LIB_OBJS += $(OUTPUT)util/environment.o 437 435 LIB_OBJS += $(OUTPUT)util/event.o 436 + LIB_OBJS += $(OUTPUT)util/evsel.o 438 437 LIB_OBJS += $(OUTPUT)util/exec_cmd.o 439 438 LIB_OBJS += $(OUTPUT)util/help.o 440 439 LIB_OBJS += $(OUTPUT)util/levenshtein.o ··· 473 470 LIB_OBJS += $(OUTPUT)util/hist.o 474 471 LIB_OBJS += $(OUTPUT)util/probe-event.o 475 472 LIB_OBJS += $(OUTPUT)util/util.o 473 + LIB_OBJS += $(OUTPUT)util/xyarray.o 476 474 LIB_OBJS += $(OUTPUT)util/cpumap.o 477 475 478 476 BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
+53 -58
tools/perf/builtin-record.c
··· 18 18 19 19 #include "util/header.h" 20 20 #include "util/event.h" 21 + #include "util/evsel.h" 21 22 #include "util/debug.h" 22 23 #include "util/session.h" 23 24 #include "util/symbol.h" ··· 28 27 #include <sched.h> 29 28 #include <sys/mman.h> 30 29 30 + #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 31 + 31 32 enum write_mode_t { 32 33 WRITE_FORCE, 33 34 WRITE_APPEND 34 35 }; 35 - 36 - static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; 37 36 38 37 static u64 user_interval = ULLONG_MAX; 39 38 static u64 default_interval = 0; ··· 82 81 static const char *cpu_list; 83 82 84 83 struct mmap_data { 85 - int counter; 86 84 void *base; 87 85 unsigned int mask; 88 86 unsigned int prev; ··· 229 229 return h_attr; 230 230 } 231 231 232 - static void create_counter(int counter, int cpu) 232 + static void create_counter(struct perf_evsel *evsel, int cpu) 233 233 { 234 - char *filter = filters[counter]; 235 - struct perf_event_attr *attr = attrs + counter; 234 + char *filter = evsel->filter; 235 + struct perf_event_attr *attr = &evsel->attr; 236 236 struct perf_header_attr *h_attr; 237 - int track = !counter; /* only the first counter needs these */ 237 + int track = !evsel->idx; /* only the first counter needs these */ 238 238 int thread_index; 239 239 int ret; 240 240 struct { ··· 320 320 321 321 for (thread_index = 0; thread_index < thread_num; thread_index++) { 322 322 try_again: 323 - fd[nr_cpu][counter][thread_index] = sys_perf_event_open(attr, 324 - all_tids[thread_index], cpu, group_fd, 0); 323 + FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, all_tids[thread_index], cpu, group_fd, 0); 325 324 326 - if (fd[nr_cpu][counter][thread_index] < 0) { 325 + if (FD(evsel, nr_cpu, thread_index) < 0) { 327 326 int err = errno; 328 327 329 328 if (err == EPERM || err == EACCES) ··· 359 360 } 360 361 printf("\n"); 361 362 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", 362 - fd[nr_cpu][counter][thread_index], strerror(err)); 363 + FD(evsel, nr_cpu, thread_index), strerror(err)); 363 364 364 365 #if defined(__i386__) || defined(__x86_64__) 365 366 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) ··· 373 374 exit(-1); 374 375 } 375 376 376 - h_attr = get_header_attr(attr, counter); 377 + h_attr = get_header_attr(attr, evsel->idx); 377 378 if (h_attr == NULL) 378 379 die("nomem\n"); 379 380 ··· 384 385 } 385 386 } 386 387 387 - if (read(fd[nr_cpu][counter][thread_index], &read_data, sizeof(read_data)) == -1) { 388 + if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) { 388 389 perror("Unable to read perf file descriptor"); 389 390 exit(-1); 390 391 } ··· 394 395 exit(-1); 395 396 } 396 397 397 - assert(fd[nr_cpu][counter][thread_index] >= 0); 398 - fcntl(fd[nr_cpu][counter][thread_index], F_SETFL, O_NONBLOCK); 398 + assert(FD(evsel, nr_cpu, thread_index) >= 0); 399 + fcntl(FD(evsel, nr_cpu, thread_index), F_SETFL, O_NONBLOCK); 399 400 400 401 /* 401 402 * First counter acts as the group leader: 402 403 */ 403 404 if (group && group_fd == -1) 404 - group_fd = fd[nr_cpu][counter][thread_index]; 405 + group_fd = FD(evsel, nr_cpu, thread_index); 405 406 406 - if (counter || thread_index) { 407 - ret = ioctl(fd[nr_cpu][counter][thread_index], 408 - PERF_EVENT_IOC_SET_OUTPUT, 409 - fd[nr_cpu][0][0]); 407 + if (evsel->idx || thread_index) { 408 + struct perf_evsel *first; 409 + first = list_entry(evsel_list.next, struct perf_evsel, node); 410 + ret = ioctl(FD(evsel, nr_cpu, thread_index), 411 + PERF_EVENT_IOC_SET_OUTPUT, 412 + FD(first, nr_cpu, 0)); 410 413 if (ret) { 411 414 error("failed to set output: %d (%s)\n", errno, 412 415 strerror(errno)); 413 416 exit(-1); 414 417 } 415 418 } else { 416 - mmap_array[nr_cpu].counter = counter; 417 419 mmap_array[nr_cpu].prev = 0; 418 420 mmap_array[nr_cpu].mask = mmap_pages*page_size - 1; 419 421 mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size, 420 - PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter][thread_index], 0); 422 + PROT_READ | PROT_WRITE, MAP_SHARED, FD(evsel, nr_cpu, thread_index), 0); 421 423 if (mmap_array[nr_cpu].base == MAP_FAILED) { 422 424 error("failed to mmap with %d (%s)\n", errno, strerror(errno)); 423 425 exit(-1); 424 426 } 425 427 426 - event_array[nr_poll].fd = fd[nr_cpu][counter][thread_index]; 428 + event_array[nr_poll].fd = FD(evsel, nr_cpu, thread_index); 427 429 event_array[nr_poll].events = POLLIN; 428 430 nr_poll++; 429 431 } 430 432 431 433 if (filter != NULL) { 432 - ret = ioctl(fd[nr_cpu][counter][thread_index], 433 - PERF_EVENT_IOC_SET_FILTER, filter); 434 + ret = ioctl(FD(evsel, nr_cpu, thread_index), 435 + PERF_EVENT_IOC_SET_FILTER, filter); 434 436 if (ret) { 435 437 error("failed to set filter with %d (%s)\n", errno, 436 438 strerror(errno)); ··· 446 446 447 447 static void open_counters(int cpu) 448 448 { 449 - int counter; 449 + struct perf_evsel *pos; 450 450 451 451 group_fd = -1; 452 - for (counter = 0; counter < nr_counters; counter++) 453 - create_counter(counter, cpu); 452 + 453 + list_for_each_entry(pos, &evsel_list, node) 454 + create_counter(pos, cpu); 454 455 455 456 nr_cpu++; 456 457 } ··· 538 537 539 538 static int __cmd_record(int argc, const char **argv) 540 539 { 541 - int i, counter; 540 + int i; 542 541 struct stat st; 543 542 int flags; 544 543 int err; ··· 605 604 goto out_delete_session; 606 605 } 607 606 608 - if (have_tracepoints(attrs, nr_counters)) 607 + if (have_tracepoints(&evsel_list)) 609 608 perf_header__set_feat(&session->header, HEADER_TRACE_INFO); 610 609 611 610 /* ··· 667 666 close(child_ready_pipe[0]); 668 667 } 669 668 670 - nr_cpus = read_cpu_map(cpu_list); 671 - if (nr_cpus < 1) { 672 - perror("failed to collect number of CPUs"); 673 - return -1; 674 - } 675 - 676 669 if (!system_wide && no_inherit && !cpu_list) { 677 670 open_counters(-1); 678 671 } else { ··· 706 711 return err; 707 712 } 708 713 709 - if (have_tracepoints(attrs, nr_counters)) { 714 + if (have_tracepoints(&evsel_list)) { 710 715 /* 711 716 * FIXME err <= 0 here actually means that 712 717 * there were no tracepoints so its not really ··· 715 720 * return this more properly and also 716 721 * propagate errors that now are calling die() 717 722 */ 718 - err = event__synthesize_tracing_data(output, attrs, 719 - nr_counters, 723 + err = event__synthesize_tracing_data(output, &evsel_list, 720 724 process_synthesized_event, 721 725 session); 722 726 if (err <= 0) { ··· 789 795 790 796 if (done) { 791 797 for (i = 0; i < nr_cpu; i++) { 792 - for (counter = 0; 793 - counter < nr_counters; 794 - counter++) { 798 + struct perf_evsel *pos; 799 + 800 + list_for_each_entry(pos, &evsel_list, node) { 795 801 for (thread = 0; 796 802 thread < thread_num; 797 803 thread++) 798 - ioctl(fd[i][counter][thread], 804 + ioctl(FD(pos, i, thread), 799 805 PERF_EVENT_IOC_DISABLE); 800 806 } 801 807 } ··· 881 887 882 888 int cmd_record(int argc, const char **argv, const char *prefix __used) 883 889 { 884 - int i, j, err = -ENOMEM; 890 + int err = -ENOMEM; 891 + struct perf_evsel *pos; 885 892 886 893 argc = parse_options(argc, argv, record_options, record_usage, 887 894 PARSE_OPT_STOP_AT_NON_OPTION); ··· 905 910 if (no_buildid_cache || no_buildid) 906 911 disable_buildid_cache(); 907 912 908 - if (!nr_counters) { 909 - nr_counters = 1; 910 - attrs[0].type = PERF_TYPE_HARDWARE; 911 - attrs[0].config = PERF_COUNT_HW_CPU_CYCLES; 913 + if (list_empty(&evsel_list) && perf_evsel_list__create_default() < 0) { 914 + pr_err("Not enough memory for event selector list\n"); 915 + goto out_symbol_exit; 912 916 } 913 917 914 918 if (target_pid != -1) { ··· 927 933 thread_num = 1; 928 934 } 929 935 930 - for (i = 0; i < MAX_NR_CPUS; i++) { 931 - for (j = 0; j < MAX_COUNTERS; j++) { 932 - fd[i][j] = malloc(sizeof(int)*thread_num); 933 - if (!fd[i][j]) 934 - goto out_free_fd; 935 - } 936 + nr_cpus = read_cpu_map(cpu_list); 937 + if (nr_cpus < 1) { 938 + perror("failed to collect number of CPUs"); 939 + return -1; 940 + } 941 + 942 + list_for_each_entry(pos, &evsel_list, node) { 943 + if (perf_evsel__alloc_fd(pos, nr_cpus, thread_num) < 0) 944 + goto out_free_fd; 936 945 } 937 946 event_array = malloc( 938 947 sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num); ··· 965 968 out_free_event_array: 966 969 free(event_array); 967 970 out_free_fd: 968 - for (i = 0; i < MAX_NR_CPUS; i++) { 969 - for (j = 0; j < MAX_COUNTERS; j++) 970 - free(fd[i][j]); 971 - } 971 + list_for_each_entry(pos, &evsel_list, node) 972 + perf_evsel__free_fd(pos); 972 973 free(all_tids); 973 974 all_tids = NULL; 974 975 out_symbol_exit:
+107 -68
tools/perf/builtin-stat.c
··· 43 43 #include "util/parse-options.h" 44 44 #include "util/parse-events.h" 45 45 #include "util/event.h" 46 + #include "util/evsel.h" 46 47 #include "util/debug.h" 47 48 #include "util/header.h" 48 49 #include "util/cpumap.h" ··· 52 51 #include <sys/prctl.h> 53 52 #include <math.h> 54 53 #include <locale.h> 54 + 55 + #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 55 56 56 57 #define DEFAULT_SEPARATOR " " 57 58 ··· 93 90 static const char *csv_sep = NULL; 94 91 static bool csv_output = false; 95 92 96 - 97 - static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; 98 - 99 - static int event_scaled[MAX_COUNTERS]; 100 - 101 - static struct { 93 + struct cpu_counts { 102 94 u64 val; 103 95 u64 ena; 104 96 u64 run; 105 - } cpu_counts[MAX_NR_CPUS][MAX_COUNTERS]; 97 + }; 106 98 107 99 static volatile int done = 0; 108 100 ··· 105 107 { 106 108 double n, mean, M2; 107 109 }; 110 + 111 + struct perf_stat { 112 + struct stats res_stats[3]; 113 + int scaled; 114 + struct cpu_counts cpu_counts[]; 115 + }; 116 + 117 + static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel, int ncpus) 118 + { 119 + size_t priv_size = (sizeof(struct perf_stat) + 120 + (ncpus * sizeof(struct cpu_counts))); 121 + evsel->priv = zalloc(priv_size); 122 + return evsel->priv == NULL ? -ENOMEM : 0; 123 + } 124 + 125 + static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) 126 + { 127 + free(evsel->priv); 128 + evsel->priv = NULL; 129 + } 108 130 109 131 static void update_stats(struct stats *stats, u64 val) 110 132 { ··· 165 147 return sqrt(variance_mean); 166 148 } 167 149 168 - struct stats event_res_stats[MAX_COUNTERS][3]; 169 150 struct stats runtime_nsecs_stats[MAX_NR_CPUS]; 170 151 struct stats runtime_cycles_stats[MAX_NR_CPUS]; 171 152 struct stats runtime_branches_stats[MAX_NR_CPUS]; 172 153 struct stats walltime_nsecs_stats; 173 154 174 - #define MATCH_EVENT(t, c, counter) \ 175 - (attrs[counter].type == PERF_TYPE_##t && \ 176 - attrs[counter].config == PERF_COUNT_##c) 155 + #define MATCH_EVENT(t, c, evsel) \ 156 + (evsel->attr.type == PERF_TYPE_##t && \ 157 + evsel->attr.config == PERF_COUNT_##c) 177 158 178 159 #define ERR_PERF_OPEN \ 179 160 "counter %d, sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information." 180 161 181 - static int create_perf_stat_counter(int counter, bool *perm_err) 162 + static int create_perf_stat_counter(struct perf_evsel *evsel, bool *perm_err) 182 163 { 183 - struct perf_event_attr *attr = attrs + counter; 164 + struct perf_event_attr *attr = &evsel->attr; 184 165 int thread; 185 166 int ncreated = 0; 186 167 ··· 191 174 int cpu; 192 175 193 176 for (cpu = 0; cpu < nr_cpus; cpu++) { 194 - fd[cpu][counter][0] = sys_perf_event_open(attr, 177 + FD(evsel, cpu, 0) = sys_perf_event_open(attr, 195 178 -1, cpumap[cpu], -1, 0); 196 - if (fd[cpu][counter][0] < 0) { 179 + if (FD(evsel, cpu, 0) < 0) { 197 180 if (errno == EPERM || errno == EACCES) 198 181 *perm_err = true; 199 - error(ERR_PERF_OPEN, counter, 200 - fd[cpu][counter][0], strerror(errno)); 182 + error(ERR_PERF_OPEN, evsel->idx, 183 + FD(evsel, cpu, 0), strerror(errno)); 201 184 } else { 202 185 ++ncreated; 203 186 } ··· 209 192 attr->enable_on_exec = 1; 210 193 } 211 194 for (thread = 0; thread < thread_num; thread++) { 212 - fd[0][counter][thread] = sys_perf_event_open(attr, 195 + FD(evsel, 0, thread) = sys_perf_event_open(attr, 213 196 all_tids[thread], -1, -1, 0); 214 - if (fd[0][counter][thread] < 0) { 197 + if (FD(evsel, 0, thread) < 0) { 215 198 if (errno == EPERM || errno == EACCES) 216 199 *perm_err = true; 217 - error(ERR_PERF_OPEN, counter, 218 - fd[0][counter][thread], 200 + error(ERR_PERF_OPEN, evsel->idx, 201 + FD(evsel, 0, thread), 219 202 strerror(errno)); 220 203 } else { 221 204 ++ncreated; ··· 229 212 /* 230 213 * Does the counter have nsecs as a unit? 231 214 */ 232 - static inline int nsec_counter(int counter) 215 + static inline int nsec_counter(struct perf_evsel *counter) 233 216 { 234 217 if (MATCH_EVENT(SOFTWARE, SW_CPU_CLOCK, counter) || 235 218 MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) ··· 242 225 * Read out the results of a single counter: 243 226 * aggregate counts across CPUs in system-wide mode 244 227 */ 245 - static void read_counter_aggr(int counter) 228 + static void read_counter_aggr(struct perf_evsel *counter) 246 229 { 230 + struct perf_stat *ps = counter->priv; 247 231 u64 count[3], single_count[3]; 248 232 int cpu; 249 233 size_t res, nv; ··· 256 238 nv = scale ? 3 : 1; 257 239 for (cpu = 0; cpu < nr_cpus; cpu++) { 258 240 for (thread = 0; thread < thread_num; thread++) { 259 - if (fd[cpu][counter][thread] < 0) 241 + if (FD(counter, cpu, thread) < 0) 260 242 continue; 261 243 262 - res = read(fd[cpu][counter][thread], 244 + res = read(FD(counter, cpu, thread), 263 245 single_count, nv * sizeof(u64)); 264 246 assert(res == nv * sizeof(u64)); 265 247 266 - close(fd[cpu][counter][thread]); 267 - fd[cpu][counter][thread] = -1; 248 + close(FD(counter, cpu, thread)); 249 + FD(counter, cpu, thread) = -1; 268 250 269 251 count[0] += single_count[0]; 270 252 if (scale) { ··· 277 259 scaled = 0; 278 260 if (scale) { 279 261 if (count[2] == 0) { 280 - event_scaled[counter] = -1; 262 + ps->scaled = -1; 281 263 count[0] = 0; 282 264 return; 283 265 } 284 266 285 267 if (count[2] < count[1]) { 286 - event_scaled[counter] = 1; 268 + ps->scaled = 1; 287 269 count[0] = (unsigned long long) 288 270 ((double)count[0] * count[1] / count[2] + 0.5); 289 271 } 290 272 } 291 273 292 274 for (i = 0; i < 3; i++) 293 - update_stats(&event_res_stats[counter][i], count[i]); 275 + update_stats(&ps->res_stats[i], count[i]); 294 276 295 277 if (verbose) { 296 278 fprintf(stderr, "%s: %Ld %Ld %Ld\n", event_name(counter), ··· 312 294 * Read out the results of a single counter: 313 295 * do not aggregate counts across CPUs in system-wide mode 314 296 */ 315 - static void read_counter(int counter) 297 + static void read_counter(struct perf_evsel *counter) 316 298 { 299 + struct cpu_counts *cpu_counts = counter->priv; 317 300 u64 count[3]; 318 301 int cpu; 319 302 size_t res, nv; ··· 325 306 326 307 for (cpu = 0; cpu < nr_cpus; cpu++) { 327 308 328 - if (fd[cpu][counter][0] < 0) 309 + if (FD(counter, cpu, 0) < 0) 329 310 continue; 330 311 331 - res = read(fd[cpu][counter][0], count, nv * sizeof(u64)); 312 + res = read(FD(counter, cpu, 0), count, nv * sizeof(u64)); 332 313 333 314 assert(res == nv * sizeof(u64)); 334 315 335 - close(fd[cpu][counter][0]); 336 - fd[cpu][counter][0] = -1; 316 + close(FD(counter, cpu, 0)); 317 + FD(counter, cpu, 0) = -1; 337 318 338 319 if (scale) { 339 320 if (count[2] == 0) { ··· 343 324 ((double)count[0] * count[1] / count[2] + 0.5); 344 325 } 345 326 } 346 - cpu_counts[cpu][counter].val = count[0]; /* scaled count */ 347 - cpu_counts[cpu][counter].ena = count[1]; 348 - cpu_counts[cpu][counter].run = count[2]; 327 + cpu_counts[cpu].val = count[0]; /* scaled count */ 328 + cpu_counts[cpu].ena = count[1]; 329 + cpu_counts[cpu].run = count[2]; 349 330 350 331 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) 351 332 update_stats(&runtime_nsecs_stats[cpu], count[0]); ··· 359 340 static int run_perf_stat(int argc __used, const char **argv) 360 341 { 361 342 unsigned long long t0, t1; 343 + struct perf_evsel *counter; 362 344 int status = 0; 363 - int counter, ncreated = 0; 345 + int ncreated = 0; 364 346 int child_ready_pipe[2], go_pipe[2]; 365 347 bool perm_err = false; 366 348 const bool forks = (argc > 0); ··· 421 401 close(child_ready_pipe[0]); 422 402 } 423 403 424 - for (counter = 0; counter < nr_counters; counter++) 404 + list_for_each_entry(counter, &evsel_list, node) 425 405 ncreated += create_perf_stat_counter(counter, &perm_err); 426 406 427 407 if (ncreated < nr_counters) { ··· 453 433 update_stats(&walltime_nsecs_stats, t1 - t0); 454 434 455 435 if (no_aggr) { 456 - for (counter = 0; counter < nr_counters; counter++) 436 + list_for_each_entry(counter, &evsel_list, node) 457 437 read_counter(counter); 458 438 } else { 459 - for (counter = 0; counter < nr_counters; counter++) 439 + list_for_each_entry(counter, &evsel_list, node) 460 440 read_counter_aggr(counter); 461 441 } 462 442 return WEXITSTATUS(status); 463 443 } 464 444 465 - static void print_noise(int counter, double avg) 445 + static void print_noise(struct perf_evsel *evsel, double avg) 466 446 { 447 + struct perf_stat *ps; 448 + 467 449 if (run_count == 1) 468 450 return; 469 451 452 + ps = evsel->priv; 470 453 fprintf(stderr, " ( +- %7.3f%% )", 471 - 100 * stddev_stats(&event_res_stats[counter][0]) / avg); 454 + 100 * stddev_stats(&ps->res_stats[0]) / avg); 472 455 } 473 456 474 - static void nsec_printout(int cpu, int counter, double avg) 457 + static void nsec_printout(int cpu, struct perf_evsel *counter, double avg) 475 458 { 476 459 double msecs = avg / 1e6; 477 460 char cpustr[16] = { '\0', }; ··· 496 473 } 497 474 } 498 475 499 - static void abs_printout(int cpu, int counter, double avg) 476 + static void abs_printout(int cpu, struct perf_evsel *counter, double avg) 500 477 { 501 478 double total, ratio = 0.0; 502 479 char cpustr[16] = { '\0', }; ··· 551 528 * Print out the results of a single counter: 552 529 * aggregated counts in system-wide mode 553 530 */ 554 - static void print_counter_aggr(int counter) 531 + static void print_counter_aggr(struct perf_evsel *counter) 555 532 { 556 - double avg = avg_stats(&event_res_stats[counter][0]); 557 - int scaled = event_scaled[counter]; 533 + struct perf_stat *ps = counter->priv; 534 + double avg = avg_stats(&ps->res_stats[0]); 535 + int scaled = ps->scaled; 558 536 559 537 if (scaled == -1) { 560 538 fprintf(stderr, "%*s%s%-24s\n", ··· 579 555 if (scaled) { 580 556 double avg_enabled, avg_running; 581 557 582 - avg_enabled = avg_stats(&event_res_stats[counter][1]); 583 - avg_running = avg_stats(&event_res_stats[counter][2]); 558 + avg_enabled = avg_stats(&ps->res_stats[1]); 559 + avg_running = avg_stats(&ps->res_stats[2]); 584 560 585 561 fprintf(stderr, " (scaled from %.2f%%)", 586 562 100 * avg_running / avg_enabled); ··· 593 569 * Print out the results of a single counter: 594 570 * does not use aggregated count in system-wide 595 571 */ 596 - static void print_counter(int counter) 572 + static void print_counter(struct perf_evsel *counter) 597 573 { 574 + struct perf_stat *ps = counter->priv; 598 575 u64 ena, run, val; 599 576 int cpu; 600 577 601 578 for (cpu = 0; cpu < nr_cpus; cpu++) { 602 - val = cpu_counts[cpu][counter].val; 603 - ena = cpu_counts[cpu][counter].ena; 604 - run = cpu_counts[cpu][counter].run; 579 + val = ps->cpu_counts[cpu].val; 580 + ena = ps->cpu_counts[cpu].ena; 581 + run = ps->cpu_counts[cpu].run; 605 582 if (run == 0 || ena == 0) { 606 583 fprintf(stderr, "CPU%*d%s%*s%s%-24s", 607 584 csv_output ? 0 : -4, ··· 634 609 635 610 static void print_stat(int argc, const char **argv) 636 611 { 637 - int i, counter; 612 + struct perf_evsel *counter; 613 + int i; 638 614 639 615 fflush(stdout); 640 616 ··· 658 632 } 659 633 660 634 if (no_aggr) { 661 - for (counter = 0; counter < nr_counters; counter++) 635 + list_for_each_entry(counter, &evsel_list, node) 662 636 print_counter(counter); 663 637 } else { 664 - for (counter = 0; counter < nr_counters; counter++) 638 + list_for_each_entry(counter, &evsel_list, node) 665 639 print_counter_aggr(counter); 666 640 } 667 641 ··· 746 720 747 721 int cmd_stat(int argc, const char **argv, const char *prefix __used) 748 722 { 749 - int status; 750 - int i,j; 723 + struct perf_evsel *pos; 724 + int status = -ENOMEM; 751 725 752 726 setlocale(LC_ALL, ""); 753 727 ··· 783 757 784 758 /* Set attrs and nr_counters if no event is selected and !null_run */ 785 759 if (!null_run && !nr_counters) { 786 - memcpy(attrs, default_attrs, sizeof(default_attrs)); 760 + size_t c; 761 + 787 762 nr_counters = ARRAY_SIZE(default_attrs); 763 + 764 + for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) { 765 + pos = perf_evsel__new(default_attrs[c].type, 766 + default_attrs[c].config, 767 + nr_counters); 768 + if (pos == NULL) 769 + goto out; 770 + list_add(&pos->node, &evsel_list); 771 + } 788 772 } 789 773 790 774 if (system_wide) ··· 822 786 thread_num = 1; 823 787 } 824 788 825 - for (i = 0; i < MAX_NR_CPUS; i++) { 826 - for (j = 0; j < MAX_COUNTERS; j++) { 827 - fd[i][j] = malloc(sizeof(int)*thread_num); 828 - if (!fd[i][j]) 829 - return -ENOMEM; 830 - } 789 + list_for_each_entry(pos, &evsel_list, node) { 790 + if (perf_evsel__alloc_stat_priv(pos, nr_cpus) < 0 || 791 + perf_evsel__alloc_fd(pos, nr_cpus, thread_num) < 0) 792 + goto out_free_fd; 831 793 } 832 794 833 795 /* ··· 848 814 849 815 if (status != -1) 850 816 print_stat(argc, argv); 851 - 817 + out_free_fd: 818 + list_for_each_entry(pos, &evsel_list, node) { 819 + perf_evsel__free_fd(pos); 820 + perf_evsel__free_stat_priv(pos); 821 + } 822 + out: 852 823 return status; 853 824 }
+104 -72
tools/perf/builtin-top.c
··· 21 21 #include "perf.h" 22 22 23 23 #include "util/color.h" 24 + #include "util/evsel.h" 24 25 #include "util/session.h" 25 26 #include "util/symbol.h" 26 27 #include "util/thread.h" ··· 30 29 #include "util/parse-options.h" 31 30 #include "util/parse-events.h" 32 31 #include "util/cpumap.h" 32 + #include "util/xyarray.h" 33 33 34 34 #include "util/debug.h" 35 35 ··· 57 55 #include <linux/unistd.h> 58 56 #include <linux/types.h> 59 57 60 - static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; 58 + #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 61 59 62 60 static bool system_wide = false; 63 61 ··· 102 100 struct sym_entry *sym_filter_entry_sched = NULL; 103 101 static int sym_pcnt_filter = 5; 104 102 static int sym_counter = 0; 103 + static struct perf_evsel *sym_evsel = NULL; 105 104 static int display_weighted = -1; 106 105 static const char *cpu_list; 107 106 ··· 356 353 return; 357 354 358 355 symbol = sym_entry__symbol(syme); 359 - printf("Showing %s for %s\n", event_name(sym_counter), symbol->name); 356 + printf("Showing %s for %s\n", event_name(sym_evsel), symbol->name); 360 357 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); 361 358 362 359 pthread_mutex_lock(&syme->src->lock); ··· 463 460 static void print_sym_table(void) 464 461 { 465 462 int printed = 0, j; 466 - int counter, snap = !display_weighted ? sym_counter : 0; 463 + struct perf_evsel *counter; 464 + int snap = !display_weighted ? sym_counter : 0; 467 465 float samples_per_sec = samples/delay_secs; 468 466 float ksamples_per_sec = kernel_samples/delay_secs; 469 467 float us_samples_per_sec = (us_samples)/delay_secs; ··· 536 532 } 537 533 538 534 if (nr_counters == 1 || !display_weighted) { 539 - printf("%Ld", (u64)attrs[0].sample_period); 535 + struct perf_evsel *first; 536 + first = list_entry(evsel_list.next, struct perf_evsel, node); 537 + printf("%Ld", first->attr.sample_period); 540 538 if (freq) 541 539 printf("Hz "); 542 540 else ··· 546 540 } 547 541 548 542 if (!display_weighted) 549 - printf("%s", event_name(sym_counter)); 550 - else for (counter = 0; counter < nr_counters; counter++) { 551 - if (counter) 543 + printf("%s", event_name(sym_evsel)); 544 + else list_for_each_entry(counter, &evsel_list, node) { 545 + if (counter->idx) 552 546 printf("/"); 553 547 554 548 printf("%s", event_name(counter)); ··· 745 739 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries); 746 740 747 741 if (nr_counters > 1) 748 - fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_counter)); 742 + fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_evsel)); 749 743 750 744 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); 751 745 ··· 832 826 break; 833 827 case 'E': 834 828 if (nr_counters > 1) { 835 - int i; 836 - 837 829 fprintf(stderr, "\nAvailable events:"); 838 - for (i = 0; i < nr_counters; i++) 839 - fprintf(stderr, "\n\t%d %s", i, event_name(i)); 830 + 831 + list_for_each_entry(sym_evsel, &evsel_list, node) 832 + fprintf(stderr, "\n\t%d %s", sym_evsel->idx, event_name(sym_evsel)); 840 833 841 834 prompt_integer(&sym_counter, "Enter details event counter"); 842 835 843 836 if (sym_counter >= nr_counters) { 844 - fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(0)); 837 + sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node); 845 838 sym_counter = 0; 839 + fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(sym_evsel)); 846 840 sleep(1); 841 + break; 847 842 } 843 + list_for_each_entry(sym_evsel, &evsel_list, node) 844 + if (sym_evsel->idx == sym_counter) 845 + break; 848 846 } else sym_counter = 0; 849 847 break; 850 848 case 'f': ··· 988 978 989 979 static void event__process_sample(const event_t *self, 990 980 struct sample_data *sample, 991 - struct perf_session *session, int counter) 981 + struct perf_session *session, 982 + struct perf_evsel *evsel) 992 983 { 993 984 u64 ip = self->ip.ip; 994 985 struct sym_entry *syme; ··· 1082 1071 1083 1072 syme = symbol__priv(al.sym); 1084 1073 if (!syme->skip) { 1085 - syme->count[counter]++; 1074 + syme->count[evsel->idx]++; 1086 1075 syme->origin = origin; 1087 - record_precise_ip(syme, counter, ip); 1076 + record_precise_ip(syme, evsel->idx, ip); 1088 1077 pthread_mutex_lock(&active_symbols_lock); 1089 1078 if (list_empty(&syme->node) || !syme->node.next) 1090 1079 __list_insert_active_sym(syme); ··· 1093 1082 } 1094 1083 1095 1084 struct mmap_data { 1096 - int counter; 1097 1085 void *base; 1098 1086 int mask; 1099 1087 unsigned int prev; 1100 1088 }; 1089 + 1090 + static int perf_evsel__alloc_mmap_per_thread(struct perf_evsel *evsel, 1091 + int ncpus, int nthreads) 1092 + { 1093 + evsel->priv = xyarray__new(ncpus, nthreads, sizeof(struct mmap_data)); 1094 + return evsel->priv != NULL ? 0 : -ENOMEM; 1095 + } 1096 + 1097 + static void perf_evsel__free_mmap(struct perf_evsel *evsel) 1098 + { 1099 + xyarray__delete(evsel->priv); 1100 + evsel->priv = NULL; 1101 + } 1101 1102 1102 1103 static unsigned int mmap_read_head(struct mmap_data *md) 1103 1104 { ··· 1123 1100 } 1124 1101 1125 1102 static void perf_session__mmap_read_counter(struct perf_session *self, 1126 - struct mmap_data *md) 1103 + struct perf_evsel *evsel, 1104 + int cpu, int thread_idx) 1127 1105 { 1106 + struct xyarray *mmap_array = evsel->priv; 1107 + struct mmap_data *md = xyarray__entry(mmap_array, cpu, thread_idx); 1128 1108 unsigned int head = mmap_read_head(md); 1129 1109 unsigned int old = md->prev; 1130 1110 unsigned char *data = md->base + page_size; ··· 1181 1155 1182 1156 event__parse_sample(event, self, &sample); 1183 1157 if (event->header.type == PERF_RECORD_SAMPLE) 1184 - event__process_sample(event, &sample, self, md->counter); 1158 + event__process_sample(event, &sample, self, evsel); 1185 1159 else 1186 1160 event__process(event, &sample, self); 1187 1161 old += size; ··· 1191 1165 } 1192 1166 1193 1167 static struct pollfd *event_array; 1194 - static struct mmap_data *mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; 1195 1168 1196 1169 static void perf_session__mmap_read(struct perf_session *self) 1197 1170 { 1198 - int i, counter, thread_index; 1171 + struct perf_evsel *counter; 1172 + int i, thread_index; 1199 1173 1200 1174 for (i = 0; i < nr_cpus; i++) { 1201 - for (counter = 0; counter < nr_counters; counter++) 1175 + list_for_each_entry(counter, &evsel_list, node) { 1202 1176 for (thread_index = 0; 1203 1177 thread_index < thread_num; 1204 1178 thread_index++) { 1205 1179 perf_session__mmap_read_counter(self, 1206 - &mmap_array[i][counter][thread_index]); 1180 + counter, i, thread_index); 1207 1181 } 1182 + } 1208 1183 } 1209 1184 } 1210 1185 1211 1186 int nr_poll; 1212 1187 int group_fd; 1213 1188 1214 - static void start_counter(int i, int counter) 1189 + static void start_counter(int i, struct perf_evsel *evsel) 1215 1190 { 1191 + struct xyarray *mmap_array = evsel->priv; 1192 + struct mmap_data *mm; 1216 1193 struct perf_event_attr *attr; 1217 1194 int cpu = -1; 1218 1195 int thread_index; ··· 1223 1194 if (target_tid == -1) 1224 1195 cpu = cpumap[i]; 1225 1196 1226 - attr = attrs + counter; 1197 + attr = &evsel->attr; 1227 1198 1228 1199 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 1229 1200 ··· 1238 1209 1239 1210 for (thread_index = 0; thread_index < thread_num; thread_index++) { 1240 1211 try_again: 1241 - fd[i][counter][thread_index] = sys_perf_event_open(attr, 1212 + FD(evsel, i, thread_index) = sys_perf_event_open(attr, 1242 1213 all_tids[thread_index], cpu, group_fd, 0); 1243 1214 1244 - if (fd[i][counter][thread_index] < 0) { 1215 + if (FD(evsel, i, thread_index) < 0) { 1245 1216 int err = errno; 1246 1217 1247 1218 if (err == EPERM || err == EACCES) ··· 1265 1236 } 1266 1237 printf("\n"); 1267 1238 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", 1268 - fd[i][counter][thread_index], strerror(err)); 1239 + FD(evsel, i, thread_index), strerror(err)); 1269 1240 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 1270 1241 exit(-1); 1271 1242 } 1272 - assert(fd[i][counter][thread_index] >= 0); 1273 - fcntl(fd[i][counter][thread_index], F_SETFL, O_NONBLOCK); 1243 + assert(FD(evsel, i, thread_index) >= 0); 1244 + fcntl(FD(evsel, i, thread_index), F_SETFL, O_NONBLOCK); 1274 1245 1275 1246 /* 1276 1247 * First counter acts as the group leader: 1277 1248 */ 1278 1249 if (group && group_fd == -1) 1279 - group_fd = fd[i][counter][thread_index]; 1250 + group_fd = FD(evsel, i, thread_index); 1280 1251 1281 - event_array[nr_poll].fd = fd[i][counter][thread_index]; 1252 + event_array[nr_poll].fd = FD(evsel, i, thread_index); 1282 1253 event_array[nr_poll].events = POLLIN; 1283 1254 nr_poll++; 1284 1255 1285 - mmap_array[i][counter][thread_index].counter = counter; 1286 - mmap_array[i][counter][thread_index].prev = 0; 1287 - mmap_array[i][counter][thread_index].mask = mmap_pages*page_size - 1; 1288 - mmap_array[i][counter][thread_index].base = mmap(NULL, (mmap_pages+1)*page_size, 1289 - PROT_READ, MAP_SHARED, fd[i][counter][thread_index], 0); 1290 - if (mmap_array[i][counter][thread_index].base == MAP_FAILED) 1256 + mm = xyarray__entry(mmap_array, i, thread_index); 1257 + mm->prev = 0; 1258 + mm->mask = mmap_pages*page_size - 1; 1259 + mm->base = mmap(NULL, (mmap_pages+1)*page_size, 1260 + PROT_READ, MAP_SHARED, FD(evsel, i, thread_index), 0); 1261 + if (mm->base == MAP_FAILED) 1291 1262 die("failed to mmap with %d (%s)\n", errno, strerror(errno)); 1292 1263 } 1293 1264 } ··· 1295 1266 static int __cmd_top(void) 1296 1267 { 1297 1268 pthread_t thread; 1298 - int i, counter; 1299 - int ret; 1269 + struct perf_evsel *counter; 1270 + int i, ret; 1300 1271 /* 1301 1272 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 1302 1273 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. ··· 1312 1283 1313 1284 for (i = 0; i < nr_cpus; i++) { 1314 1285 group_fd = -1; 1315 - for (counter = 0; counter < nr_counters; counter++) 1286 + list_for_each_entry(counter, &evsel_list, node) 1316 1287 start_counter(i, counter); 1317 1288 } 1318 1289 ··· 1401 1372 1402 1373 int cmd_top(int argc, const char **argv, const char *prefix __used) 1403 1374 { 1404 - int counter; 1405 - int i,j; 1375 + struct perf_evsel *pos; 1376 + int status = -ENOMEM; 1406 1377 1407 1378 page_size = sysconf(_SC_PAGE_SIZE); 1408 1379 ··· 1427 1398 thread_num = 1; 1428 1399 } 1429 1400 1430 - for (i = 0; i < MAX_NR_CPUS; i++) { 1431 - for (j = 0; j < MAX_COUNTERS; j++) { 1432 - fd[i][j] = malloc(sizeof(int)*thread_num); 1433 - mmap_array[i][j] = zalloc( 1434 - sizeof(struct mmap_data)*thread_num); 1435 - if (!fd[i][j] || !mmap_array[i][j]) 1436 - return -ENOMEM; 1437 - } 1438 - } 1439 1401 event_array = malloc( 1440 1402 sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num); 1441 1403 if (!event_array) ··· 1439 1419 cpu_list = NULL; 1440 1420 } 1441 1421 1442 - if (!nr_counters) 1443 - nr_counters = 1; 1444 - 1445 - symbol_conf.priv_size = (sizeof(struct sym_entry) + 1446 - (nr_counters + 1) * sizeof(unsigned long)); 1447 - 1448 - symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1449 - if (symbol__init() < 0) 1450 - return -1; 1422 + if (!nr_counters && perf_evsel_list__create_default() < 0) { 1423 + pr_err("Not enough memory for event selector list\n"); 1424 + return -ENOMEM; 1425 + } 1451 1426 1452 1427 if (delay_secs < 1) 1453 1428 delay_secs = 1; ··· 1459 1444 exit(EXIT_FAILURE); 1460 1445 } 1461 1446 1462 - /* 1463 - * Fill in the ones not specifically initialized via -c: 1464 - */ 1465 - for (counter = 0; counter < nr_counters; counter++) { 1466 - if (attrs[counter].sample_period) 1467 - continue; 1468 - 1469 - attrs[counter].sample_period = default_interval; 1470 - } 1471 - 1472 1447 if (target_tid != -1) 1473 1448 nr_cpus = 1; 1474 1449 else ··· 1467 1462 if (nr_cpus < 1) 1468 1463 usage_with_options(top_usage, options); 1469 1464 1465 + list_for_each_entry(pos, &evsel_list, node) { 1466 + if (perf_evsel__alloc_mmap_per_thread(pos, nr_cpus, thread_num) < 0 || 1467 + perf_evsel__alloc_fd(pos, nr_cpus, thread_num) < 0) 1468 + goto out_free_fd; 1469 + /* 1470 + * Fill in the ones not specifically initialized via -c: 1471 + */ 1472 + if (pos->attr.sample_period) 1473 + continue; 1474 + 1475 + pos->attr.sample_period = default_interval; 1476 + } 1477 + 1478 + symbol_conf.priv_size = (sizeof(struct sym_entry) + 1479 + (nr_counters + 1) * sizeof(unsigned long)); 1480 + 1481 + symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1482 + if (symbol__init() < 0) 1483 + return -1; 1484 + 1470 1485 get_term_dimensions(&winsize); 1471 1486 if (print_entries == 0) { 1472 1487 update_print_entries(&winsize); 1473 1488 signal(SIGWINCH, sig_winch_handler); 1474 1489 } 1475 1490 1476 - return __cmd_top(); 1491 + status = __cmd_top(); 1492 + out_free_fd: 1493 + list_for_each_entry(pos, &evsel_list, node) { 1494 + perf_evsel__free_fd(pos); 1495 + perf_evsel__free_mmap(pos); 1496 + } 1497 + 1498 + return status; 1477 1499 }
+35
tools/perf/util/evsel.c
··· 1 + #include "evsel.h" 2 + #include "util.h" 3 + 4 + struct perf_evsel *perf_evsel__new(u32 type, u64 config, int idx) 5 + { 6 + struct perf_evsel *evsel = zalloc(sizeof(*evsel)); 7 + 8 + if (evsel != NULL) { 9 + evsel->idx = idx; 10 + evsel->attr.type = type; 11 + evsel->attr.config = config; 12 + INIT_LIST_HEAD(&evsel->node); 13 + } 14 + 15 + return evsel; 16 + } 17 + 18 + int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 19 + { 20 + evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); 21 + return evsel->fd != NULL ? 0 : -ENOMEM; 22 + } 23 + 24 + void perf_evsel__free_fd(struct perf_evsel *evsel) 25 + { 26 + xyarray__delete(evsel->fd); 27 + evsel->fd = NULL; 28 + } 29 + 30 + void perf_evsel__delete(struct perf_evsel *evsel) 31 + { 32 + assert(list_empty(&evsel->node)); 33 + xyarray__delete(evsel->fd); 34 + free(evsel); 35 + }
+24
tools/perf/util/evsel.h
··· 1 + #ifndef __PERF_EVSEL_H 2 + #define __PERF_EVSEL_H 1 3 + 4 + #include <linux/list.h> 5 + #include <linux/perf_event.h> 6 + #include "types.h" 7 + #include "xyarray.h" 8 + 9 + struct perf_evsel { 10 + struct list_head node; 11 + struct perf_event_attr attr; 12 + char *filter; 13 + struct xyarray *fd; 14 + int idx; 15 + void *priv; 16 + }; 17 + 18 + struct perf_evsel *perf_evsel__new(u32 type, u64 config, int idx); 19 + void perf_evsel__delete(struct perf_evsel *evsel); 20 + 21 + int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 22 + void perf_evsel__free_fd(struct perf_evsel *evsel); 23 + 24 + #endif /* __PERF_EVSEL_H */
+4 -5
tools/perf/util/header.c
··· 461 461 462 462 /* Write trace info */ 463 463 trace_sec->offset = lseek(fd, 0, SEEK_CUR); 464 - read_tracing_data(fd, attrs, nr_counters); 464 + read_tracing_data(fd, &evsel_list); 465 465 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; 466 466 } 467 467 ··· 1131 1131 return 0; 1132 1132 } 1133 1133 1134 - int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs, 1135 - int nb_events, 1134 + int event__synthesize_tracing_data(int fd, struct list_head *pattrs, 1136 1135 event__handler_t process, 1137 1136 struct perf_session *session __unused) 1138 1137 { ··· 1142 1143 memset(&ev, 0, sizeof(ev)); 1143 1144 1144 1145 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; 1145 - size = read_tracing_data_size(fd, pattrs, nb_events); 1146 + size = read_tracing_data_size(fd, pattrs); 1146 1147 if (size <= 0) 1147 1148 return size; 1148 1149 aligned_size = ALIGN(size, sizeof(u64)); ··· 1152 1153 1153 1154 process(&ev, NULL, session); 1154 1155 1155 - err = read_tracing_data(fd, pattrs, nb_events); 1156 + err = read_tracing_data(fd, pattrs); 1156 1157 write_padded(fd, NULL, 0, padding); 1157 1158 1158 1159 return aligned_size;
+1 -2
tools/perf/util/header.h
··· 113 113 int event__process_event_type(event_t *self, 114 114 struct perf_session *session); 115 115 116 - int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs, 117 - int nb_events, 116 + int event__synthesize_tracing_data(int fd, struct list_head *pattrs, 118 117 event__handler_t process, 119 118 struct perf_session *session); 120 119 int event__process_tracing_data(event_t *self,
+31 -16
tools/perf/util/parse-events.c
··· 1 1 #include "../../../include/linux/hw_breakpoint.h" 2 2 #include "util.h" 3 3 #include "../perf.h" 4 + #include "evsel.h" 4 5 #include "parse-options.h" 5 6 #include "parse-events.h" 6 7 #include "exec_cmd.h" ··· 13 12 14 13 int nr_counters; 15 14 16 - struct perf_event_attr attrs[MAX_COUNTERS]; 17 - char *filters[MAX_COUNTERS]; 15 + LIST_HEAD(evsel_list); 18 16 19 17 struct event_symbol { 20 18 u8 type; ··· 266 266 return name; 267 267 } 268 268 269 - const char *event_name(int counter) 269 + const char *event_name(struct perf_evsel *evsel) 270 270 { 271 - u64 config = attrs[counter].config; 272 - int type = attrs[counter].type; 271 + u64 config = evsel->attr.config; 272 + int type = evsel->attr.type; 273 273 274 274 return __event_name(type, config); 275 275 } ··· 814 814 return -1; 815 815 816 816 for (;;) { 817 - if (nr_counters == MAX_COUNTERS) 818 - return -1; 819 - 820 817 memset(&attr, 0, sizeof(attr)); 821 818 ret = parse_event_symbols(&str, &attr); 822 819 if (ret == EVT_FAILED) ··· 823 826 return -1; 824 827 825 828 if (ret != EVT_HANDLED_ALL) { 826 - attrs[nr_counters] = attr; 827 - nr_counters++; 829 + struct perf_evsel *evsel; 830 + evsel = perf_evsel__new(attr.type, attr.config, 831 + nr_counters); 832 + if (evsel == NULL) 833 + return -1; 834 + list_add_tail(&evsel->node, &evsel_list); 835 + ++nr_counters; 828 836 } 829 837 830 838 if (*str == 0) ··· 846 844 int parse_filter(const struct option *opt __used, const char *str, 847 845 int unset __used) 848 846 { 849 - int i = nr_counters - 1; 850 - int len = strlen(str); 847 + struct perf_evsel *last = NULL; 851 848 852 - if (i < 0 || attrs[i].type != PERF_TYPE_TRACEPOINT) { 849 + if (!list_empty(&evsel_list)) 850 + last = list_entry(evsel_list.prev, struct perf_evsel, node); 851 + 852 + if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) { 853 853 fprintf(stderr, 854 854 "-F option should follow a -e tracepoint option\n"); 855 855 return -1; 856 856 } 857 857 858 - filters[i] = malloc(len + 1); 859 - if (!filters[i]) { 858 + last->filter = strdup(str); 859 + if (last->filter == NULL) { 860 860 fprintf(stderr, "not enough memory to hold filter string\n"); 861 861 return -1; 862 862 } 863 - strcpy(filters[i], str); 864 863 865 864 return 0; 866 865 } ··· 969 966 print_tracepoint_events(); 970 967 971 968 exit(129); 969 + } 970 + 971 + int perf_evsel_list__create_default(void) 972 + { 973 + struct perf_evsel *evsel = perf_evsel__new(PERF_TYPE_HARDWARE, 974 + PERF_COUNT_HW_CPU_CYCLES, 0); 975 + if (evsel == NULL) 976 + return -ENOMEM; 977 + 978 + list_add(&evsel->node, &evsel_list); 979 + ++nr_counters; 980 + return 0; 972 981 }
+11 -6
tools/perf/util/parse-events.h
··· 4 4 * Parse symbolic events/counts passed in as options: 5 5 */ 6 6 7 + #include <linux/perf_event.h> 8 + 9 + struct list_head; 10 + struct perf_evsel; 11 + 12 + extern struct list_head evsel_list; 13 + 14 + int perf_evsel_list__create_default(void); 15 + 7 16 struct option; 8 17 9 18 struct tracepoint_path { ··· 22 13 }; 23 14 24 15 extern struct tracepoint_path *tracepoint_id_to_path(u64 config); 25 - extern bool have_tracepoints(struct perf_event_attr *pattrs, int nb_events); 16 + extern bool have_tracepoints(struct list_head *evsel_list); 26 17 27 18 extern int nr_counters; 28 19 29 - extern struct perf_event_attr attrs[MAX_COUNTERS]; 30 - extern char *filters[MAX_COUNTERS]; 31 - 32 - extern const char *event_name(int ctr); 20 + const char *event_name(struct perf_evsel *event); 33 21 extern const char *__event_name(int type, u64 config); 34 22 35 23 extern int parse_events(const struct option *opt, const char *str, int unset); ··· 38 32 39 33 extern char debugfs_path[]; 40 34 extern int valid_debugfs_mount(const char *debugfs); 41 - 42 35 43 36 #endif /* __PERF_PARSE_EVENTS_H */
+16 -14
tools/perf/util/trace-event-info.c
··· 34 34 #include <ctype.h> 35 35 #include <errno.h> 36 36 #include <stdbool.h> 37 + #include <linux/list.h> 37 38 #include <linux/kernel.h> 38 39 39 40 #include "../perf.h" 40 41 #include "trace-event.h" 41 42 #include "debugfs.h" 43 + #include "evsel.h" 42 44 43 45 #define VERSION "0.5" 44 46 ··· 471 469 } 472 470 473 471 static struct tracepoint_path * 474 - get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events) 472 + get_tracepoints_path(struct list_head *pattrs) 475 473 { 476 474 struct tracepoint_path path, *ppath = &path; 477 - int i, nr_tracepoints = 0; 475 + struct perf_evsel *pos; 476 + int nr_tracepoints = 0; 478 477 479 - for (i = 0; i < nb_events; i++) { 480 - if (pattrs[i].type != PERF_TYPE_TRACEPOINT) 478 + list_for_each_entry(pos, pattrs, node) { 479 + if (pos->attr.type != PERF_TYPE_TRACEPOINT) 481 480 continue; 482 481 ++nr_tracepoints; 483 - ppath->next = tracepoint_id_to_path(pattrs[i].config); 482 + ppath->next = tracepoint_id_to_path(pos->attr.config); 484 483 if (!ppath->next) 485 484 die("%s\n", "No memory to alloc tracepoints list"); 486 485 ppath = ppath->next; ··· 490 487 return nr_tracepoints > 0 ? path.next : NULL; 491 488 } 492 489 493 - bool have_tracepoints(struct perf_event_attr *pattrs, int nb_events) 490 + bool have_tracepoints(struct list_head *pattrs) 494 491 { 495 - int i; 492 + struct perf_evsel *pos; 496 493 497 - for (i = 0; i < nb_events; i++) 498 - if (pattrs[i].type == PERF_TYPE_TRACEPOINT) 494 + list_for_each_entry(pos, pattrs, node) 495 + if (pos->attr.type == PERF_TYPE_TRACEPOINT) 499 496 return true; 500 497 501 498 return false; 502 499 } 503 500 504 - int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events) 501 + int read_tracing_data(int fd, struct list_head *pattrs) 505 502 { 506 503 char buf[BUFSIZ]; 507 - struct tracepoint_path *tps = get_tracepoints_path(pattrs, nb_events); 504 + struct tracepoint_path *tps = get_tracepoints_path(pattrs); 508 505 509 506 /* 510 507 * What? No tracepoints? No sense writing anything here, bail out. ··· 548 545 return 0; 549 546 } 550 547 551 - ssize_t read_tracing_data_size(int fd, struct perf_event_attr *pattrs, 552 - int nb_events) 548 + ssize_t read_tracing_data_size(int fd, struct list_head *pattrs) 553 549 { 554 550 ssize_t size; 555 551 int err = 0; 556 552 557 553 calc_data_size = 1; 558 - err = read_tracing_data(fd, pattrs, nb_events); 554 + err = read_tracing_data(fd, pattrs); 559 555 size = calc_data_size - 1; 560 556 calc_data_size = 0; 561 557
+2 -3
tools/perf/util/trace-event.h
··· 262 262 void *raw_field_ptr(struct event *event, const char *name, void *data); 263 263 unsigned long long eval_flag(const char *flag); 264 264 265 - int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events); 266 - ssize_t read_tracing_data_size(int fd, struct perf_event_attr *pattrs, 267 - int nb_events); 265 + int read_tracing_data(int fd, struct list_head *pattrs); 266 + ssize_t read_tracing_data_size(int fd, struct list_head *pattrs); 268 267 269 268 /* taken from kernel/trace/trace.h */ 270 269 enum trace_flag_type {
+20
tools/perf/util/xyarray.c
··· 1 + #include "xyarray.h" 2 + #include "util.h" 3 + 4 + struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size) 5 + { 6 + size_t row_size = ylen * entry_size; 7 + struct xyarray *xy = zalloc(sizeof(*xy) + xlen * row_size); 8 + 9 + if (xy != NULL) { 10 + xy->entry_size = entry_size; 11 + xy->row_size = row_size; 12 + } 13 + 14 + return xy; 15 + } 16 + 17 + void xyarray__delete(struct xyarray *xy) 18 + { 19 + free(xy); 20 + }
+20
tools/perf/util/xyarray.h
··· 1 + #ifndef _PERF_XYARRAY_H_ 2 + #define _PERF_XYARRAY_H_ 1 3 + 4 + #include <sys/types.h> 5 + 6 + struct xyarray { 7 + size_t row_size; 8 + size_t entry_size; 9 + char contents[]; 10 + }; 11 + 12 + struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size); 13 + void xyarray__delete(struct xyarray *xy); 14 + 15 + static inline void *xyarray__entry(struct xyarray *xy, int x, int y) 16 + { 17 + return &xy->contents[x * xy->row_size + y * xy->entry_size]; 18 + } 19 + 20 + #endif /* _PERF_XYARRAY_H_ */