diff options
author | Ingo Molnar <mingo@kernel.org> | 2014-07-28 04:09:03 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-07-28 04:09:03 -0400 |
commit | 068f1d3f45546f4bb24e9be67231db1be296f0c8 (patch) | |
tree | edd13e6585cc2dbd301760193fd854d653032e34 /tools | |
parent | f4be073db878d0e79f74bc36f1642847781791a0 (diff) | |
parent | dcabb507fd3a2b19aed6b4068e2a954f5fd8de45 (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
Infrastructure changes:
o More prep work to support Intel PT: (Adrian Hunter)
- Polishing 'script' BTS output
- 'inject' can specify --kallsym
- VDSO is per machine, not a global var
- Expose data addr lookup functions previously private to 'script'
- Large mmap fixes in events processing
o Fix build on gcc 4.4.7 (Arnaldo Carvalho de Melo)
o Event ordering fixes (Jiri Olsa)
o Include standard stringify macros in power pc code (Sukadev Bhattiprolu)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
29 files changed, 470 insertions, 115 deletions
diff --git a/tools/perf/Documentation/perf-inject.txt b/tools/perf/Documentation/perf-inject.txt index a00a34276c54..dc7442cf3d7f 100644 --- a/tools/perf/Documentation/perf-inject.txt +++ b/tools/perf/Documentation/perf-inject.txt | |||
@@ -41,6 +41,9 @@ OPTIONS | |||
41 | tasks slept. sched_switch contains a callchain where a task slept and | 41 | tasks slept. sched_switch contains a callchain where a task slept and |
42 | sched_stat contains a timeslice how long a task slept. | 42 | sched_stat contains a timeslice how long a task slept. |
43 | 43 | ||
44 | --kallsyms=<file>:: | ||
45 | kallsyms pathname | ||
46 | |||
44 | SEE ALSO | 47 | SEE ALSO |
45 | -------- | 48 | -------- |
46 | linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1] | 49 | linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1] |
diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c index 2f7073d107fd..6c1b8a75db09 100644 --- a/tools/perf/arch/powerpc/util/header.c +++ b/tools/perf/arch/powerpc/util/header.c | |||
@@ -5,9 +5,7 @@ | |||
5 | #include <string.h> | 5 | #include <string.h> |
6 | 6 | ||
7 | #include "../../util/header.h" | 7 | #include "../../util/header.h" |
8 | 8 | #include "../../util/util.h" | |
9 | #define __stringify_1(x) #x | ||
10 | #define __stringify(x) __stringify_1(x) | ||
11 | 9 | ||
12 | #define mfspr(rn) ({unsigned long rval; \ | 10 | #define mfspr(rn) ({unsigned long rval; \ |
13 | asm volatile("mfspr %0," __stringify(rn) \ | 11 | asm volatile("mfspr %0," __stringify(rn) \ |
diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c index 3655f24c3170..fd2868490d00 100644 --- a/tools/perf/arch/x86/util/tsc.c +++ b/tools/perf/arch/x86/util/tsc.c | |||
@@ -37,3 +37,12 @@ int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, | |||
37 | 37 | ||
38 | return 0; | 38 | return 0; |
39 | } | 39 | } |
40 | |||
41 | u64 rdtsc(void) | ||
42 | { | ||
43 | unsigned int low, high; | ||
44 | |||
45 | asm volatile("rdtsc" : "=a" (low), "=d" (high)); | ||
46 | |||
47 | return low | ((u64)high) << 32; | ||
48 | } | ||
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index cf6a605a13e8..9a02807387d6 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c | |||
@@ -439,6 +439,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) | |||
439 | "where and how long tasks slept"), | 439 | "where and how long tasks slept"), |
440 | OPT_INCR('v', "verbose", &verbose, | 440 | OPT_INCR('v', "verbose", &verbose, |
441 | "be more verbose (show build ids, etc)"), | 441 | "be more verbose (show build ids, etc)"), |
442 | OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file", | ||
443 | "kallsyms pathname"), | ||
442 | OPT_END() | 444 | OPT_END() |
443 | }; | 445 | }; |
444 | const char * const inject_usage[] = { | 446 | const char * const inject_usage[] = { |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 378b85b731a7..4869050e7194 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -238,6 +238,7 @@ static struct perf_event_header finished_round_event = { | |||
238 | 238 | ||
239 | static int record__mmap_read_all(struct record *rec) | 239 | static int record__mmap_read_all(struct record *rec) |
240 | { | 240 | { |
241 | u64 bytes_written = rec->bytes_written; | ||
241 | int i; | 242 | int i; |
242 | int rc = 0; | 243 | int rc = 0; |
243 | 244 | ||
@@ -250,7 +251,11 @@ static int record__mmap_read_all(struct record *rec) | |||
250 | } | 251 | } |
251 | } | 252 | } |
252 | 253 | ||
253 | if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) | 254 | /* |
255 | * Mark the round finished in case we wrote | ||
256 | * at least one event. | ||
257 | */ | ||
258 | if (bytes_written != rec->bytes_written) | ||
254 | rc = record__write(rec, &finished_round_event, sizeof(finished_round_event)); | 259 | rc = record__write(rec, &finished_round_event, sizeof(finished_round_event)); |
255 | 260 | ||
256 | out: | 261 | out: |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 9e9c91f5b7fa..f57035b89c15 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -358,27 +358,6 @@ static void print_sample_start(struct perf_sample *sample, | |||
358 | } | 358 | } |
359 | } | 359 | } |
360 | 360 | ||
361 | static bool is_bts_event(struct perf_event_attr *attr) | ||
362 | { | ||
363 | return ((attr->type == PERF_TYPE_HARDWARE) && | ||
364 | (attr->config & PERF_COUNT_HW_BRANCH_INSTRUCTIONS) && | ||
365 | (attr->sample_period == 1)); | ||
366 | } | ||
367 | |||
368 | static bool sample_addr_correlates_sym(struct perf_event_attr *attr) | ||
369 | { | ||
370 | if ((attr->type == PERF_TYPE_SOFTWARE) && | ||
371 | ((attr->config == PERF_COUNT_SW_PAGE_FAULTS) || | ||
372 | (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN) || | ||
373 | (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ))) | ||
374 | return true; | ||
375 | |||
376 | if (is_bts_event(attr)) | ||
377 | return true; | ||
378 | |||
379 | return false; | ||
380 | } | ||
381 | |||
382 | static void print_sample_addr(union perf_event *event, | 361 | static void print_sample_addr(union perf_event *event, |
383 | struct perf_sample *sample, | 362 | struct perf_sample *sample, |
384 | struct machine *machine, | 363 | struct machine *machine, |
@@ -386,24 +365,13 @@ static void print_sample_addr(union perf_event *event, | |||
386 | struct perf_event_attr *attr) | 365 | struct perf_event_attr *attr) |
387 | { | 366 | { |
388 | struct addr_location al; | 367 | struct addr_location al; |
389 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | ||
390 | 368 | ||
391 | printf("%16" PRIx64, sample->addr); | 369 | printf("%16" PRIx64, sample->addr); |
392 | 370 | ||
393 | if (!sample_addr_correlates_sym(attr)) | 371 | if (!sample_addr_correlates_sym(attr)) |
394 | return; | 372 | return; |
395 | 373 | ||
396 | thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, | 374 | perf_event__preprocess_sample_addr(event, sample, machine, thread, &al); |
397 | sample->addr, &al); | ||
398 | if (!al.map) | ||
399 | thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE, | ||
400 | sample->addr, &al); | ||
401 | |||
402 | al.cpu = sample->cpu; | ||
403 | al.sym = NULL; | ||
404 | |||
405 | if (al.map) | ||
406 | al.sym = map__find_symbol(al.map, al.addr, NULL); | ||
407 | 375 | ||
408 | if (PRINT_FIELD(SYM)) { | 376 | if (PRINT_FIELD(SYM)) { |
409 | printf(" "); | 377 | printf(" "); |
@@ -427,25 +395,35 @@ static void print_sample_bts(union perf_event *event, | |||
427 | struct addr_location *al) | 395 | struct addr_location *al) |
428 | { | 396 | { |
429 | struct perf_event_attr *attr = &evsel->attr; | 397 | struct perf_event_attr *attr = &evsel->attr; |
398 | bool print_srcline_last = false; | ||
430 | 399 | ||
431 | /* print branch_from information */ | 400 | /* print branch_from information */ |
432 | if (PRINT_FIELD(IP)) { | 401 | if (PRINT_FIELD(IP)) { |
433 | if (!symbol_conf.use_callchain) | 402 | unsigned int print_opts = output[attr->type].print_ip_opts; |
434 | printf(" "); | 403 | |
435 | else | 404 | if (symbol_conf.use_callchain && sample->callchain) { |
436 | printf("\n"); | 405 | printf("\n"); |
437 | perf_evsel__print_ip(evsel, sample, al, | 406 | } else { |
438 | output[attr->type].print_ip_opts, | 407 | printf(" "); |
408 | if (print_opts & PRINT_IP_OPT_SRCLINE) { | ||
409 | print_srcline_last = true; | ||
410 | print_opts &= ~PRINT_IP_OPT_SRCLINE; | ||
411 | } | ||
412 | } | ||
413 | perf_evsel__print_ip(evsel, sample, al, print_opts, | ||
439 | PERF_MAX_STACK_DEPTH); | 414 | PERF_MAX_STACK_DEPTH); |
440 | } | 415 | } |
441 | 416 | ||
442 | printf(" => "); | ||
443 | |||
444 | /* print branch_to information */ | 417 | /* print branch_to information */ |
445 | if (PRINT_FIELD(ADDR) || | 418 | if (PRINT_FIELD(ADDR) || |
446 | ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && | 419 | ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && |
447 | !output[attr->type].user_set)) | 420 | !output[attr->type].user_set)) { |
421 | printf(" => "); | ||
448 | print_sample_addr(event, sample, al->machine, thread, attr); | 422 | print_sample_addr(event, sample, al->machine, thread, attr); |
423 | } | ||
424 | |||
425 | if (print_srcline_last) | ||
426 | map__fprintf_srcline(al->map, al->addr, "\n ", stdout); | ||
449 | 427 | ||
450 | printf("\n"); | 428 | printf("\n"); |
451 | } | 429 | } |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index c4a5a7d7b2cf..a6c375224f46 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -1994,10 +1994,10 @@ static int perf_evlist__add_pgfault(struct perf_evlist *evlist, | |||
1994 | struct perf_event_attr attr = { | 1994 | struct perf_event_attr attr = { |
1995 | .type = PERF_TYPE_SOFTWARE, | 1995 | .type = PERF_TYPE_SOFTWARE, |
1996 | .mmap_data = 1, | 1996 | .mmap_data = 1, |
1997 | .sample_period = 1, | ||
1998 | }; | 1997 | }; |
1999 | 1998 | ||
2000 | attr.config = config; | 1999 | attr.config = config; |
2000 | attr.sample_period = 1; | ||
2001 | 2001 | ||
2002 | event_attr_init(&attr); | 2002 | event_attr_init(&attr); |
2003 | 2003 | ||
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c index 0372f6edca20..f238442b238a 100644 --- a/tools/perf/tests/perf-time-to-tsc.c +++ b/tools/perf/tests/perf-time-to-tsc.c | |||
@@ -25,15 +25,6 @@ | |||
25 | } \ | 25 | } \ |
26 | } | 26 | } |
27 | 27 | ||
28 | static u64 rdtsc(void) | ||
29 | { | ||
30 | unsigned int low, high; | ||
31 | |||
32 | asm volatile("rdtsc" : "=a" (low), "=d" (high)); | ||
33 | |||
34 | return low | ((u64)high) << 32; | ||
35 | } | ||
36 | |||
37 | /** | 28 | /** |
38 | * test__perf_time_to_tsc - test converting perf time to TSC. | 29 | * test__perf_time_to_tsc - test converting perf time to TSC. |
39 | * | 30 | * |
diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c index c5d05ec17220..6a37be53a5d2 100644 --- a/tools/perf/util/cloexec.c +++ b/tools/perf/util/cloexec.c | |||
@@ -1,3 +1,4 @@ | |||
1 | #include <sched.h> | ||
1 | #include "util.h" | 2 | #include "util.h" |
2 | #include "../perf.h" | 3 | #include "../perf.h" |
3 | #include "cloexec.h" | 4 | #include "cloexec.h" |
@@ -14,9 +15,13 @@ static int perf_flag_probe(void) | |||
14 | }; | 15 | }; |
15 | int fd; | 16 | int fd; |
16 | int err; | 17 | int err; |
18 | int cpu = sched_getcpu(); | ||
19 | |||
20 | if (cpu < 0) | ||
21 | cpu = 0; | ||
17 | 22 | ||
18 | /* check cloexec flag */ | 23 | /* check cloexec flag */ |
19 | fd = sys_perf_event_open(&attr, 0, -1, -1, | 24 | fd = sys_perf_event_open(&attr, -1, cpu, -1, |
20 | PERF_FLAG_FD_CLOEXEC); | 25 | PERF_FLAG_FD_CLOEXEC); |
21 | err = errno; | 26 | err = errno; |
22 | 27 | ||
@@ -30,7 +35,7 @@ static int perf_flag_probe(void) | |||
30 | err, strerror(err)); | 35 | err, strerror(err)); |
31 | 36 | ||
32 | /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ | 37 | /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ |
33 | fd = sys_perf_event_open(&attr, 0, -1, -1, 0); | 38 | fd = sys_perf_event_open(&attr, -1, cpu, -1, 0); |
34 | err = errno; | 39 | err = errno; |
35 | 40 | ||
36 | if (WARN_ONCE(fd < 0, | 41 | if (WARN_ONCE(fd < 0, |
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index fc006fed8877..90d02c661dd4 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c | |||
@@ -216,7 +216,7 @@ static int open_dso(struct dso *dso, struct machine *machine) | |||
216 | { | 216 | { |
217 | int fd = __open_dso(dso, machine); | 217 | int fd = __open_dso(dso, machine); |
218 | 218 | ||
219 | if (fd > 0) { | 219 | if (fd >= 0) { |
220 | dso__list_add(dso); | 220 | dso__list_add(dso); |
221 | /* | 221 | /* |
222 | * Check if we crossed the allowed number | 222 | * Check if we crossed the allowed number |
@@ -331,26 +331,44 @@ int dso__data_fd(struct dso *dso, struct machine *machine) | |||
331 | }; | 331 | }; |
332 | int i = 0; | 332 | int i = 0; |
333 | 333 | ||
334 | if (dso->data.status == DSO_DATA_STATUS_ERROR) | ||
335 | return -1; | ||
336 | |||
334 | if (dso->data.fd >= 0) | 337 | if (dso->data.fd >= 0) |
335 | return dso->data.fd; | 338 | goto out; |
336 | 339 | ||
337 | if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) { | 340 | if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) { |
338 | dso->data.fd = open_dso(dso, machine); | 341 | dso->data.fd = open_dso(dso, machine); |
339 | return dso->data.fd; | 342 | goto out; |
340 | } | 343 | } |
341 | 344 | ||
342 | do { | 345 | do { |
343 | int fd; | ||
344 | |||
345 | dso->binary_type = binary_type_data[i++]; | 346 | dso->binary_type = binary_type_data[i++]; |
346 | 347 | ||
347 | fd = open_dso(dso, machine); | 348 | dso->data.fd = open_dso(dso, machine); |
348 | if (fd >= 0) | 349 | if (dso->data.fd >= 0) |
349 | return dso->data.fd = fd; | 350 | goto out; |
350 | 351 | ||
351 | } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND); | 352 | } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND); |
353 | out: | ||
354 | if (dso->data.fd >= 0) | ||
355 | dso->data.status = DSO_DATA_STATUS_OK; | ||
356 | else | ||
357 | dso->data.status = DSO_DATA_STATUS_ERROR; | ||
352 | 358 | ||
353 | return -EINVAL; | 359 | return dso->data.fd; |
360 | } | ||
361 | |||
362 | bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by) | ||
363 | { | ||
364 | u32 flag = 1 << by; | ||
365 | |||
366 | if (dso->data.status_seen & flag) | ||
367 | return true; | ||
368 | |||
369 | dso->data.status_seen |= flag; | ||
370 | |||
371 | return false; | ||
354 | } | 372 | } |
355 | 373 | ||
356 | static void | 374 | static void |
@@ -526,6 +544,28 @@ static int data_file_size(struct dso *dso) | |||
526 | return 0; | 544 | return 0; |
527 | } | 545 | } |
528 | 546 | ||
547 | /** | ||
548 | * dso__data_size - Return dso data size | ||
549 | * @dso: dso object | ||
550 | * @machine: machine object | ||
551 | * | ||
552 | * Return: dso data size | ||
553 | */ | ||
554 | off_t dso__data_size(struct dso *dso, struct machine *machine) | ||
555 | { | ||
556 | int fd; | ||
557 | |||
558 | fd = dso__data_fd(dso, machine); | ||
559 | if (fd < 0) | ||
560 | return fd; | ||
561 | |||
562 | if (data_file_size(dso)) | ||
563 | return -1; | ||
564 | |||
565 | /* For now just estimate dso data size is close to file size */ | ||
566 | return dso->data.file_size; | ||
567 | } | ||
568 | |||
529 | static ssize_t data_read_offset(struct dso *dso, u64 offset, | 569 | static ssize_t data_read_offset(struct dso *dso, u64 offset, |
530 | u8 *data, ssize_t size) | 570 | u8 *data, ssize_t size) |
531 | { | 571 | { |
@@ -701,6 +741,7 @@ struct dso *dso__new(const char *name) | |||
701 | dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; | 741 | dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; |
702 | dso->data.cache = RB_ROOT; | 742 | dso->data.cache = RB_ROOT; |
703 | dso->data.fd = -1; | 743 | dso->data.fd = -1; |
744 | dso->data.status = DSO_DATA_STATUS_UNKNOWN; | ||
704 | dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; | 745 | dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; |
705 | dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND; | 746 | dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND; |
706 | dso->is_64_bit = (sizeof(void *) == 8); | 747 | dso->is_64_bit = (sizeof(void *) == 8); |
@@ -899,3 +940,14 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp) | |||
899 | 940 | ||
900 | return ret; | 941 | return ret; |
901 | } | 942 | } |
943 | |||
944 | enum dso_type dso__type(struct dso *dso, struct machine *machine) | ||
945 | { | ||
946 | int fd; | ||
947 | |||
948 | fd = dso__data_fd(dso, machine); | ||
949 | if (fd < 0) | ||
950 | return DSO__TYPE_UNKNOWN; | ||
951 | |||
952 | return dso__type_fd(fd); | ||
953 | } | ||
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index c239e86541a3..5e463c0964d4 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/rbtree.h> | 5 | #include <linux/rbtree.h> |
6 | #include <stdbool.h> | 6 | #include <stdbool.h> |
7 | #include <linux/types.h> | 7 | #include <linux/types.h> |
8 | #include <linux/bitops.h> | ||
8 | #include "map.h" | 9 | #include "map.h" |
9 | #include "build-id.h" | 10 | #include "build-id.h" |
10 | 11 | ||
@@ -40,6 +41,23 @@ enum dso_swap_type { | |||
40 | DSO_SWAP__YES, | 41 | DSO_SWAP__YES, |
41 | }; | 42 | }; |
42 | 43 | ||
44 | enum dso_data_status { | ||
45 | DSO_DATA_STATUS_ERROR = -1, | ||
46 | DSO_DATA_STATUS_UNKNOWN = 0, | ||
47 | DSO_DATA_STATUS_OK = 1, | ||
48 | }; | ||
49 | |||
50 | enum dso_data_status_seen { | ||
51 | DSO_DATA_STATUS_SEEN_ITRACE, | ||
52 | }; | ||
53 | |||
54 | enum dso_type { | ||
55 | DSO__TYPE_UNKNOWN, | ||
56 | DSO__TYPE_64BIT, | ||
57 | DSO__TYPE_32BIT, | ||
58 | DSO__TYPE_X32BIT, | ||
59 | }; | ||
60 | |||
43 | #define DSO__SWAP(dso, type, val) \ | 61 | #define DSO__SWAP(dso, type, val) \ |
44 | ({ \ | 62 | ({ \ |
45 | type ____r = val; \ | 63 | type ____r = val; \ |
@@ -104,6 +122,8 @@ struct dso { | |||
104 | struct { | 122 | struct { |
105 | struct rb_root cache; | 123 | struct rb_root cache; |
106 | int fd; | 124 | int fd; |
125 | int status; | ||
126 | u32 status_seen; | ||
107 | size_t file_size; | 127 | size_t file_size; |
108 | struct list_head open_entry; | 128 | struct list_head open_entry; |
109 | } data; | 129 | } data; |
@@ -154,6 +174,7 @@ int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type t | |||
154 | * The dso__data_* external interface provides following functions: | 174 | * The dso__data_* external interface provides following functions: |
155 | * dso__data_fd | 175 | * dso__data_fd |
156 | * dso__data_close | 176 | * dso__data_close |
177 | * dso__data_size | ||
157 | * dso__data_read_offset | 178 | * dso__data_read_offset |
158 | * dso__data_read_addr | 179 | * dso__data_read_addr |
159 | * | 180 | * |
@@ -191,11 +212,13 @@ int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type t | |||
191 | int dso__data_fd(struct dso *dso, struct machine *machine); | 212 | int dso__data_fd(struct dso *dso, struct machine *machine); |
192 | void dso__data_close(struct dso *dso); | 213 | void dso__data_close(struct dso *dso); |
193 | 214 | ||
215 | off_t dso__data_size(struct dso *dso, struct machine *machine); | ||
194 | ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, | 216 | ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, |
195 | u64 offset, u8 *data, ssize_t size); | 217 | u64 offset, u8 *data, ssize_t size); |
196 | ssize_t dso__data_read_addr(struct dso *dso, struct map *map, | 218 | ssize_t dso__data_read_addr(struct dso *dso, struct map *map, |
197 | struct machine *machine, u64 addr, | 219 | struct machine *machine, u64 addr, |
198 | u8 *data, ssize_t size); | 220 | u8 *data, ssize_t size); |
221 | bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by); | ||
199 | 222 | ||
200 | struct map *dso__new_map(const char *name); | 223 | struct map *dso__new_map(const char *name); |
201 | struct dso *dso__kernel_findnew(struct machine *machine, const char *name, | 224 | struct dso *dso__kernel_findnew(struct machine *machine, const char *name, |
@@ -230,4 +253,6 @@ static inline bool dso__is_kcore(struct dso *dso) | |||
230 | 253 | ||
231 | void dso__free_a2l(struct dso *dso); | 254 | void dso__free_a2l(struct dso *dso); |
232 | 255 | ||
256 | enum dso_type dso__type(struct dso *dso, struct machine *machine); | ||
257 | |||
233 | #endif /* __PERF_DSO */ | 258 | #endif /* __PERF_DSO */ |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 7e0e8ae568ec..1398c83d896d 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -874,3 +874,45 @@ int perf_event__preprocess_sample(const union perf_event *event, | |||
874 | 874 | ||
875 | return 0; | 875 | return 0; |
876 | } | 876 | } |
877 | |||
878 | bool is_bts_event(struct perf_event_attr *attr) | ||
879 | { | ||
880 | return attr->type == PERF_TYPE_HARDWARE && | ||
881 | (attr->config & PERF_COUNT_HW_BRANCH_INSTRUCTIONS) && | ||
882 | attr->sample_period == 1; | ||
883 | } | ||
884 | |||
885 | bool sample_addr_correlates_sym(struct perf_event_attr *attr) | ||
886 | { | ||
887 | if (attr->type == PERF_TYPE_SOFTWARE && | ||
888 | (attr->config == PERF_COUNT_SW_PAGE_FAULTS || | ||
889 | attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN || | ||
890 | attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)) | ||
891 | return true; | ||
892 | |||
893 | if (is_bts_event(attr)) | ||
894 | return true; | ||
895 | |||
896 | return false; | ||
897 | } | ||
898 | |||
899 | void perf_event__preprocess_sample_addr(union perf_event *event, | ||
900 | struct perf_sample *sample, | ||
901 | struct machine *machine, | ||
902 | struct thread *thread, | ||
903 | struct addr_location *al) | ||
904 | { | ||
905 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | ||
906 | |||
907 | thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, | ||
908 | sample->addr, al); | ||
909 | if (!al->map) | ||
910 | thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE, | ||
911 | sample->addr, al); | ||
912 | |||
913 | al->cpu = sample->cpu; | ||
914 | al->sym = NULL; | ||
915 | |||
916 | if (al->map) | ||
917 | al->sym = map__find_symbol(al->map, al->addr, NULL); | ||
918 | } | ||
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index e5dd40addb30..94d6976180da 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -288,6 +288,16 @@ int perf_event__preprocess_sample(const union perf_event *event, | |||
288 | struct addr_location *al, | 288 | struct addr_location *al, |
289 | struct perf_sample *sample); | 289 | struct perf_sample *sample); |
290 | 290 | ||
291 | struct thread; | ||
292 | |||
293 | bool is_bts_event(struct perf_event_attr *attr); | ||
294 | bool sample_addr_correlates_sym(struct perf_event_attr *attr); | ||
295 | void perf_event__preprocess_sample_addr(union perf_event *event, | ||
296 | struct perf_sample *sample, | ||
297 | struct machine *machine, | ||
298 | struct thread *thread, | ||
299 | struct addr_location *al); | ||
300 | |||
291 | const char *perf_event__name(unsigned int id); | 301 | const char *perf_event__name(unsigned int id); |
292 | 302 | ||
293 | size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, | 303 | size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 893f8e2df928..158c787ce0c4 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -200,6 +200,47 @@ static int write_buildid(const char *name, size_t name_len, u8 *build_id, | |||
200 | return write_padded(fd, name, name_len + 1, len); | 200 | return write_padded(fd, name, name_len + 1, len); |
201 | } | 201 | } |
202 | 202 | ||
203 | static int __dsos__hit_all(struct list_head *head) | ||
204 | { | ||
205 | struct dso *pos; | ||
206 | |||
207 | list_for_each_entry(pos, head, node) | ||
208 | pos->hit = true; | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static int machine__hit_all_dsos(struct machine *machine) | ||
214 | { | ||
215 | int err; | ||
216 | |||
217 | err = __dsos__hit_all(&machine->kernel_dsos); | ||
218 | if (err) | ||
219 | return err; | ||
220 | |||
221 | return __dsos__hit_all(&machine->user_dsos); | ||
222 | } | ||
223 | |||
224 | int dsos__hit_all(struct perf_session *session) | ||
225 | { | ||
226 | struct rb_node *nd; | ||
227 | int err; | ||
228 | |||
229 | err = machine__hit_all_dsos(&session->machines.host); | ||
230 | if (err) | ||
231 | return err; | ||
232 | |||
233 | for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { | ||
234 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
235 | |||
236 | err = machine__hit_all_dsos(pos); | ||
237 | if (err) | ||
238 | return err; | ||
239 | } | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
203 | static int __dsos__write_buildid_table(struct list_head *head, | 244 | static int __dsos__write_buildid_table(struct list_head *head, |
204 | struct machine *machine, | 245 | struct machine *machine, |
205 | pid_t pid, u16 misc, int fd) | 246 | pid_t pid, u16 misc, int fd) |
@@ -215,9 +256,9 @@ static int __dsos__write_buildid_table(struct list_head *head, | |||
215 | if (!pos->hit) | 256 | if (!pos->hit) |
216 | continue; | 257 | continue; |
217 | 258 | ||
218 | if (is_vdso_map(pos->short_name)) { | 259 | if (dso__is_vdso(pos)) { |
219 | name = (char *) VDSO__MAP_NAME; | 260 | name = pos->short_name; |
220 | name_len = sizeof(VDSO__MAP_NAME) + 1; | 261 | name_len = pos->short_name_len + 1; |
221 | } else if (dso__is_kcore(pos)) { | 262 | } else if (dso__is_kcore(pos)) { |
222 | machine__mmap_name(machine, nm, sizeof(nm)); | 263 | machine__mmap_name(machine, nm, sizeof(nm)); |
223 | name = nm; | 264 | name = nm; |
@@ -298,7 +339,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, | |||
298 | 339 | ||
299 | len = scnprintf(filename, size, "%s%s%s", | 340 | len = scnprintf(filename, size, "%s%s%s", |
300 | debugdir, slash ? "/" : "", | 341 | debugdir, slash ? "/" : "", |
301 | is_vdso ? VDSO__MAP_NAME : realname); | 342 | is_vdso ? DSO__NAME_VDSO : realname); |
302 | if (mkdir_p(filename, 0755)) | 343 | if (mkdir_p(filename, 0755)) |
303 | goto out_free; | 344 | goto out_free; |
304 | 345 | ||
@@ -386,7 +427,7 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine, | |||
386 | const char *debugdir) | 427 | const char *debugdir) |
387 | { | 428 | { |
388 | bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; | 429 | bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; |
389 | bool is_vdso = is_vdso_map(dso->short_name); | 430 | bool is_vdso = dso__is_vdso(dso); |
390 | const char *name = dso->long_name; | 431 | const char *name = dso->long_name; |
391 | char nm[PATH_MAX]; | 432 | char nm[PATH_MAX]; |
392 | 433 | ||
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index d08cfe499404..8f5cbaea64a5 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -151,6 +151,8 @@ int perf_event__process_build_id(struct perf_tool *tool, | |||
151 | struct perf_session *session); | 151 | struct perf_session *session); |
152 | bool is_perf_magic(u64 magic); | 152 | bool is_perf_magic(u64 magic); |
153 | 153 | ||
154 | int dsos__hit_all(struct perf_session *session); | ||
155 | |||
154 | /* | 156 | /* |
155 | * arch specific callback | 157 | * arch specific callback |
156 | */ | 158 | */ |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 93c8b6fbc799..16bba9fff2c8 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include "sort.h" | 8 | #include "sort.h" |
9 | #include "strlist.h" | 9 | #include "strlist.h" |
10 | #include "thread.h" | 10 | #include "thread.h" |
11 | #include "vdso.h" | ||
11 | #include <stdbool.h> | 12 | #include <stdbool.h> |
12 | #include <symbol/kallsyms.h> | 13 | #include <symbol/kallsyms.h> |
13 | #include "unwind.h" | 14 | #include "unwind.h" |
@@ -23,6 +24,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | |||
23 | INIT_LIST_HEAD(&machine->dead_threads); | 24 | INIT_LIST_HEAD(&machine->dead_threads); |
24 | machine->last_match = NULL; | 25 | machine->last_match = NULL; |
25 | 26 | ||
27 | machine->vdso_info = NULL; | ||
28 | |||
26 | machine->kmaps.machine = machine; | 29 | machine->kmaps.machine = machine; |
27 | machine->pid = pid; | 30 | machine->pid = pid; |
28 | 31 | ||
@@ -45,6 +48,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | |||
45 | thread__set_comm(thread, comm, 0); | 48 | thread__set_comm(thread, comm, 0); |
46 | } | 49 | } |
47 | 50 | ||
51 | machine->current_tid = NULL; | ||
52 | |||
48 | return 0; | 53 | return 0; |
49 | } | 54 | } |
50 | 55 | ||
@@ -103,7 +108,9 @@ void machine__exit(struct machine *machine) | |||
103 | map_groups__exit(&machine->kmaps); | 108 | map_groups__exit(&machine->kmaps); |
104 | dsos__delete(&machine->user_dsos); | 109 | dsos__delete(&machine->user_dsos); |
105 | dsos__delete(&machine->kernel_dsos); | 110 | dsos__delete(&machine->kernel_dsos); |
111 | vdso__exit(machine); | ||
106 | zfree(&machine->root_dir); | 112 | zfree(&machine->root_dir); |
113 | zfree(&machine->current_tid); | ||
107 | } | 114 | } |
108 | 115 | ||
109 | void machine__delete(struct machine *machine) | 116 | void machine__delete(struct machine *machine) |
@@ -1092,14 +1099,14 @@ int machine__process_mmap2_event(struct machine *machine, | |||
1092 | else | 1099 | else |
1093 | type = MAP__FUNCTION; | 1100 | type = MAP__FUNCTION; |
1094 | 1101 | ||
1095 | map = map__new(&machine->user_dsos, event->mmap2.start, | 1102 | map = map__new(machine, event->mmap2.start, |
1096 | event->mmap2.len, event->mmap2.pgoff, | 1103 | event->mmap2.len, event->mmap2.pgoff, |
1097 | event->mmap2.pid, event->mmap2.maj, | 1104 | event->mmap2.pid, event->mmap2.maj, |
1098 | event->mmap2.min, event->mmap2.ino, | 1105 | event->mmap2.min, event->mmap2.ino, |
1099 | event->mmap2.ino_generation, | 1106 | event->mmap2.ino_generation, |
1100 | event->mmap2.prot, | 1107 | event->mmap2.prot, |
1101 | event->mmap2.flags, | 1108 | event->mmap2.flags, |
1102 | event->mmap2.filename, type); | 1109 | event->mmap2.filename, type, thread); |
1103 | 1110 | ||
1104 | if (map == NULL) | 1111 | if (map == NULL) |
1105 | goto out_problem; | 1112 | goto out_problem; |
@@ -1142,11 +1149,11 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event | |||
1142 | else | 1149 | else |
1143 | type = MAP__FUNCTION; | 1150 | type = MAP__FUNCTION; |
1144 | 1151 | ||
1145 | map = map__new(&machine->user_dsos, event->mmap.start, | 1152 | map = map__new(machine, event->mmap.start, |
1146 | event->mmap.len, event->mmap.pgoff, | 1153 | event->mmap.len, event->mmap.pgoff, |
1147 | event->mmap.pid, 0, 0, 0, 0, 0, 0, | 1154 | event->mmap.pid, 0, 0, 0, 0, 0, 0, |
1148 | event->mmap.filename, | 1155 | event->mmap.filename, |
1149 | type); | 1156 | type, thread); |
1150 | 1157 | ||
1151 | if (map == NULL) | 1158 | if (map == NULL) |
1152 | goto out_problem; | 1159 | goto out_problem; |
@@ -1481,3 +1488,46 @@ int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too | |||
1481 | /* command specified */ | 1488 | /* command specified */ |
1482 | return 0; | 1489 | return 0; |
1483 | } | 1490 | } |
1491 | |||
1492 | pid_t machine__get_current_tid(struct machine *machine, int cpu) | ||
1493 | { | ||
1494 | if (cpu < 0 || cpu >= MAX_NR_CPUS || !machine->current_tid) | ||
1495 | return -1; | ||
1496 | |||
1497 | return machine->current_tid[cpu]; | ||
1498 | } | ||
1499 | |||
1500 | int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, | ||
1501 | pid_t tid) | ||
1502 | { | ||
1503 | struct thread *thread; | ||
1504 | |||
1505 | if (cpu < 0) | ||
1506 | return -EINVAL; | ||
1507 | |||
1508 | if (!machine->current_tid) { | ||
1509 | int i; | ||
1510 | |||
1511 | machine->current_tid = calloc(MAX_NR_CPUS, sizeof(pid_t)); | ||
1512 | if (!machine->current_tid) | ||
1513 | return -ENOMEM; | ||
1514 | for (i = 0; i < MAX_NR_CPUS; i++) | ||
1515 | machine->current_tid[i] = -1; | ||
1516 | } | ||
1517 | |||
1518 | if (cpu >= MAX_NR_CPUS) { | ||
1519 | pr_err("Requested CPU %d too large. ", cpu); | ||
1520 | pr_err("Consider raising MAX_NR_CPUS\n"); | ||
1521 | return -EINVAL; | ||
1522 | } | ||
1523 | |||
1524 | machine->current_tid[cpu] = tid; | ||
1525 | |||
1526 | thread = machine__findnew_thread(machine, pid, tid); | ||
1527 | if (!thread) | ||
1528 | return -ENOMEM; | ||
1529 | |||
1530 | thread->cpu = cpu; | ||
1531 | |||
1532 | return 0; | ||
1533 | } | ||
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index c8c74a119398..b972824e6294 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h | |||
@@ -20,6 +20,8 @@ union perf_event; | |||
20 | 20 | ||
21 | extern const char *ref_reloc_sym_names[]; | 21 | extern const char *ref_reloc_sym_names[]; |
22 | 22 | ||
23 | struct vdso_info; | ||
24 | |||
23 | struct machine { | 25 | struct machine { |
24 | struct rb_node rb_node; | 26 | struct rb_node rb_node; |
25 | pid_t pid; | 27 | pid_t pid; |
@@ -28,11 +30,13 @@ struct machine { | |||
28 | struct rb_root threads; | 30 | struct rb_root threads; |
29 | struct list_head dead_threads; | 31 | struct list_head dead_threads; |
30 | struct thread *last_match; | 32 | struct thread *last_match; |
33 | struct vdso_info *vdso_info; | ||
31 | struct list_head user_dsos; | 34 | struct list_head user_dsos; |
32 | struct list_head kernel_dsos; | 35 | struct list_head kernel_dsos; |
33 | struct map_groups kmaps; | 36 | struct map_groups kmaps; |
34 | struct map *vmlinux_maps[MAP__NR_TYPES]; | 37 | struct map *vmlinux_maps[MAP__NR_TYPES]; |
35 | symbol_filter_t symbol_filter; | 38 | symbol_filter_t symbol_filter; |
39 | pid_t *current_tid; | ||
36 | }; | 40 | }; |
37 | 41 | ||
38 | static inline | 42 | static inline |
@@ -191,4 +195,8 @@ int machine__synthesize_threads(struct machine *machine, struct target *target, | |||
191 | perf_event__process, data_mmap); | 195 | perf_event__process, data_mmap); |
192 | } | 196 | } |
193 | 197 | ||
198 | pid_t machine__get_current_tid(struct machine *machine, int cpu); | ||
199 | int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, | ||
200 | pid_t tid); | ||
201 | |||
194 | #endif /* __PERF_MACHINE_H */ | 202 | #endif /* __PERF_MACHINE_H */ |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 845f627e45f4..31b8905dd863 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include "build-id.h" | 13 | #include "build-id.h" |
14 | #include "util.h" | 14 | #include "util.h" |
15 | #include "debug.h" | 15 | #include "debug.h" |
16 | #include "machine.h" | ||
16 | #include <linux/string.h> | 17 | #include <linux/string.h> |
17 | 18 | ||
18 | const char *map_type__name[MAP__NR_TYPES] = { | 19 | const char *map_type__name[MAP__NR_TYPES] = { |
@@ -137,10 +138,10 @@ void map__init(struct map *map, enum map_type type, | |||
137 | map->erange_warned = false; | 138 | map->erange_warned = false; |
138 | } | 139 | } |
139 | 140 | ||
140 | struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | 141 | struct map *map__new(struct machine *machine, u64 start, u64 len, |
141 | u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, | 142 | u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, |
142 | u64 ino_gen, u32 prot, u32 flags, char *filename, | 143 | u64 ino_gen, u32 prot, u32 flags, char *filename, |
143 | enum map_type type) | 144 | enum map_type type, struct thread *thread) |
144 | { | 145 | { |
145 | struct map *map = malloc(sizeof(*map)); | 146 | struct map *map = malloc(sizeof(*map)); |
146 | 147 | ||
@@ -173,9 +174,9 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | |||
173 | 174 | ||
174 | if (vdso) { | 175 | if (vdso) { |
175 | pgoff = 0; | 176 | pgoff = 0; |
176 | dso = vdso__dso_findnew(dsos__list); | 177 | dso = vdso__dso_findnew(machine, thread); |
177 | } else | 178 | } else |
178 | dso = __dsos__findnew(dsos__list, filename); | 179 | dso = __dsos__findnew(&machine->user_dsos, filename); |
179 | 180 | ||
180 | if (dso == NULL) | 181 | if (dso == NULL) |
181 | goto out_delete; | 182 | goto out_delete; |
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 22d13a219590..2f83954af050 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
@@ -104,6 +104,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip); | |||
104 | u64 map__objdump_2mem(struct map *map, u64 ip); | 104 | u64 map__objdump_2mem(struct map *map, u64 ip); |
105 | 105 | ||
106 | struct symbol; | 106 | struct symbol; |
107 | struct thread; | ||
107 | 108 | ||
108 | /* map__for_each_symbol - iterate over the symbols in the given map | 109 | /* map__for_each_symbol - iterate over the symbols in the given map |
109 | * | 110 | * |
@@ -119,10 +120,10 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); | |||
119 | 120 | ||
120 | void map__init(struct map *map, enum map_type type, | 121 | void map__init(struct map *map, enum map_type type, |
121 | u64 start, u64 end, u64 pgoff, struct dso *dso); | 122 | u64 start, u64 end, u64 pgoff, struct dso *dso); |
122 | struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | 123 | struct map *map__new(struct machine *machine, u64 start, u64 len, |
123 | u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, | 124 | u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, |
124 | u64 ino_gen, u32 prot, u32 flags, | 125 | u64 ino_gen, u32 prot, u32 flags, |
125 | char *filename, enum map_type type); | 126 | char *filename, enum map_type type, struct thread *thread); |
126 | struct map *map__new2(u64 start, struct dso *dso, enum map_type type); | 127 | struct map *map__new2(u64 start, struct dso *dso, enum map_type type); |
127 | void map__delete(struct map *map); | 128 | void map__delete(struct map *map); |
128 | struct map *map__clone(struct map *map); | 129 | struct map *map__clone(struct map *map); |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index eac14ce0ae8d..88dfef70c13d 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -14,7 +14,6 @@ | |||
14 | #include "util.h" | 14 | #include "util.h" |
15 | #include "cpumap.h" | 15 | #include "cpumap.h" |
16 | #include "perf_regs.h" | 16 | #include "perf_regs.h" |
17 | #include "vdso.h" | ||
18 | 17 | ||
19 | static int perf_session__open(struct perf_session *session) | 18 | static int perf_session__open(struct perf_session *session) |
20 | { | 19 | { |
@@ -156,7 +155,6 @@ void perf_session__delete(struct perf_session *session) | |||
156 | if (session->file) | 155 | if (session->file) |
157 | perf_data_file__close(session->file); | 156 | perf_data_file__close(session->file); |
158 | free(session); | 157 | free(session); |
159 | vdso__exit(); | ||
160 | } | 158 | } |
161 | 159 | ||
162 | static int process_event_synth_tracing_data_stub(struct perf_tool *tool | 160 | static int process_event_synth_tracing_data_stub(struct perf_tool *tool |
@@ -511,6 +509,7 @@ static int flush_sample_queue(struct perf_session *s, | |||
511 | os->last_flush = iter->timestamp; | 509 | os->last_flush = iter->timestamp; |
512 | list_del(&iter->list); | 510 | list_del(&iter->list); |
513 | list_add(&iter->list, &os->sample_cache); | 511 | list_add(&iter->list, &os->sample_cache); |
512 | os->nr_samples--; | ||
514 | 513 | ||
515 | if (show_progress) | 514 | if (show_progress) |
516 | ui_progress__update(&prog, 1); | 515 | ui_progress__update(&prog, 1); |
@@ -523,8 +522,6 @@ static int flush_sample_queue(struct perf_session *s, | |||
523 | list_entry(head->prev, struct sample_queue, list); | 522 | list_entry(head->prev, struct sample_queue, list); |
524 | } | 523 | } |
525 | 524 | ||
526 | os->nr_samples = 0; | ||
527 | |||
528 | return 0; | 525 | return 0; |
529 | } | 526 | } |
530 | 527 | ||
@@ -994,8 +991,10 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
994 | } | 991 | } |
995 | } | 992 | } |
996 | 993 | ||
997 | static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, | 994 | static s64 perf_session__process_user_event(struct perf_session *session, |
998 | struct perf_tool *tool, u64 file_offset) | 995 | union perf_event *event, |
996 | struct perf_tool *tool, | ||
997 | u64 file_offset) | ||
999 | { | 998 | { |
1000 | int fd = perf_data_file__fd(session->file); | 999 | int fd = perf_data_file__fd(session->file); |
1001 | int err; | 1000 | int err; |
@@ -1037,7 +1036,7 @@ static void event_swap(union perf_event *event, bool sample_id_all) | |||
1037 | swap(event, sample_id_all); | 1036 | swap(event, sample_id_all); |
1038 | } | 1037 | } |
1039 | 1038 | ||
1040 | static int perf_session__process_event(struct perf_session *session, | 1039 | static s64 perf_session__process_event(struct perf_session *session, |
1041 | union perf_event *event, | 1040 | union perf_event *event, |
1042 | struct perf_tool *tool, | 1041 | struct perf_tool *tool, |
1043 | u64 file_offset) | 1042 | u64 file_offset) |
@@ -1148,7 +1147,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session, | |||
1148 | union perf_event *event; | 1147 | union perf_event *event; |
1149 | uint32_t size, cur_size = 0; | 1148 | uint32_t size, cur_size = 0; |
1150 | void *buf = NULL; | 1149 | void *buf = NULL; |
1151 | int skip = 0; | 1150 | s64 skip = 0; |
1152 | u64 head; | 1151 | u64 head; |
1153 | ssize_t err; | 1152 | ssize_t err; |
1154 | void *p; | 1153 | void *p; |
@@ -1277,13 +1276,13 @@ int __perf_session__process_events(struct perf_session *session, | |||
1277 | u64 file_size, struct perf_tool *tool) | 1276 | u64 file_size, struct perf_tool *tool) |
1278 | { | 1277 | { |
1279 | int fd = perf_data_file__fd(session->file); | 1278 | int fd = perf_data_file__fd(session->file); |
1280 | u64 head, page_offset, file_offset, file_pos; | 1279 | u64 head, page_offset, file_offset, file_pos, size; |
1281 | int err, mmap_prot, mmap_flags, map_idx = 0; | 1280 | int err, mmap_prot, mmap_flags, map_idx = 0; |
1282 | size_t mmap_size; | 1281 | size_t mmap_size; |
1283 | char *buf, *mmaps[NUM_MMAPS]; | 1282 | char *buf, *mmaps[NUM_MMAPS]; |
1284 | union perf_event *event; | 1283 | union perf_event *event; |
1285 | uint32_t size; | ||
1286 | struct ui_progress prog; | 1284 | struct ui_progress prog; |
1285 | s64 skip; | ||
1287 | 1286 | ||
1288 | perf_tool__fill_defaults(tool); | 1287 | perf_tool__fill_defaults(tool); |
1289 | 1288 | ||
@@ -1344,7 +1343,8 @@ more: | |||
1344 | size = event->header.size; | 1343 | size = event->header.size; |
1345 | 1344 | ||
1346 | if (size < sizeof(struct perf_event_header) || | 1345 | if (size < sizeof(struct perf_event_header) || |
1347 | perf_session__process_event(session, event, tool, file_pos) < 0) { | 1346 | (skip = perf_session__process_event(session, event, tool, file_pos)) |
1347 | < 0) { | ||
1348 | pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", | 1348 | pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", |
1349 | file_offset + head, event->header.size, | 1349 | file_offset + head, event->header.size, |
1350 | event->header.type); | 1350 | event->header.type); |
@@ -1352,6 +1352,9 @@ more: | |||
1352 | goto out_err; | 1352 | goto out_err; |
1353 | } | 1353 | } |
1354 | 1354 | ||
1355 | if (skip) | ||
1356 | size += skip; | ||
1357 | |||
1355 | head += size; | 1358 | head += size; |
1356 | file_pos += size; | 1359 | file_pos += size; |
1357 | 1360 | ||
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index cef8f426356e..d75349979e65 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -622,7 +622,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, | |||
622 | GElf_Shdr shdr; | 622 | GElf_Shdr shdr; |
623 | ss->adjust_symbols = (ehdr.e_type == ET_EXEC || | 623 | ss->adjust_symbols = (ehdr.e_type == ET_EXEC || |
624 | ehdr.e_type == ET_REL || | 624 | ehdr.e_type == ET_REL || |
625 | is_vdso_map(dso->short_name) || | 625 | dso__is_vdso(dso) || |
626 | elf_section_by_name(elf, &ehdr, &shdr, | 626 | elf_section_by_name(elf, &ehdr, &shdr, |
627 | ".gnu.prelink_undo", | 627 | ".gnu.prelink_undo", |
628 | NULL) != NULL); | 628 | NULL) != NULL); |
@@ -1028,6 +1028,39 @@ int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data, | |||
1028 | return err; | 1028 | return err; |
1029 | } | 1029 | } |
1030 | 1030 | ||
1031 | enum dso_type dso__type_fd(int fd) | ||
1032 | { | ||
1033 | enum dso_type dso_type = DSO__TYPE_UNKNOWN; | ||
1034 | GElf_Ehdr ehdr; | ||
1035 | Elf_Kind ek; | ||
1036 | Elf *elf; | ||
1037 | |||
1038 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
1039 | if (elf == NULL) | ||
1040 | goto out; | ||
1041 | |||
1042 | ek = elf_kind(elf); | ||
1043 | if (ek != ELF_K_ELF) | ||
1044 | goto out_end; | ||
1045 | |||
1046 | if (gelf_getclass(elf) == ELFCLASS64) { | ||
1047 | dso_type = DSO__TYPE_64BIT; | ||
1048 | goto out_end; | ||
1049 | } | ||
1050 | |||
1051 | if (gelf_getehdr(elf, &ehdr) == NULL) | ||
1052 | goto out_end; | ||
1053 | |||
1054 | if (ehdr.e_machine == EM_X86_64) | ||
1055 | dso_type = DSO__TYPE_X32BIT; | ||
1056 | else | ||
1057 | dso_type = DSO__TYPE_32BIT; | ||
1058 | out_end: | ||
1059 | elf_end(elf); | ||
1060 | out: | ||
1061 | return dso_type; | ||
1062 | } | ||
1063 | |||
1031 | static int copy_bytes(int from, off_t from_offs, int to, off_t to_offs, u64 len) | 1064 | static int copy_bytes(int from, off_t from_offs, int to, off_t to_offs, u64 len) |
1032 | { | 1065 | { |
1033 | ssize_t r; | 1066 | ssize_t r; |
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index 101f55d407d0..c9541fea9514 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c | |||
@@ -305,6 +305,27 @@ static int fd__is_64_bit(int fd) | |||
305 | return e_ident[EI_CLASS] == ELFCLASS64; | 305 | return e_ident[EI_CLASS] == ELFCLASS64; |
306 | } | 306 | } |
307 | 307 | ||
308 | enum dso_type dso__type_fd(int fd) | ||
309 | { | ||
310 | Elf64_Ehdr ehdr; | ||
311 | int ret; | ||
312 | |||
313 | ret = fd__is_64_bit(fd); | ||
314 | if (ret < 0) | ||
315 | return DSO__TYPE_UNKNOWN; | ||
316 | |||
317 | if (ret) | ||
318 | return DSO__TYPE_64BIT; | ||
319 | |||
320 | if (readn(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) | ||
321 | return DSO__TYPE_UNKNOWN; | ||
322 | |||
323 | if (ehdr.e_machine == EM_X86_64) | ||
324 | return DSO__TYPE_X32BIT; | ||
325 | |||
326 | return DSO__TYPE_32BIT; | ||
327 | } | ||
328 | |||
308 | int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, | 329 | int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, |
309 | struct symsrc *ss, | 330 | struct symsrc *ss, |
310 | struct symsrc *runtime_ss __maybe_unused, | 331 | struct symsrc *runtime_ss __maybe_unused, |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index ee2d3ccd3ad1..e7295e93cff9 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -243,6 +243,8 @@ struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, | |||
243 | struct symbol *dso__first_symbol(struct dso *dso, enum map_type type); | 243 | struct symbol *dso__first_symbol(struct dso *dso, enum map_type type); |
244 | struct symbol *dso__next_symbol(struct symbol *sym); | 244 | struct symbol *dso__next_symbol(struct symbol *sym); |
245 | 245 | ||
246 | enum dso_type dso__type_fd(int fd); | ||
247 | |||
246 | int filename__read_build_id(const char *filename, void *bf, size_t size); | 248 | int filename__read_build_id(const char *filename, void *bf, size_t size); |
247 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); | 249 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); |
248 | int modules__parse(const char *filename, void *arg, | 250 | int modules__parse(const char *filename, void *arg, |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 9692c06a9e21..12c7a253a63c 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -34,6 +34,7 @@ struct thread *thread__new(pid_t pid, pid_t tid) | |||
34 | thread->pid_ = pid; | 34 | thread->pid_ = pid; |
35 | thread->tid = tid; | 35 | thread->tid = tid; |
36 | thread->ppid = -1; | 36 | thread->ppid = -1; |
37 | thread->cpu = -1; | ||
37 | INIT_LIST_HEAD(&thread->comm_list); | 38 | INIT_LIST_HEAD(&thread->comm_list); |
38 | 39 | ||
39 | comm_str = malloc(32); | 40 | comm_str = malloc(32); |
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 3c0c2724f82c..716b7723cce2 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
@@ -17,6 +17,7 @@ struct thread { | |||
17 | pid_t pid_; /* Not all tools update this */ | 17 | pid_t pid_; /* Not all tools update this */ |
18 | pid_t tid; | 18 | pid_t tid; |
19 | pid_t ppid; | 19 | pid_t ppid; |
20 | int cpu; | ||
20 | char shortname[3]; | 21 | char shortname[3]; |
21 | bool comm_set; | 22 | bool comm_set; |
22 | bool dead; /* if set thread has exited */ | 23 | bool dead; /* if set thread has exited */ |
diff --git a/tools/perf/util/tsc.c b/tools/perf/util/tsc.c index ef4749836ce9..4d4210d4e13d 100644 --- a/tools/perf/util/tsc.c +++ b/tools/perf/util/tsc.c | |||
@@ -23,3 +23,8 @@ u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc) | |||
23 | return tc->time_zero + quot * tc->time_mult + | 23 | return tc->time_zero + quot * tc->time_mult + |
24 | ((rem * tc->time_mult) >> tc->time_shift); | 24 | ((rem * tc->time_mult) >> tc->time_shift); |
25 | } | 25 | } |
26 | |||
27 | u64 __weak rdtsc(void) | ||
28 | { | ||
29 | return 0; | ||
30 | } | ||
diff --git a/tools/perf/util/tsc.h b/tools/perf/util/tsc.h index 4eca84887c8a..a8b78f1b3243 100644 --- a/tools/perf/util/tsc.h +++ b/tools/perf/util/tsc.h | |||
@@ -7,5 +7,6 @@ | |||
7 | 7 | ||
8 | u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc); | 8 | u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc); |
9 | u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc); | 9 | u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc); |
10 | u64 rdtsc(void); | ||
10 | 11 | ||
11 | #endif | 12 | #endif |
diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index 290582452da3..adca69384fcc 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c | |||
@@ -11,11 +11,34 @@ | |||
11 | #include "vdso.h" | 11 | #include "vdso.h" |
12 | #include "util.h" | 12 | #include "util.h" |
13 | #include "symbol.h" | 13 | #include "symbol.h" |
14 | #include "machine.h" | ||
14 | #include "linux/string.h" | 15 | #include "linux/string.h" |
15 | #include "debug.h" | 16 | #include "debug.h" |
16 | 17 | ||
17 | static bool vdso_found; | 18 | #define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX" |
18 | static char vdso_file[] = "/tmp/perf-vdso.so-XXXXXX"; | 19 | |
20 | struct vdso_file { | ||
21 | bool found; | ||
22 | bool error; | ||
23 | char temp_file_name[sizeof(VDSO__TEMP_FILE_NAME)]; | ||
24 | const char *dso_name; | ||
25 | }; | ||
26 | |||
27 | struct vdso_info { | ||
28 | struct vdso_file vdso; | ||
29 | }; | ||
30 | |||
31 | static struct vdso_info *vdso_info__new(void) | ||
32 | { | ||
33 | static const struct vdso_info vdso_info_init = { | ||
34 | .vdso = { | ||
35 | .temp_file_name = VDSO__TEMP_FILE_NAME, | ||
36 | .dso_name = DSO__NAME_VDSO, | ||
37 | }, | ||
38 | }; | ||
39 | |||
40 | return memdup(&vdso_info_init, sizeof(vdso_info_init)); | ||
41 | } | ||
19 | 42 | ||
20 | static int find_vdso_map(void **start, void **end) | 43 | static int find_vdso_map(void **start, void **end) |
21 | { | 44 | { |
@@ -48,7 +71,7 @@ static int find_vdso_map(void **start, void **end) | |||
48 | return !found; | 71 | return !found; |
49 | } | 72 | } |
50 | 73 | ||
51 | static char *get_file(void) | 74 | static char *get_file(struct vdso_file *vdso_file) |
52 | { | 75 | { |
53 | char *vdso = NULL; | 76 | char *vdso = NULL; |
54 | char *buf = NULL; | 77 | char *buf = NULL; |
@@ -56,10 +79,10 @@ static char *get_file(void) | |||
56 | size_t size; | 79 | size_t size; |
57 | int fd; | 80 | int fd; |
58 | 81 | ||
59 | if (vdso_found) | 82 | if (vdso_file->found) |
60 | return vdso_file; | 83 | return vdso_file->temp_file_name; |
61 | 84 | ||
62 | if (find_vdso_map(&start, &end)) | 85 | if (vdso_file->error || find_vdso_map(&start, &end)) |
63 | return NULL; | 86 | return NULL; |
64 | 87 | ||
65 | size = end - start; | 88 | size = end - start; |
@@ -68,45 +91,78 @@ static char *get_file(void) | |||
68 | if (!buf) | 91 | if (!buf) |
69 | return NULL; | 92 | return NULL; |
70 | 93 | ||
71 | fd = mkstemp(vdso_file); | 94 | fd = mkstemp(vdso_file->temp_file_name); |
72 | if (fd < 0) | 95 | if (fd < 0) |
73 | goto out; | 96 | goto out; |
74 | 97 | ||
75 | if (size == (size_t) write(fd, buf, size)) | 98 | if (size == (size_t) write(fd, buf, size)) |
76 | vdso = vdso_file; | 99 | vdso = vdso_file->temp_file_name; |
77 | 100 | ||
78 | close(fd); | 101 | close(fd); |
79 | 102 | ||
80 | out: | 103 | out: |
81 | free(buf); | 104 | free(buf); |
82 | 105 | ||
83 | vdso_found = (vdso != NULL); | 106 | vdso_file->found = (vdso != NULL); |
107 | vdso_file->error = !vdso_file->found; | ||
84 | return vdso; | 108 | return vdso; |
85 | } | 109 | } |
86 | 110 | ||
87 | void vdso__exit(void) | 111 | void vdso__exit(struct machine *machine) |
88 | { | 112 | { |
89 | if (vdso_found) | 113 | struct vdso_info *vdso_info = machine->vdso_info; |
90 | unlink(vdso_file); | 114 | |
115 | if (!vdso_info) | ||
116 | return; | ||
117 | |||
118 | if (vdso_info->vdso.found) | ||
119 | unlink(vdso_info->vdso.temp_file_name); | ||
120 | |||
121 | zfree(&machine->vdso_info); | ||
91 | } | 122 | } |
92 | 123 | ||
93 | struct dso *vdso__dso_findnew(struct list_head *head) | 124 | static struct dso *vdso__new(struct machine *machine, const char *short_name, |
125 | const char *long_name) | ||
94 | { | 126 | { |
95 | struct dso *dso = dsos__find(head, VDSO__MAP_NAME, true); | 127 | struct dso *dso; |
96 | 128 | ||
129 | dso = dso__new(short_name); | ||
130 | if (dso != NULL) { | ||
131 | dsos__add(&machine->user_dsos, dso); | ||
132 | dso__set_long_name(dso, long_name, false); | ||
133 | } | ||
134 | |||
135 | return dso; | ||
136 | } | ||
137 | |||
138 | struct dso *vdso__dso_findnew(struct machine *machine, | ||
139 | struct thread *thread __maybe_unused) | ||
140 | { | ||
141 | struct vdso_info *vdso_info; | ||
142 | struct dso *dso; | ||
143 | |||
144 | if (!machine->vdso_info) | ||
145 | machine->vdso_info = vdso_info__new(); | ||
146 | |||
147 | vdso_info = machine->vdso_info; | ||
148 | if (!vdso_info) | ||
149 | return NULL; | ||
150 | |||
151 | dso = dsos__find(&machine->user_dsos, DSO__NAME_VDSO, true); | ||
97 | if (!dso) { | 152 | if (!dso) { |
98 | char *file; | 153 | char *file; |
99 | 154 | ||
100 | file = get_file(); | 155 | file = get_file(&vdso_info->vdso); |
101 | if (!file) | 156 | if (!file) |
102 | return NULL; | 157 | return NULL; |
103 | 158 | ||
104 | dso = dso__new(VDSO__MAP_NAME); | 159 | dso = vdso__new(machine, DSO__NAME_VDSO, file); |
105 | if (dso != NULL) { | ||
106 | dsos__add(head, dso); | ||
107 | dso__set_long_name(dso, file, false); | ||
108 | } | ||
109 | } | 160 | } |
110 | 161 | ||
111 | return dso; | 162 | return dso; |
112 | } | 163 | } |
164 | |||
165 | bool dso__is_vdso(struct dso *dso) | ||
166 | { | ||
167 | return !strcmp(dso->short_name, DSO__NAME_VDSO); | ||
168 | } | ||
diff --git a/tools/perf/util/vdso.h b/tools/perf/util/vdso.h index 0f76e7caf6f8..af9d6929a215 100644 --- a/tools/perf/util/vdso.h +++ b/tools/perf/util/vdso.h | |||
@@ -7,12 +7,21 @@ | |||
7 | 7 | ||
8 | #define VDSO__MAP_NAME "[vdso]" | 8 | #define VDSO__MAP_NAME "[vdso]" |
9 | 9 | ||
10 | #define DSO__NAME_VDSO "[vdso]" | ||
11 | |||
10 | static inline bool is_vdso_map(const char *filename) | 12 | static inline bool is_vdso_map(const char *filename) |
11 | { | 13 | { |
12 | return !strcmp(filename, VDSO__MAP_NAME); | 14 | return !strcmp(filename, VDSO__MAP_NAME); |
13 | } | 15 | } |
14 | 16 | ||
15 | struct dso *vdso__dso_findnew(struct list_head *head); | 17 | struct dso; |
16 | void vdso__exit(void); | 18 | |
19 | bool dso__is_vdso(struct dso *dso); | ||
20 | |||
21 | struct machine; | ||
22 | struct thread; | ||
23 | |||
24 | struct dso *vdso__dso_findnew(struct machine *machine, struct thread *thread); | ||
25 | void vdso__exit(struct machine *machine); | ||
17 | 26 | ||
18 | #endif /* __PERF_VDSO__ */ | 27 | #endif /* __PERF_VDSO__ */ |