diff options
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 11 | ||||
-rw-r--r-- | include/linux/perf_event.h | 24 | ||||
-rw-r--r-- | kernel/events/core.c | 6 | ||||
-rw-r--r-- | tools/perf/Makefile | 1 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 1 | ||||
-rw-r--r-- | tools/perf/config/feature-tests.mak | 2 | ||||
-rw-r--r-- | tools/perf/util/dwarf-aux.c | 25 | ||||
-rw-r--r-- | tools/perf/util/dwarf-aux.h | 6 | ||||
-rw-r--r-- | tools/perf/util/header.c | 12 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 49 | ||||
-rw-r--r-- | tools/perf/util/session.c | 4 |
11 files changed, 106 insertions, 35 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 897783b3302a..9d8449158cf9 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
@@ -1888,10 +1888,7 @@ void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now) | |||
1888 | userpg->cap_user_rdpmc = x86_pmu.attr_rdpmc; | 1888 | userpg->cap_user_rdpmc = x86_pmu.attr_rdpmc; |
1889 | userpg->pmc_width = x86_pmu.cntval_bits; | 1889 | userpg->pmc_width = x86_pmu.cntval_bits; |
1890 | 1890 | ||
1891 | if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) | 1891 | if (!sched_clock_stable) |
1892 | return; | ||
1893 | |||
1894 | if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) | ||
1895 | return; | 1892 | return; |
1896 | 1893 | ||
1897 | userpg->cap_user_time = 1; | 1894 | userpg->cap_user_time = 1; |
@@ -1899,10 +1896,8 @@ void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now) | |||
1899 | userpg->time_shift = CYC2NS_SCALE_FACTOR; | 1896 | userpg->time_shift = CYC2NS_SCALE_FACTOR; |
1900 | userpg->time_offset = this_cpu_read(cyc2ns_offset) - now; | 1897 | userpg->time_offset = this_cpu_read(cyc2ns_offset) - now; |
1901 | 1898 | ||
1902 | if (sched_clock_stable && !check_tsc_disabled()) { | 1899 | userpg->cap_user_time_zero = 1; |
1903 | userpg->cap_user_time_zero = 1; | 1900 | userpg->time_zero = this_cpu_read(cyc2ns_offset); |
1904 | userpg->time_zero = this_cpu_read(cyc2ns_offset); | ||
1905 | } | ||
1906 | } | 1901 | } |
1907 | 1902 | ||
1908 | /* | 1903 | /* |
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 866e85c5eb94..c8ba627c1d60 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -294,9 +294,31 @@ struct ring_buffer; | |||
294 | */ | 294 | */ |
295 | struct perf_event { | 295 | struct perf_event { |
296 | #ifdef CONFIG_PERF_EVENTS | 296 | #ifdef CONFIG_PERF_EVENTS |
297 | struct list_head group_entry; | 297 | /* |
298 | * entry onto perf_event_context::event_list; | ||
299 | * modifications require ctx->lock | ||
300 | * RCU safe iterations. | ||
301 | */ | ||
298 | struct list_head event_entry; | 302 | struct list_head event_entry; |
303 | |||
304 | /* | ||
305 | * XXX: group_entry and sibling_list should be mutually exclusive; | ||
306 | * either you're a sibling on a group, or you're the group leader. | ||
307 | * Rework the code to always use the same list element. | ||
308 | * | ||
309 | * Locked for modification by both ctx->mutex and ctx->lock; holding | ||
310 | * either sufficies for read. | ||
311 | */ | ||
312 | struct list_head group_entry; | ||
299 | struct list_head sibling_list; | 313 | struct list_head sibling_list; |
314 | |||
315 | /* | ||
316 | * We need storage to track the entries in perf_pmu_migrate_context; we | ||
317 | * cannot use the event_entry because of RCU and we want to keep the | ||
318 | * group in tact which avoids us using the other two entries. | ||
319 | */ | ||
320 | struct list_head migrate_entry; | ||
321 | |||
300 | struct hlist_node hlist_entry; | 322 | struct hlist_node hlist_entry; |
301 | int nr_siblings; | 323 | int nr_siblings; |
302 | int group_flags; | 324 | int group_flags; |
diff --git a/kernel/events/core.c b/kernel/events/core.c index cb4238e85b38..d49a9d29334c 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -7234,15 +7234,15 @@ void perf_pmu_migrate_context(struct pmu *pmu, int src_cpu, int dst_cpu) | |||
7234 | perf_remove_from_context(event); | 7234 | perf_remove_from_context(event); |
7235 | unaccount_event_cpu(event, src_cpu); | 7235 | unaccount_event_cpu(event, src_cpu); |
7236 | put_ctx(src_ctx); | 7236 | put_ctx(src_ctx); |
7237 | list_add(&event->event_entry, &events); | 7237 | list_add(&event->migrate_entry, &events); |
7238 | } | 7238 | } |
7239 | mutex_unlock(&src_ctx->mutex); | 7239 | mutex_unlock(&src_ctx->mutex); |
7240 | 7240 | ||
7241 | synchronize_rcu(); | 7241 | synchronize_rcu(); |
7242 | 7242 | ||
7243 | mutex_lock(&dst_ctx->mutex); | 7243 | mutex_lock(&dst_ctx->mutex); |
7244 | list_for_each_entry_safe(event, tmp, &events, event_entry) { | 7244 | list_for_each_entry_safe(event, tmp, &events, migrate_entry) { |
7245 | list_del(&event->event_entry); | 7245 | list_del(&event->migrate_entry); |
7246 | if (event->state >= PERF_EVENT_STATE_OFF) | 7246 | if (event->state >= PERF_EVENT_STATE_OFF) |
7247 | event->state = PERF_EVENT_STATE_INACTIVE; | 7247 | event->state = PERF_EVENT_STATE_INACTIVE; |
7248 | account_event_cpu(event, dst_cpu); | 7248 | account_event_cpu(event, dst_cpu); |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 3a0ff7fb71b6..64c043b7a438 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -770,6 +770,7 @@ check: $(OUTPUT)common-cmds.h | |||
770 | install-bin: all | 770 | install-bin: all |
771 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' | 771 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' |
772 | $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)' | 772 | $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)' |
773 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' | ||
773 | $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' | 774 | $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' |
774 | ifndef NO_LIBPERL | 775 | ifndef NO_LIBPERL |
775 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' | 776 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index f686d5ff594e..5098f144b92d 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -457,6 +457,7 @@ static int __run_perf_stat(int argc, const char **argv) | |||
457 | perror("failed to prepare workload"); | 457 | perror("failed to prepare workload"); |
458 | return -1; | 458 | return -1; |
459 | } | 459 | } |
460 | child_pid = evsel_list->workload.pid; | ||
460 | } | 461 | } |
461 | 462 | ||
462 | if (group) | 463 | if (group) |
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak index d5a8dd44945f..f79305739ecc 100644 --- a/tools/perf/config/feature-tests.mak +++ b/tools/perf/config/feature-tests.mak | |||
@@ -219,7 +219,7 @@ define SOURCE_LIBAUDIT | |||
219 | 219 | ||
220 | int main(void) | 220 | int main(void) |
221 | { | 221 | { |
222 | printf(\"error message: %s\n\", audit_errno_to_name(0)); | 222 | printf(\"error message: %s\", audit_errno_to_name(0)); |
223 | return audit_open(); | 223 | return audit_open(); |
224 | } | 224 | } |
225 | endef | 225 | endef |
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index e23bde19d590..7defd77105d0 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c | |||
@@ -426,7 +426,7 @@ static int __die_search_func_cb(Dwarf_Die *fn_die, void *data) | |||
426 | * @die_mem: a buffer for result DIE | 426 | * @die_mem: a buffer for result DIE |
427 | * | 427 | * |
428 | * Search a non-inlined function DIE which includes @addr. Stores the | 428 | * Search a non-inlined function DIE which includes @addr. Stores the |
429 | * DIE to @die_mem and returns it if found. Returns NULl if failed. | 429 | * DIE to @die_mem and returns it if found. Returns NULL if failed. |
430 | */ | 430 | */ |
431 | Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, | 431 | Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, |
432 | Dwarf_Die *die_mem) | 432 | Dwarf_Die *die_mem) |
@@ -454,15 +454,32 @@ static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data) | |||
454 | } | 454 | } |
455 | 455 | ||
456 | /** | 456 | /** |
457 | * die_find_top_inlinefunc - Search the top inlined function at given address | ||
458 | * @sp_die: a subprogram DIE which including @addr | ||
459 | * @addr: target address | ||
460 | * @die_mem: a buffer for result DIE | ||
461 | * | ||
462 | * Search an inlined function DIE which includes @addr. Stores the | ||
463 | * DIE to @die_mem and returns it if found. Returns NULL if failed. | ||
464 | * Even if several inlined functions are expanded recursively, this | ||
465 | * doesn't trace it down, and returns the topmost one. | ||
466 | */ | ||
467 | Dwarf_Die *die_find_top_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | ||
468 | Dwarf_Die *die_mem) | ||
469 | { | ||
470 | return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); | ||
471 | } | ||
472 | |||
473 | /** | ||
457 | * die_find_inlinefunc - Search an inlined function at given address | 474 | * die_find_inlinefunc - Search an inlined function at given address |
458 | * @cu_die: a CU DIE which including @addr | 475 | * @sp_die: a subprogram DIE which including @addr |
459 | * @addr: target address | 476 | * @addr: target address |
460 | * @die_mem: a buffer for result DIE | 477 | * @die_mem: a buffer for result DIE |
461 | * | 478 | * |
462 | * Search an inlined function DIE which includes @addr. Stores the | 479 | * Search an inlined function DIE which includes @addr. Stores the |
463 | * DIE to @die_mem and returns it if found. Returns NULl if failed. | 480 | * DIE to @die_mem and returns it if found. Returns NULL if failed. |
464 | * If several inlined functions are expanded recursively, this trace | 481 | * If several inlined functions are expanded recursively, this trace |
465 | * it and returns deepest one. | 482 | * it down and returns deepest one. |
466 | */ | 483 | */ |
467 | Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | 484 | Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
468 | Dwarf_Die *die_mem) | 485 | Dwarf_Die *die_mem) |
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index 8658d41697d2..b4fe90c6cb2d 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h | |||
@@ -79,7 +79,11 @@ extern Dwarf_Die *die_find_child(Dwarf_Die *rt_die, | |||
79 | extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, | 79 | extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, |
80 | Dwarf_Die *die_mem); | 80 | Dwarf_Die *die_mem); |
81 | 81 | ||
82 | /* Search an inlined function including given address */ | 82 | /* Search the top inlined function including given address */ |
83 | extern Dwarf_Die *die_find_top_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | ||
84 | Dwarf_Die *die_mem); | ||
85 | |||
86 | /* Search the deepest inlined function including given address */ | ||
83 | extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | 87 | extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
84 | Dwarf_Die *die_mem); | 88 | Dwarf_Die *die_mem); |
85 | 89 | ||
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index ce69901176d8..c3e5a3b817ab 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -2768,6 +2768,18 @@ int perf_session__read_header(struct perf_session *session) | |||
2768 | if (perf_file_header__read(&f_header, header, fd) < 0) | 2768 | if (perf_file_header__read(&f_header, header, fd) < 0) |
2769 | return -EINVAL; | 2769 | return -EINVAL; |
2770 | 2770 | ||
2771 | /* | ||
2772 | * Sanity check that perf.data was written cleanly; data size is | ||
2773 | * initialized to 0 and updated only if the on_exit function is run. | ||
2774 | * If data size is still 0 then the file contains only partial | ||
2775 | * information. Just warn user and process it as much as it can. | ||
2776 | */ | ||
2777 | if (f_header.data.size == 0) { | ||
2778 | pr_warning("WARNING: The %s file's data size field is 0 which is unexpected.\n" | ||
2779 | "Was the 'perf record' command properly terminated?\n", | ||
2780 | session->filename); | ||
2781 | } | ||
2782 | |||
2771 | nr_attrs = f_header.attrs.size / f_header.attr_size; | 2783 | nr_attrs = f_header.attrs.size / f_header.attr_size; |
2772 | lseek(fd, f_header.attrs.offset, SEEK_SET); | 2784 | lseek(fd, f_header.attrs.offset, SEEK_SET); |
2773 | 2785 | ||
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 371476cb8ddc..c09e0a9fdf4c 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -1327,8 +1327,8 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, | |||
1327 | struct perf_probe_point *ppt) | 1327 | struct perf_probe_point *ppt) |
1328 | { | 1328 | { |
1329 | Dwarf_Die cudie, spdie, indie; | 1329 | Dwarf_Die cudie, spdie, indie; |
1330 | Dwarf_Addr _addr, baseaddr; | 1330 | Dwarf_Addr _addr = 0, baseaddr = 0; |
1331 | const char *fname = NULL, *func = NULL, *tmp; | 1331 | const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; |
1332 | int baseline = 0, lineno = 0, ret = 0; | 1332 | int baseline = 0, lineno = 0, ret = 0; |
1333 | 1333 | ||
1334 | /* Adjust address with bias */ | 1334 | /* Adjust address with bias */ |
@@ -1349,27 +1349,36 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, | |||
1349 | /* Find a corresponding function (name, baseline and baseaddr) */ | 1349 | /* Find a corresponding function (name, baseline and baseaddr) */ |
1350 | if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { | 1350 | if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { |
1351 | /* Get function entry information */ | 1351 | /* Get function entry information */ |
1352 | tmp = dwarf_diename(&spdie); | 1352 | func = basefunc = dwarf_diename(&spdie); |
1353 | if (!tmp || | 1353 | if (!func || |
1354 | dwarf_entrypc(&spdie, &baseaddr) != 0 || | 1354 | dwarf_entrypc(&spdie, &baseaddr) != 0 || |
1355 | dwarf_decl_line(&spdie, &baseline) != 0) | 1355 | dwarf_decl_line(&spdie, &baseline) != 0) { |
1356 | lineno = 0; | ||
1356 | goto post; | 1357 | goto post; |
1357 | func = tmp; | 1358 | } |
1358 | 1359 | ||
1359 | if (addr == (unsigned long)baseaddr) | 1360 | if (addr == (unsigned long)baseaddr) { |
1360 | /* Function entry - Relative line number is 0 */ | 1361 | /* Function entry - Relative line number is 0 */ |
1361 | lineno = baseline; | 1362 | lineno = baseline; |
1362 | else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, | 1363 | fname = dwarf_decl_file(&spdie); |
1363 | &indie)) { | 1364 | goto post; |
1365 | } | ||
1366 | |||
1367 | /* Track down the inline functions step by step */ | ||
1368 | while (die_find_top_inlinefunc(&spdie, (Dwarf_Addr)addr, | ||
1369 | &indie)) { | ||
1370 | /* There is an inline function */ | ||
1364 | if (dwarf_entrypc(&indie, &_addr) == 0 && | 1371 | if (dwarf_entrypc(&indie, &_addr) == 0 && |
1365 | _addr == addr) | 1372 | _addr == addr) { |
1366 | /* | 1373 | /* |
1367 | * addr is at an inline function entry. | 1374 | * addr is at an inline function entry. |
1368 | * In this case, lineno should be the call-site | 1375 | * In this case, lineno should be the call-site |
1369 | * line number. | 1376 | * line number. (overwrite lineinfo) |
1370 | */ | 1377 | */ |
1371 | lineno = die_get_call_lineno(&indie); | 1378 | lineno = die_get_call_lineno(&indie); |
1372 | else { | 1379 | fname = die_get_call_file(&indie); |
1380 | break; | ||
1381 | } else { | ||
1373 | /* | 1382 | /* |
1374 | * addr is in an inline function body. | 1383 | * addr is in an inline function body. |
1375 | * Since lineno points one of the lines | 1384 | * Since lineno points one of the lines |
@@ -1377,19 +1386,27 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, | |||
1377 | * be the entry line of the inline function. | 1386 | * be the entry line of the inline function. |
1378 | */ | 1387 | */ |
1379 | tmp = dwarf_diename(&indie); | 1388 | tmp = dwarf_diename(&indie); |
1380 | if (tmp && | 1389 | if (!tmp || |
1381 | dwarf_decl_line(&spdie, &baseline) == 0) | 1390 | dwarf_decl_line(&indie, &baseline) != 0) |
1382 | func = tmp; | 1391 | break; |
1392 | func = tmp; | ||
1393 | spdie = indie; | ||
1383 | } | 1394 | } |
1384 | } | 1395 | } |
1396 | /* Verify the lineno and baseline are in a same file */ | ||
1397 | tmp = dwarf_decl_file(&spdie); | ||
1398 | if (!tmp || strcmp(tmp, fname) != 0) | ||
1399 | lineno = 0; | ||
1385 | } | 1400 | } |
1386 | 1401 | ||
1387 | post: | 1402 | post: |
1388 | /* Make a relative line number or an offset */ | 1403 | /* Make a relative line number or an offset */ |
1389 | if (lineno) | 1404 | if (lineno) |
1390 | ppt->line = lineno - baseline; | 1405 | ppt->line = lineno - baseline; |
1391 | else if (func) | 1406 | else if (basefunc) { |
1392 | ppt->offset = addr - (unsigned long)baseaddr; | 1407 | ppt->offset = addr - (unsigned long)baseaddr; |
1408 | func = basefunc; | ||
1409 | } | ||
1393 | 1410 | ||
1394 | /* Duplicate strings */ | 1411 | /* Duplicate strings */ |
1395 | if (func) { | 1412 | if (func) { |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 70ffa41518f3..568b750c01f6 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -256,6 +256,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool) | |||
256 | tool->sample = process_event_sample_stub; | 256 | tool->sample = process_event_sample_stub; |
257 | if (tool->mmap == NULL) | 257 | if (tool->mmap == NULL) |
258 | tool->mmap = process_event_stub; | 258 | tool->mmap = process_event_stub; |
259 | if (tool->mmap2 == NULL) | ||
260 | tool->mmap2 = process_event_stub; | ||
259 | if (tool->comm == NULL) | 261 | if (tool->comm == NULL) |
260 | tool->comm = process_event_stub; | 262 | tool->comm = process_event_stub; |
261 | if (tool->fork == NULL) | 263 | if (tool->fork == NULL) |
@@ -1310,7 +1312,7 @@ int __perf_session__process_events(struct perf_session *session, | |||
1310 | file_offset = page_offset; | 1312 | file_offset = page_offset; |
1311 | head = data_offset - page_offset; | 1313 | head = data_offset - page_offset; |
1312 | 1314 | ||
1313 | if (data_offset + data_size < file_size) | 1315 | if (data_size && (data_offset + data_size < file_size)) |
1314 | file_size = data_offset + data_size; | 1316 | file_size = data_offset + data_size; |
1315 | 1317 | ||
1316 | progress_next = file_size / 16; | 1318 | progress_next = file_size / 16; |