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

Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf changes from Ingo Molnar:
"Kernel side changes:

- Consolidate the PMU interrupt-disabled code amongst architectures
(Vince Weaver)

- misc fixes

Tooling changes (new features, user visible changes):

- Add support for pagefault tracing in 'trace', please see multiple
examples in the changeset messages (Stanislav Fomichev).

- Add pagefault statistics in 'trace' (Stanislav Fomichev)

- Add header for columns in 'top' and 'report' TUI browsers (Jiri
Olsa)

- Add pagefault statistics in 'trace' (Stanislav Fomichev)

- Add IO mode into timechart command (Stanislav Fomichev)

- Fallback to syscalls:* when raw_syscalls:* is not available in the
perl and python perf scripts. (Daniel Bristot de Oliveira)

- Add --repeat global option to 'perf bench' to be used in benchmarks
such as the existing 'futex' one, that was modified to use it
instead of a local option. (Davidlohr Bueso)

- Fix fd -> pathname resolution in 'trace', be it using /proc or a
vfs_getname probe point. (Arnaldo Carvalho de Melo)

- Add suggestion of how to set perf_event_paranoid sysctl, to help
non-root users trying tools like 'trace' to get a working
environment. (Arnaldo Carvalho de Melo)

- Updates from trace-cmd for traceevent plugin_kvm plus args cleanup
(Steven Rostedt, Jan Kiszka)

- Support S/390 in 'perf kvm stat' (Alexander Yarygin)

Tooling infrastructure changes:

- Allow reserving a row for header purposes in the hists browser
(Arnaldo Carvalho de Melo)

- Various fixes and prep work related to supporting Intel PT (Adrian
Hunter)

- Introduce multiple debug variables control (Jiri Olsa)

- Add callchain and additional sample information for python scripts
(Joseph Schuchart)

- 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

- Include standard stringify macros in power pc code (Sukadev
Bhattiprolu)

Tooling cleanups:

- Convert open coded equivalents to asprintf() (Andy Shevchenko)

- Remove needless reassignments in 'trace' (Arnaldo Carvalho de Melo)

- Cache the is_exit syscall test in 'trace) (Arnaldo Carvalho de
Melo)

- No need to reimplement err() in 'perf bench sched-messaging', drop
barf(). (Davidlohr Bueso).

- Remove ev_name argument from perf_evsel__hists_browse, can be
obtained from the other parameters. (Jiri Olsa)

Tooling fixes:

- Fix memory leak in the 'sched-messaging' perf bench test.
(Davidlohr Bueso)

- The -o and -n 'perf bench mem' options are mutually exclusive, emit
error when both are specified. (Davidlohr Bueso)

- Fix scrollbar refresh row index in the ui browser, problem exposed
now that headers will be added and will be allowed to be switched
on/off. (Jiri Olsa)

- Handle the num array type in python properly (Sebastian Andrzej
Siewior)

- Fix wrong condition for allocation failure (Jiri Olsa)

- Adjust callchain based on DWARF debug info on powerpc (Sukadev
Bhattiprolu)

- Fix a risk for doing free on uninitialized pointer in traceevent
lib (Rickard Strandqvist)

- Update attr test with PERF_FLAG_FD_CLOEXEC flag (Jiri Olsa)

- Enable close-on-exec flag on perf file descriptor (Yann Droneaud)

- Fix build on gcc 4.4.7 (Arnaldo Carvalho de Melo)

- Event ordering fixes (Jiri Olsa)"

* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (123 commits)
Revert "perf tools: Fix jump label always changing during tracing"
perf tools: Fix perf usage string leftover
perf: Check permission only for parent tracepoint event
perf record: Store PERF_RECORD_FINISHED_ROUND only for nonempty rounds
perf record: Always force PERF_RECORD_FINISHED_ROUND event
perf inject: Add --kallsyms parameter
perf tools: Expose 'addr' functions so they can be reused
perf session: Fix accounting of ordered samples queue
perf powerpc: Include util/util.h and remove stringify macros
perf tools: Fix build on gcc 4.4.7
perf tools: Add thread parameter to vdso__dso_findnew()
perf tools: Add dso__type()
perf tools: Separate the VDSO map name from the VDSO dso name
perf tools: Add vdso__new()
perf machine: Fix the lifetime of the VDSO temporary file
perf tools: Group VDSO global variables into a structure
perf session: Add ability to skip 4GiB or more
perf session: Add ability to 'skip' a non-piped event stream
perf tools: Pass machine to vdso__dso_findnew()
perf tools: Add dso__data_size()
...

+3705 -947
+3 -4
arch/arc/kernel/perf_event.c
··· 99 99 struct hw_perf_event *hwc = &event->hw; 100 100 int ret; 101 101 102 - /* ARC 700 PMU does not support sampling events */ 103 - if (is_sampling_event(event)) 104 - return -ENOENT; 105 - 106 102 switch (event->attr.type) { 107 103 case PERF_TYPE_HARDWARE: 108 104 if (event->attr.config >= PERF_COUNT_HW_MAX) ··· 293 297 .stop = arc_pmu_stop, 294 298 .read = arc_pmu_read, 295 299 }; 300 + 301 + /* ARC 700 PMU does not support sampling events */ 302 + arc_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; 296 303 297 304 ret = perf_pmu_register(&arc_pmu->pmu, pdev->name, PERF_TYPE_RAW); 298 305
+7 -8
arch/blackfin/kernel/perf_event.c
··· 389 389 if (attr->exclude_hv || attr->exclude_idle) 390 390 return -EPERM; 391 391 392 - /* 393 - * All of the on-chip counters are "limited", in that they have 394 - * no interrupts, and are therefore unable to do sampling without 395 - * further work and timer assistance. 396 - */ 397 - if (hwc->sample_period) 398 - return -EINVAL; 399 - 400 392 ret = 0; 401 393 switch (attr->type) { 402 394 case PERF_TYPE_RAW: ··· 481 489 static int __init bfin_pmu_init(void) 482 490 { 483 491 int ret; 492 + 493 + /* 494 + * All of the on-chip counters are "limited", in that they have 495 + * no interrupts, and are therefore unable to do sampling without 496 + * further work and timer assistance. 497 + */ 498 + pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; 484 499 485 500 ret = perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW); 486 501 if (!ret)
+9 -10
arch/metag/kernel/perf/perf_event.c
··· 568 568 return -EINVAL; 569 569 570 570 /* 571 - * Early cores have "limited" counters - they have no overflow 572 - * interrupts - and so are unable to do sampling without extra work 573 - * and timer assistance. 574 - */ 575 - if (metag_pmu->max_period == 0) { 576 - if (hwc->sample_period) 577 - return -EINVAL; 578 - } 579 - 580 - /* 581 571 * Don't assign an index until the event is placed into the hardware. 582 572 * -1 signifies that we're still deciding where to put it. On SMP 583 573 * systems each core has its own set of counters, so we can't do any ··· 855 865 856 866 pr_info("enabled with %s PMU driver, %d counters available\n", 857 867 metag_pmu->name, metag_pmu->max_events); 868 + 869 + /* 870 + * Early cores have "limited" counters - they have no overflow 871 + * interrupts - and so are unable to do sampling without extra work 872 + * and timer assistance. 873 + */ 874 + if (metag_pmu->max_period == 0) { 875 + metag_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; 876 + } 858 877 859 878 /* Initialise the active events and reservation mutex */ 860 879 atomic_set(&metag_pmu->active_events, 0);
+4 -2
arch/powerpc/perf/hv-24x7.c
··· 387 387 event->attr.exclude_hv || 388 388 event->attr.exclude_idle || 389 389 event->attr.exclude_host || 390 - event->attr.exclude_guest || 391 - is_sampling_event(event)) /* no sampling */ 390 + event->attr.exclude_guest) 392 391 return -EINVAL; 393 392 394 393 /* no branch sampling */ ··· 511 512 hv_page_cache = kmem_cache_create("hv-page-4096", 4096, 4096, 0, NULL); 512 513 if (!hv_page_cache) 513 514 return -ENOMEM; 515 + 516 + /* sampling not supported */ 517 + h_24x7_pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; 514 518 515 519 r = perf_pmu_register(&h_24x7_pmu, h_24x7_pmu.name, -1); 516 520 if (r)
+4 -2
arch/powerpc/perf/hv-gpci.c
··· 210 210 event->attr.exclude_hv || 211 211 event->attr.exclude_idle || 212 212 event->attr.exclude_host || 213 - event->attr.exclude_guest || 214 - is_sampling_event(event)) /* no sampling */ 213 + event->attr.exclude_guest) 215 214 return -EINVAL; 216 215 217 216 /* no branch sampling */ ··· 282 283 hret); 283 284 return -ENODEV; 284 285 } 286 + 287 + /* sampling not supported */ 288 + h_gpci_pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; 285 289 286 290 r = perf_pmu_register(&h_gpci_pmu, h_gpci_pmu.name, -1); 287 291 if (r)
+1
arch/s390/include/uapi/asm/Kbuild
··· 16 16 header-y += ipcbuf.h 17 17 header-y += kvm.h 18 18 header-y += kvm_para.h 19 + header-y += kvm_perf.h 19 20 header-y += kvm_virtio.h 20 21 header-y += mman.h 21 22 header-y += monwriter.h
+25
arch/s390/include/uapi/asm/kvm_perf.h
··· 1 + /* 2 + * Definitions for perf-kvm on s390 3 + * 4 + * Copyright 2014 IBM Corp. 5 + * Author(s): Alexander Yarygin <yarygin@linux.vnet.ibm.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License (version 2 only) 9 + * as published by the Free Software Foundation. 10 + */ 11 + 12 + #ifndef __LINUX_KVM_PERF_S390_H 13 + #define __LINUX_KVM_PERF_S390_H 14 + 15 + #include <asm/sie.h> 16 + 17 + #define DECODE_STR_LEN 40 18 + 19 + #define VCPU_ID "id" 20 + 21 + #define KVM_ENTRY_TRACE "kvm:kvm_s390_sie_enter" 22 + #define KVM_EXIT_TRACE "kvm:kvm_s390_sie_exit" 23 + #define KVM_EXIT_REASON "icptcode" 24 + 25 + #endif
+6 -6
arch/s390/kernel/perf_cpum_cf.c
··· 411 411 case PERF_TYPE_HARDWARE: 412 412 case PERF_TYPE_HW_CACHE: 413 413 case PERF_TYPE_RAW: 414 - /* The CPU measurement counter facility does not have overflow 415 - * interrupts to do sampling. Sampling must be provided by 416 - * external means, for example, by timers. 417 - */ 418 - if (is_sampling_event(event)) 419 - return -ENOENT; 420 414 err = __hw_perf_event_init(event); 421 415 break; 422 416 default: ··· 674 680 "failed with rc=%i\n", rc); 675 681 goto out; 676 682 } 683 + 684 + /* The CPU measurement counter facility does not have overflow 685 + * interrupts to do sampling. Sampling must be provided by 686 + * external means, for example, by timers. 687 + */ 688 + cpumf_pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; 677 689 678 690 cpumf_pmu.attr_groups = cpumf_cf_event_group(); 679 691 rc = perf_pmu_register(&cpumf_pmu, "cpum_cf", PERF_TYPE_RAW);
+7 -8
arch/sh/kernel/perf_event.c
··· 129 129 return -ENODEV; 130 130 131 131 /* 132 - * All of the on-chip counters are "limited", in that they have 133 - * no interrupts, and are therefore unable to do sampling without 134 - * further work and timer assistance. 135 - */ 136 - if (hwc->sample_period) 137 - return -EINVAL; 138 - 139 - /* 140 132 * See if we need to reserve the counter. 141 133 * 142 134 * If no events are currently in use, then we have to take a ··· 383 391 sh_pmu = _pmu; 384 392 385 393 pr_info("Performance Events: %s support registered\n", _pmu->name); 394 + 395 + /* 396 + * All of the on-chip counters are "limited", in that they have 397 + * no interrupts, and are therefore unable to do sampling without 398 + * further work and timer assistance. 399 + */ 400 + pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; 386 401 387 402 WARN_ON(_pmu->num_events > MAX_HWEVENTS); 388 403
+1
arch/x86/include/uapi/asm/Kbuild
··· 22 22 header-y += ist.h 23 23 header-y += kvm.h 24 24 header-y += kvm_para.h 25 + header-y += kvm_perf.h 25 26 header-y += ldt.h 26 27 header-y += mce.h 27 28 header-y += mman.h
+16
arch/x86/include/uapi/asm/kvm_perf.h
··· 1 + #ifndef _ASM_X86_KVM_PERF_H 2 + #define _ASM_X86_KVM_PERF_H 3 + 4 + #include <asm/svm.h> 5 + #include <asm/vmx.h> 6 + #include <asm/kvm.h> 7 + 8 + #define DECODE_STR_LEN 20 9 + 10 + #define VCPU_ID "vcpu_id" 11 + 12 + #define KVM_ENTRY_TRACE "kvm:kvm_entry" 13 + #define KVM_EXIT_TRACE "kvm:kvm_exit" 14 + #define KVM_EXIT_REASON "exit_reason" 15 + 16 + #endif /* _ASM_X86_KVM_PERF_H */
+84 -27
arch/x86/kernel/cpu/perf_event_amd_uncore.c
··· 294 294 cpu_to_node(cpu)); 295 295 } 296 296 297 - static void amd_uncore_cpu_up_prepare(unsigned int cpu) 297 + static int amd_uncore_cpu_up_prepare(unsigned int cpu) 298 298 { 299 - struct amd_uncore *uncore; 299 + struct amd_uncore *uncore_nb = NULL, *uncore_l2; 300 300 301 301 if (amd_uncore_nb) { 302 - uncore = amd_uncore_alloc(cpu); 303 - uncore->cpu = cpu; 304 - uncore->num_counters = NUM_COUNTERS_NB; 305 - uncore->rdpmc_base = RDPMC_BASE_NB; 306 - uncore->msr_base = MSR_F15H_NB_PERF_CTL; 307 - uncore->active_mask = &amd_nb_active_mask; 308 - uncore->pmu = &amd_nb_pmu; 309 - *per_cpu_ptr(amd_uncore_nb, cpu) = uncore; 302 + uncore_nb = amd_uncore_alloc(cpu); 303 + if (!uncore_nb) 304 + goto fail; 305 + uncore_nb->cpu = cpu; 306 + uncore_nb->num_counters = NUM_COUNTERS_NB; 307 + uncore_nb->rdpmc_base = RDPMC_BASE_NB; 308 + uncore_nb->msr_base = MSR_F15H_NB_PERF_CTL; 309 + uncore_nb->active_mask = &amd_nb_active_mask; 310 + uncore_nb->pmu = &amd_nb_pmu; 311 + *per_cpu_ptr(amd_uncore_nb, cpu) = uncore_nb; 310 312 } 311 313 312 314 if (amd_uncore_l2) { 313 - uncore = amd_uncore_alloc(cpu); 314 - uncore->cpu = cpu; 315 - uncore->num_counters = NUM_COUNTERS_L2; 316 - uncore->rdpmc_base = RDPMC_BASE_L2; 317 - uncore->msr_base = MSR_F16H_L2I_PERF_CTL; 318 - uncore->active_mask = &amd_l2_active_mask; 319 - uncore->pmu = &amd_l2_pmu; 320 - *per_cpu_ptr(amd_uncore_l2, cpu) = uncore; 315 + uncore_l2 = amd_uncore_alloc(cpu); 316 + if (!uncore_l2) 317 + goto fail; 318 + uncore_l2->cpu = cpu; 319 + uncore_l2->num_counters = NUM_COUNTERS_L2; 320 + uncore_l2->rdpmc_base = RDPMC_BASE_L2; 321 + uncore_l2->msr_base = MSR_F16H_L2I_PERF_CTL; 322 + uncore_l2->active_mask = &amd_l2_active_mask; 323 + uncore_l2->pmu = &amd_l2_pmu; 324 + *per_cpu_ptr(amd_uncore_l2, cpu) = uncore_l2; 321 325 } 326 + 327 + return 0; 328 + 329 + fail: 330 + kfree(uncore_nb); 331 + return -ENOMEM; 322 332 } 323 333 324 334 static struct amd_uncore * ··· 451 441 452 442 if (!--uncore->refcnt) 453 443 kfree(uncore); 454 - *per_cpu_ptr(amd_uncore_nb, cpu) = NULL; 444 + *per_cpu_ptr(uncores, cpu) = NULL; 455 445 } 456 446 457 447 static void amd_uncore_cpu_dead(unsigned int cpu) ··· 471 461 472 462 switch (action & ~CPU_TASKS_FROZEN) { 473 463 case CPU_UP_PREPARE: 474 - amd_uncore_cpu_up_prepare(cpu); 464 + if (amd_uncore_cpu_up_prepare(cpu)) 465 + return notifier_from_errno(-ENOMEM); 475 466 break; 476 467 477 468 case CPU_STARTING: ··· 512 501 amd_uncore_cpu_online(cpu); 513 502 } 514 503 504 + static void cleanup_cpu_online(void *dummy) 505 + { 506 + unsigned int cpu = smp_processor_id(); 507 + 508 + amd_uncore_cpu_dead(cpu); 509 + } 510 + 515 511 static int __init amd_uncore_init(void) 516 512 { 517 - unsigned int cpu; 513 + unsigned int cpu, cpu2; 518 514 int ret = -ENODEV; 519 515 520 516 if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) 521 - return -ENODEV; 517 + goto fail_nodev; 522 518 523 519 if (!cpu_has_topoext) 524 - return -ENODEV; 520 + goto fail_nodev; 525 521 526 522 if (cpu_has_perfctr_nb) { 527 523 amd_uncore_nb = alloc_percpu(struct amd_uncore *); 528 - perf_pmu_register(&amd_nb_pmu, amd_nb_pmu.name, -1); 524 + if (!amd_uncore_nb) { 525 + ret = -ENOMEM; 526 + goto fail_nb; 527 + } 528 + ret = perf_pmu_register(&amd_nb_pmu, amd_nb_pmu.name, -1); 529 + if (ret) 530 + goto fail_nb; 529 531 530 532 printk(KERN_INFO "perf: AMD NB counters detected\n"); 531 533 ret = 0; ··· 546 522 547 523 if (cpu_has_perfctr_l2) { 548 524 amd_uncore_l2 = alloc_percpu(struct amd_uncore *); 549 - perf_pmu_register(&amd_l2_pmu, amd_l2_pmu.name, -1); 525 + if (!amd_uncore_l2) { 526 + ret = -ENOMEM; 527 + goto fail_l2; 528 + } 529 + ret = perf_pmu_register(&amd_l2_pmu, amd_l2_pmu.name, -1); 530 + if (ret) 531 + goto fail_l2; 550 532 551 533 printk(KERN_INFO "perf: AMD L2I counters detected\n"); 552 534 ret = 0; 553 535 } 554 536 555 537 if (ret) 556 - return -ENODEV; 538 + goto fail_nodev; 557 539 558 540 cpu_notifier_register_begin(); 559 541 560 542 /* init cpus already online before registering for hotplug notifier */ 561 543 for_each_online_cpu(cpu) { 562 - amd_uncore_cpu_up_prepare(cpu); 544 + ret = amd_uncore_cpu_up_prepare(cpu); 545 + if (ret) 546 + goto fail_online; 563 547 smp_call_function_single(cpu, init_cpu_already_online, NULL, 1); 564 548 } 565 549 ··· 575 543 cpu_notifier_register_done(); 576 544 577 545 return 0; 546 + 547 + 548 + fail_online: 549 + for_each_online_cpu(cpu2) { 550 + if (cpu2 == cpu) 551 + break; 552 + smp_call_function_single(cpu, cleanup_cpu_online, NULL, 1); 553 + } 554 + cpu_notifier_register_done(); 555 + 556 + /* amd_uncore_nb/l2 should have been freed by cleanup_cpu_online */ 557 + amd_uncore_nb = amd_uncore_l2 = NULL; 558 + if (cpu_has_perfctr_l2) 559 + perf_pmu_unregister(&amd_l2_pmu); 560 + fail_l2: 561 + if (cpu_has_perfctr_nb) 562 + perf_pmu_unregister(&amd_nb_pmu); 563 + if (amd_uncore_l2) 564 + free_percpu(amd_uncore_l2); 565 + fail_nb: 566 + if (amd_uncore_nb) 567 + free_percpu(amd_uncore_nb); 568 + 569 + fail_nodev: 570 + return ret; 578 571 } 579 572 device_initcall(amd_uncore_init);
+1 -4
arch/x86/kernel/cpu/perf_event_intel_uncore.c
··· 2947 2947 * extra registers. If we failed to take an extra 2948 2948 * register, try the alternative. 2949 2949 */ 2950 - if (idx % 2) 2951 - idx--; 2952 - else 2953 - idx++; 2950 + idx ^= 1; 2954 2951 if (idx != reg1->idx % 6) { 2955 2952 if (idx == 2) 2956 2953 config1 >>= 8;
+7 -1
kernel/events/core.c
··· 5266 5266 5267 5267 goto got_name; 5268 5268 } else { 5269 + if (vma->vm_ops && vma->vm_ops->name) { 5270 + name = (char *) vma->vm_ops->name(vma); 5271 + if (name) 5272 + goto cpy_name; 5273 + } 5274 + 5269 5275 name = (char *)arch_vma_name(vma); 5270 5276 if (name) 5271 5277 goto cpy_name; ··· 7810 7804 /* 7811 7805 * Initialize the perf_event context in task_struct 7812 7806 */ 7813 - int perf_event_init_context(struct task_struct *child, int ctxn) 7807 + static int perf_event_init_context(struct task_struct *child, int ctxn) 7814 7808 { 7815 7809 struct perf_event_context *child_ctx, *parent_ctx; 7816 7810 struct perf_event_context *cloned_ctx;
+12
kernel/trace/trace_event_perf.c
··· 30 30 return ret; 31 31 } 32 32 33 + /* 34 + * We checked and allowed to create parent, 35 + * allow children without checking. 36 + */ 37 + if (p_event->parent) 38 + return 0; 39 + 40 + /* 41 + * It's ok to check current process (owner) permissions in here, 42 + * because code below is called only via perf_event_open syscall. 43 + */ 44 + 33 45 /* The ftrace function trace is allowed only for root. */ 34 46 if (ftrace_event_is_function(tp_event)) { 35 47 if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
+3 -3
tools/lib/traceevent/event-parse.c
··· 2395 2395 { 2396 2396 struct print_arg *field; 2397 2397 enum event_type type; 2398 - char *token; 2398 + char *token = NULL; 2399 2399 2400 2400 memset(arg, 0, sizeof(*arg)); 2401 2401 arg->type = PRINT_FLAGS; ··· 2448 2448 { 2449 2449 struct print_arg *field; 2450 2450 enum event_type type; 2451 - char *token; 2451 + char *token = NULL; 2452 2452 2453 2453 memset(arg, 0, sizeof(*arg)); 2454 2454 arg->type = PRINT_SYMBOL; ··· 2487 2487 { 2488 2488 struct print_arg *field; 2489 2489 enum event_type type; 2490 - char *token; 2490 + char *token = NULL; 2491 2491 2492 2492 memset(arg, 0, sizeof(*arg)); 2493 2493 arg->type = PRINT_HEX;
+1 -2
tools/lib/traceevent/plugin_cfg80211.c
··· 5 5 #include "event-parse.h" 6 6 7 7 static unsigned long long 8 - process___le16_to_cpup(struct trace_seq *s, 9 - unsigned long long *args) 8 + process___le16_to_cpup(struct trace_seq *s, unsigned long long *args) 10 9 { 11 10 uint16_t *val = (uint16_t *) (unsigned long) args[0]; 12 11 return val ? (long long) le16toh(*val) : 0;
+2 -4
tools/lib/traceevent/plugin_jbd2.c
··· 30 30 #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) 31 31 32 32 static unsigned long long 33 - process_jbd2_dev_to_name(struct trace_seq *s, 34 - unsigned long long *args) 33 + process_jbd2_dev_to_name(struct trace_seq *s, unsigned long long *args) 35 34 { 36 35 unsigned int dev = args[0]; 37 36 ··· 39 40 } 40 41 41 42 static unsigned long long 42 - process_jiffies_to_msecs(struct trace_seq *s, 43 - unsigned long long *args) 43 + process_jiffies_to_msecs(struct trace_seq *s, unsigned long long *args) 44 44 { 45 45 unsigned long long jiffies = args[0]; 46 46
+56 -8
tools/lib/traceevent/plugin_kvm.c
··· 240 240 for (i = 0; strings[i].val >= 0; i++) 241 241 if (strings[i].val == val) 242 242 break; 243 - if (strings[i].str) 244 - return strings[i].str; 245 - return "UNKNOWN"; 243 + 244 + return strings[i].str; 246 245 } 247 246 248 - static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record, 249 - struct event_format *event, void *context) 247 + static int print_exit_reason(struct trace_seq *s, struct pevent_record *record, 248 + struct event_format *event, const char *field) 250 249 { 251 250 unsigned long long isa; 252 251 unsigned long long val; 253 - unsigned long long info1 = 0, info2 = 0; 252 + const char *reason; 254 253 255 - if (pevent_get_field_val(s, event, "exit_reason", record, &val, 1) < 0) 254 + if (pevent_get_field_val(s, event, field, record, &val, 1) < 0) 256 255 return -1; 257 256 258 257 if (pevent_get_field_val(s, event, "isa", record, &isa, 0) < 0) 259 258 isa = 1; 260 259 261 - trace_seq_printf(s, "reason %s", find_exit_reason(isa, val)); 260 + reason = find_exit_reason(isa, val); 261 + if (reason) 262 + trace_seq_printf(s, "reason %s", reason); 263 + else 264 + trace_seq_printf(s, "reason UNKNOWN (%llu)", val); 265 + return 0; 266 + } 267 + 268 + static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record, 269 + struct event_format *event, void *context) 270 + { 271 + unsigned long long info1 = 0, info2 = 0; 272 + 273 + if (print_exit_reason(s, record, event, "exit_reason") < 0) 274 + return -1; 262 275 263 276 pevent_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1); 264 277 ··· 324 311 trace_seq_printf(s, "%llx:%llx: %s%s", csbase, rip, disasm, 325 312 failed ? " FAIL" : ""); 326 313 return 0; 314 + } 315 + 316 + 317 + static int kvm_nested_vmexit_inject_handler(struct trace_seq *s, struct pevent_record *record, 318 + struct event_format *event, void *context) 319 + { 320 + if (print_exit_reason(s, record, event, "exit_code") < 0) 321 + return -1; 322 + 323 + pevent_print_num_field(s, " info1 %llx", event, "exit_info1", record, 1); 324 + pevent_print_num_field(s, " info2 %llx", event, "exit_info2", record, 1); 325 + pevent_print_num_field(s, " int_info %llx", event, "exit_int_info", record, 1); 326 + pevent_print_num_field(s, " int_info_err %llx", event, "exit_int_info_err", record, 1); 327 + 328 + return 0; 329 + } 330 + 331 + static int kvm_nested_vmexit_handler(struct trace_seq *s, struct pevent_record *record, 332 + struct event_format *event, void *context) 333 + { 334 + pevent_print_num_field(s, "rip %llx ", event, "rip", record, 1); 335 + 336 + return kvm_nested_vmexit_inject_handler(s, record, event, context); 327 337 } 328 338 329 339 union kvm_mmu_page_role { ··· 445 409 pevent_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", 446 410 kvm_emulate_insn_handler, NULL); 447 411 412 + pevent_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit", 413 + kvm_nested_vmexit_handler, NULL); 414 + 415 + pevent_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject", 416 + kvm_nested_vmexit_inject_handler, NULL); 417 + 448 418 pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", 449 419 kvm_mmu_get_page_handler, NULL); 450 420 ··· 484 442 485 443 pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", 486 444 kvm_emulate_insn_handler, NULL); 445 + 446 + pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit", 447 + kvm_nested_vmexit_handler, NULL); 448 + 449 + pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject", 450 + kvm_nested_vmexit_inject_handler, NULL); 487 451 488 452 pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", 489 453 kvm_mmu_get_page_handler, NULL);
+4
tools/perf/Documentation/perf-bench.txt
··· 16 16 17 17 COMMON OPTIONS 18 18 -------------- 19 + -r:: 20 + --repeat=:: 21 + Specify amount of times to repeat the run (default 10). 22 + 19 23 -f:: 20 24 --format=:: 21 25 Specify format style.
+3
tools/perf/Documentation/perf-inject.txt
··· 41 41 tasks slept. sched_switch contains a callchain where a task slept and 42 42 sched_stat contains a timeslice how long a task slept. 43 43 44 + --kallsyms=<file>:: 45 + kallsyms pathname 46 + 44 47 SEE ALSO 45 48 -------- 46 49 linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
+9 -7
tools/perf/Documentation/perf-kvm.txt
··· 51 51 'perf kvm stat <command>' to run a command and gather performance counter 52 52 statistics. 53 53 Especially, perf 'kvm stat record/report' generates a statistical analysis 54 - of KVM events. Currently, vmexit, mmio and ioport events are supported. 55 - 'perf kvm stat record <command>' records kvm events and the events between 56 - start and end <command>. 54 + of KVM events. Currently, vmexit, mmio (x86 only) and ioport (x86 only) 55 + events are supported. 'perf kvm stat record <command>' records kvm events 56 + and the events between start and end <command>. 57 57 And this command produces a file which contains tracing results of kvm 58 58 events. 59 59 ··· 103 103 analyze events which occures on this vcpu. (default: all vcpus) 104 104 105 105 --event=<value>:: 106 - event to be analyzed. Possible values: vmexit, mmio, ioport. 107 - (default: vmexit) 106 + event to be analyzed. Possible values: vmexit, mmio (x86 only), 107 + ioport (x86 only). (default: vmexit) 108 108 -k:: 109 109 --key=<value>:: 110 110 Sorting key. Possible values: sample (default, sort by samples ··· 138 138 139 139 140 140 --event=<value>:: 141 - event to be analyzed. Possible values: vmexit, mmio, ioport. 141 + event to be analyzed. Possible values: vmexit, 142 + mmio (x86 only), ioport (x86 only). 142 143 (default: vmexit) 143 144 144 145 -k:: ··· 148 147 number), time (sort by average time). 149 148 150 149 --duration=<value>:: 151 - Show events other than HLT that take longer than duration usecs. 150 + Show events other than HLT (x86 only) or Wait state (s390 only) 151 + that take longer than duration usecs. 152 152 153 153 SEE ALSO 154 154 --------
+36 -2
tools/perf/Documentation/perf-timechart.txt
··· 15 15 There are two variants of perf timechart: 16 16 17 17 'perf timechart record <command>' to record the system level events 18 - of an arbitrary workload. 18 + of an arbitrary workload. By default timechart records only scheduler 19 + and CPU events (task switches, running times, CPU power states, etc), 20 + but it's possible to record IO (disk, network) activity using -I argument. 19 21 20 22 'perf timechart' to turn a trace into a Scalable Vector Graphics file, 21 - that can be viewed with popular SVG viewers such as 'Inkscape'. 23 + that can be viewed with popular SVG viewers such as 'Inkscape'. Depending 24 + on the events in the perf.data file, timechart will contain scheduler/cpu 25 + events or IO events. 26 + 27 + In IO mode, every bar has two charts: upper and lower. 28 + Upper bar shows incoming events (disk reads, ingress network packets). 29 + Lower bar shows outgoing events (disk writes, egress network packets). 30 + There are also poll bars which show how much time application spent 31 + in poll/epoll/select syscalls. 22 32 23 33 TIMECHART OPTIONS 24 34 ----------------- ··· 64 54 duration or tasks with given name. If number is given it's interpreted 65 55 as number of nanoseconds. If non-numeric string is given it's 66 56 interpreted as task name. 57 + --io-skip-eagain:: 58 + Don't draw EAGAIN IO events. 59 + --io-min-time=<nsecs>:: 60 + Draw small events as if they lasted min-time. Useful when you need 61 + to see very small and fast IO. It's possible to specify ms or us 62 + suffix to specify time in milliseconds or microseconds. 63 + Default value is 1ms. 64 + --io-merge-dist=<nsecs>:: 65 + Merge events that are merge-dist nanoseconds apart. 66 + Reduces number of figures on the SVG and makes it more render-friendly. 67 + It's possible to specify ms or us suffix to specify time in 68 + milliseconds or microseconds. 69 + Default value is 1us. 67 70 68 71 RECORD OPTIONS 69 72 -------------- ··· 86 63 -T:: 87 64 --tasks-only:: 88 65 Record only tasks-related events 66 + -I:: 67 + --io-only:: 68 + Record only io-related events 89 69 -g:: 90 70 --callchain:: 91 71 Do call-graph (stack chain/backtrace) recording ··· 112 86 then generate timechart and highlight 'gcc' tasks: 113 87 114 88 $ perf timechart --highlight gcc 89 + 90 + Record system-wide IO events: 91 + 92 + $ perf timechart record -I 93 + 94 + then generate timechart: 95 + 96 + $ perf timechart 115 97 116 98 SEE ALSO 117 99 --------
+46
tools/perf/Documentation/perf-trace.txt
··· 107 107 Show tool stats such as number of times fd->pathname was discovered thru 108 108 hooking the open syscall return + vfs_getname or via reading /proc/pid/fd, etc. 109 109 110 + -F=[all|min|maj]:: 111 + --pf=[all|min|maj]:: 112 + Trace pagefaults. Optionally, you can specify whether you want minor, 113 + major or all pagefaults. Default value is maj. 114 + 115 + --syscalls:: 116 + Trace system calls. This options is enabled by default. 117 + 118 + PAGEFAULTS 119 + ---------- 120 + 121 + When tracing pagefaults, the format of the trace is as follows: 122 + 123 + <min|maj>fault [<ip.symbol>+<ip.offset>] => <addr.dso@addr.offset> (<map type><addr level>). 124 + 125 + - min/maj indicates whether fault event is minor or major; 126 + - ip.symbol shows symbol for instruction pointer (the code that generated the 127 + fault); if no debug symbols available, perf trace will print raw IP; 128 + - addr.dso shows DSO for the faulted address; 129 + - map type is either 'd' for non-executable maps or 'x' for executable maps; 130 + - addr level is either 'k' for kernel dso or '.' for user dso. 131 + 132 + For symbols resolution you may need to install debugging symbols. 133 + 134 + Please be aware that duration is currently always 0 and doesn't reflect actual 135 + time it took for fault to be handled! 136 + 137 + When --verbose specified, perf trace tries to print all available information 138 + for both IP and fault address in the form of dso@symbol+offset. 139 + 140 + EXAMPLES 141 + -------- 142 + 143 + Trace only major pagefaults: 144 + 145 + $ perf trace --no-syscalls -F 146 + 147 + Trace syscalls, major and minor pagefaults: 148 + 149 + $ perf trace -F all 150 + 151 + 1416.547 ( 0.000 ms): python/20235 majfault [CRYPTO_push_info_+0x0] => /lib/x86_64-linux-gnu/libcrypto.so.1.0.0@0x61be0 (x.) 152 + 153 + As you can see, there was major pagefault in python process, from 154 + CRYPTO_push_info_ routine which faulted somewhere in libcrypto.so. 155 + 110 156 SEE ALSO 111 157 -------- 112 158 linkperf:perf-record[1], linkperf:perf-script[1]
+9 -1
tools/perf/Documentation/perf.txt
··· 8 8 SYNOPSIS 9 9 -------- 10 10 [verse] 11 - 'perf' [--version] [--help] COMMAND [ARGS] 11 + 'perf' [--version] [--help] [OPTIONS] COMMAND [ARGS] 12 + 13 + OPTIONS 14 + ------- 15 + --debug:: 16 + Setup debug variable (just verbose for now) in value 17 + range (0, 10). Use like: 18 + --debug verbose # sets verbose = 1 19 + --debug verbose=2 # sets verbose = 2 12 20 13 21 DESCRIPTION 14 22 -----------
+3
tools/perf/MANIFEST
··· 37 37 arch/x86/include/uapi/asm/svm.h 38 38 arch/x86/include/uapi/asm/vmx.h 39 39 arch/x86/include/uapi/asm/kvm.h 40 + arch/x86/include/uapi/asm/kvm_perf.h 41 + arch/s390/include/uapi/asm/sie.h 42 + arch/s390/include/uapi/asm/kvm_perf.h
+4
tools/perf/Makefile.perf
··· 295 295 LIB_H += util/perf_regs.h 296 296 LIB_H += util/unwind.h 297 297 LIB_H += util/vdso.h 298 + LIB_H += util/tsc.h 298 299 LIB_H += ui/helpline.h 299 300 LIB_H += ui/progress.h 300 301 LIB_H += ui/util.h 301 302 LIB_H += ui/ui.h 302 303 LIB_H += util/data.h 304 + LIB_H += util/kvm-stat.h 303 305 304 306 LIB_OBJS += $(OUTPUT)util/abspath.o 305 307 LIB_OBJS += $(OUTPUT)util/alias.o ··· 375 373 LIB_OBJS += $(OUTPUT)util/record.o 376 374 LIB_OBJS += $(OUTPUT)util/srcline.o 377 375 LIB_OBJS += $(OUTPUT)util/data.o 376 + LIB_OBJS += $(OUTPUT)util/tsc.o 377 + LIB_OBJS += $(OUTPUT)util/cloexec.o 378 378 379 379 LIB_OBJS += $(OUTPUT)ui/setup.o 380 380 LIB_OBJS += $(OUTPUT)ui/helpline.o
+1
tools/perf/arch/powerpc/Makefile
··· 3 3 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o 4 4 endif 5 5 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o 6 + LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/skip-callchain-idx.o
+1 -3
tools/perf/arch/powerpc/util/header.c
··· 5 5 #include <string.h> 6 6 7 7 #include "../../util/header.h" 8 - 9 - #define __stringify_1(x) #x 10 - #define __stringify(x) __stringify_1(x) 8 + #include "../../util/util.h" 11 9 12 10 #define mfspr(rn) ({unsigned long rval; \ 13 11 asm volatile("mfspr %0," __stringify(rn) \
+266
tools/perf/arch/powerpc/util/skip-callchain-idx.c
··· 1 + /* 2 + * Use DWARF Debug information to skip unnecessary callchain entries. 3 + * 4 + * Copyright (C) 2014 Sukadev Bhattiprolu, IBM Corporation. 5 + * Copyright (C) 2014 Ulrich Weigand, IBM Corporation. 6 + * 7 + * This program is free software; you can redistribute it and/or 8 + * modify it under the terms of the GNU General Public License 9 + * as published by the Free Software Foundation; either version 10 + * 2 of the License, or (at your option) any later version. 11 + */ 12 + #include <inttypes.h> 13 + #include <dwarf.h> 14 + #include <elfutils/libdwfl.h> 15 + 16 + #include "util/thread.h" 17 + #include "util/callchain.h" 18 + 19 + /* 20 + * When saving the callchain on Power, the kernel conservatively saves 21 + * excess entries in the callchain. A few of these entries are needed 22 + * in some cases but not others. If the unnecessary entries are not 23 + * ignored, we end up with duplicate arcs in the call-graphs. Use 24 + * DWARF debug information to skip over any unnecessary callchain 25 + * entries. 26 + * 27 + * See function header for arch_adjust_callchain() below for more details. 28 + * 29 + * The libdwfl code in this file is based on code from elfutils 30 + * (libdwfl/argp-std.c, libdwfl/tests/addrcfi.c, etc). 31 + */ 32 + static char *debuginfo_path; 33 + 34 + static const Dwfl_Callbacks offline_callbacks = { 35 + .debuginfo_path = &debuginfo_path, 36 + .find_debuginfo = dwfl_standard_find_debuginfo, 37 + .section_address = dwfl_offline_section_address, 38 + }; 39 + 40 + 41 + /* 42 + * Use the DWARF expression for the Call-frame-address and determine 43 + * if return address is in LR and if a new frame was allocated. 44 + */ 45 + static int check_return_reg(int ra_regno, Dwarf_Frame *frame) 46 + { 47 + Dwarf_Op ops_mem[2]; 48 + Dwarf_Op dummy; 49 + Dwarf_Op *ops = &dummy; 50 + size_t nops; 51 + int result; 52 + 53 + result = dwarf_frame_register(frame, ra_regno, ops_mem, &ops, &nops); 54 + if (result < 0) { 55 + pr_debug("dwarf_frame_register() %s\n", dwarf_errmsg(-1)); 56 + return -1; 57 + } 58 + 59 + /* 60 + * Check if return address is on the stack. 61 + */ 62 + if (nops != 0 || ops != NULL) 63 + return 0; 64 + 65 + /* 66 + * Return address is in LR. Check if a frame was allocated 67 + * but not-yet used. 68 + */ 69 + result = dwarf_frame_cfa(frame, &ops, &nops); 70 + if (result < 0) { 71 + pr_debug("dwarf_frame_cfa() returns %d, %s\n", result, 72 + dwarf_errmsg(-1)); 73 + return -1; 74 + } 75 + 76 + /* 77 + * If call frame address is in r1, no new frame was allocated. 78 + */ 79 + if (nops == 1 && ops[0].atom == DW_OP_bregx && ops[0].number == 1 && 80 + ops[0].number2 == 0) 81 + return 1; 82 + 83 + /* 84 + * A new frame was allocated but has not yet been used. 85 + */ 86 + return 2; 87 + } 88 + 89 + /* 90 + * Get the DWARF frame from the .eh_frame section. 91 + */ 92 + static Dwarf_Frame *get_eh_frame(Dwfl_Module *mod, Dwarf_Addr pc) 93 + { 94 + int result; 95 + Dwarf_Addr bias; 96 + Dwarf_CFI *cfi; 97 + Dwarf_Frame *frame; 98 + 99 + cfi = dwfl_module_eh_cfi(mod, &bias); 100 + if (!cfi) { 101 + pr_debug("%s(): no CFI - %s\n", __func__, dwfl_errmsg(-1)); 102 + return NULL; 103 + } 104 + 105 + result = dwarf_cfi_addrframe(cfi, pc, &frame); 106 + if (result) { 107 + pr_debug("%s(): %s\n", __func__, dwfl_errmsg(-1)); 108 + return NULL; 109 + } 110 + 111 + return frame; 112 + } 113 + 114 + /* 115 + * Get the DWARF frame from the .debug_frame section. 116 + */ 117 + static Dwarf_Frame *get_dwarf_frame(Dwfl_Module *mod, Dwarf_Addr pc) 118 + { 119 + Dwarf_CFI *cfi; 120 + Dwarf_Addr bias; 121 + Dwarf_Frame *frame; 122 + int result; 123 + 124 + cfi = dwfl_module_dwarf_cfi(mod, &bias); 125 + if (!cfi) { 126 + pr_debug("%s(): no CFI - %s\n", __func__, dwfl_errmsg(-1)); 127 + return NULL; 128 + } 129 + 130 + result = dwarf_cfi_addrframe(cfi, pc, &frame); 131 + if (result) { 132 + pr_debug("%s(): %s\n", __func__, dwfl_errmsg(-1)); 133 + return NULL; 134 + } 135 + 136 + return frame; 137 + } 138 + 139 + /* 140 + * Return: 141 + * 0 if return address for the program counter @pc is on stack 142 + * 1 if return address is in LR and no new stack frame was allocated 143 + * 2 if return address is in LR and a new frame was allocated (but not 144 + * yet used) 145 + * -1 in case of errors 146 + */ 147 + static int check_return_addr(const char *exec_file, Dwarf_Addr pc) 148 + { 149 + int rc = -1; 150 + Dwfl *dwfl; 151 + Dwfl_Module *mod; 152 + Dwarf_Frame *frame; 153 + int ra_regno; 154 + Dwarf_Addr start = pc; 155 + Dwarf_Addr end = pc; 156 + bool signalp; 157 + 158 + dwfl = dwfl_begin(&offline_callbacks); 159 + if (!dwfl) { 160 + pr_debug("dwfl_begin() failed: %s\n", dwarf_errmsg(-1)); 161 + return -1; 162 + } 163 + 164 + if (dwfl_report_offline(dwfl, "", exec_file, -1) == NULL) { 165 + pr_debug("dwfl_report_offline() failed %s\n", dwarf_errmsg(-1)); 166 + goto out; 167 + } 168 + 169 + mod = dwfl_addrmodule(dwfl, pc); 170 + if (!mod) { 171 + pr_debug("dwfl_addrmodule() failed, %s\n", dwarf_errmsg(-1)); 172 + goto out; 173 + } 174 + 175 + /* 176 + * To work with split debug info files (eg: glibc), check both 177 + * .eh_frame and .debug_frame sections of the ELF header. 178 + */ 179 + frame = get_eh_frame(mod, pc); 180 + if (!frame) { 181 + frame = get_dwarf_frame(mod, pc); 182 + if (!frame) 183 + goto out; 184 + } 185 + 186 + ra_regno = dwarf_frame_info(frame, &start, &end, &signalp); 187 + if (ra_regno < 0) { 188 + pr_debug("Return address register unavailable: %s\n", 189 + dwarf_errmsg(-1)); 190 + goto out; 191 + } 192 + 193 + rc = check_return_reg(ra_regno, frame); 194 + 195 + out: 196 + dwfl_end(dwfl); 197 + return rc; 198 + } 199 + 200 + /* 201 + * The callchain saved by the kernel always includes the link register (LR). 202 + * 203 + * 0: PERF_CONTEXT_USER 204 + * 1: Program counter (Next instruction pointer) 205 + * 2: LR value 206 + * 3: Caller's caller 207 + * 4: ... 208 + * 209 + * The value in LR is only needed when it holds a return address. If the 210 + * return address is on the stack, we should ignore the LR value. 211 + * 212 + * Further, when the return address is in the LR, if a new frame was just 213 + * allocated but the LR was not saved into it, then the LR contains the 214 + * caller, slot 4: contains the caller's caller and the contents of slot 3: 215 + * (chain->ips[3]) is undefined and must be ignored. 216 + * 217 + * Use DWARF debug information to determine if any entries need to be skipped. 218 + * 219 + * Return: 220 + * index: of callchain entry that needs to be ignored (if any) 221 + * -1 if no entry needs to be ignored or in case of errors 222 + */ 223 + int arch_skip_callchain_idx(struct machine *machine, struct thread *thread, 224 + struct ip_callchain *chain) 225 + { 226 + struct addr_location al; 227 + struct dso *dso = NULL; 228 + int rc; 229 + u64 ip; 230 + u64 skip_slot = -1; 231 + 232 + if (chain->nr < 3) 233 + return skip_slot; 234 + 235 + ip = chain->ips[2]; 236 + 237 + thread__find_addr_location(thread, machine, PERF_RECORD_MISC_USER, 238 + MAP__FUNCTION, ip, &al); 239 + 240 + if (al.map) 241 + dso = al.map->dso; 242 + 243 + if (!dso) { 244 + pr_debug("%" PRIx64 " dso is NULL\n", ip); 245 + return skip_slot; 246 + } 247 + 248 + rc = check_return_addr(dso->long_name, ip); 249 + 250 + pr_debug("DSO %s, nr %" PRIx64 ", ip 0x%" PRIx64 "rc %d\n", 251 + dso->long_name, chain->nr, ip, rc); 252 + 253 + if (rc == 0) { 254 + /* 255 + * Return address on stack. Ignore LR value in callchain 256 + */ 257 + skip_slot = 2; 258 + } else if (rc == 2) { 259 + /* 260 + * New frame allocated but return address still in LR. 261 + * Ignore the caller's caller entry in callchain. 262 + */ 263 + skip_slot = 3; 264 + } 265 + return skip_slot; 266 + }
+3
tools/perf/arch/s390/Makefile
··· 2 2 PERF_HAVE_DWARF_REGS := 1 3 3 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o 4 4 endif 5 + LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o 6 + HAVE_KVM_STAT_SUPPORT := 1 7 + LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/kvm-stat.o
+28
tools/perf/arch/s390/util/header.c
··· 1 + /* 2 + * Implementation of get_cpuid(). 3 + * 4 + * Copyright 2014 IBM Corp. 5 + * Author(s): Alexander Yarygin <yarygin@linux.vnet.ibm.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License (version 2 only) 9 + * as published by the Free Software Foundation. 10 + */ 11 + 12 + #include <sys/types.h> 13 + #include <unistd.h> 14 + #include <stdio.h> 15 + #include <string.h> 16 + 17 + #include "../../util/header.h" 18 + 19 + int get_cpuid(char *buffer, size_t sz) 20 + { 21 + const char *cpuid = "IBM/S390"; 22 + 23 + if (strlen(cpuid) + 1 > sz) 24 + return -1; 25 + 26 + strcpy(buffer, cpuid); 27 + return 0; 28 + }
+105
tools/perf/arch/s390/util/kvm-stat.c
··· 1 + /* 2 + * Arch specific functions for perf kvm stat. 3 + * 4 + * Copyright 2014 IBM Corp. 5 + * Author(s): Alexander Yarygin <yarygin@linux.vnet.ibm.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License (version 2 only) 9 + * as published by the Free Software Foundation. 10 + */ 11 + 12 + #include "../../util/kvm-stat.h" 13 + #include <asm/kvm_perf.h> 14 + 15 + define_exit_reasons_table(sie_exit_reasons, sie_intercept_code); 16 + define_exit_reasons_table(sie_icpt_insn_codes, icpt_insn_codes); 17 + define_exit_reasons_table(sie_sigp_order_codes, sigp_order_codes); 18 + define_exit_reasons_table(sie_diagnose_codes, diagnose_codes); 19 + define_exit_reasons_table(sie_icpt_prog_codes, icpt_prog_codes); 20 + 21 + static void event_icpt_insn_get_key(struct perf_evsel *evsel, 22 + struct perf_sample *sample, 23 + struct event_key *key) 24 + { 25 + unsigned long insn; 26 + 27 + insn = perf_evsel__intval(evsel, sample, "instruction"); 28 + key->key = icpt_insn_decoder(insn); 29 + key->exit_reasons = sie_icpt_insn_codes; 30 + } 31 + 32 + static void event_sigp_get_key(struct perf_evsel *evsel, 33 + struct perf_sample *sample, 34 + struct event_key *key) 35 + { 36 + key->key = perf_evsel__intval(evsel, sample, "order_code"); 37 + key->exit_reasons = sie_sigp_order_codes; 38 + } 39 + 40 + static void event_diag_get_key(struct perf_evsel *evsel, 41 + struct perf_sample *sample, 42 + struct event_key *key) 43 + { 44 + key->key = perf_evsel__intval(evsel, sample, "code"); 45 + key->exit_reasons = sie_diagnose_codes; 46 + } 47 + 48 + static void event_icpt_prog_get_key(struct perf_evsel *evsel, 49 + struct perf_sample *sample, 50 + struct event_key *key) 51 + { 52 + key->key = perf_evsel__intval(evsel, sample, "code"); 53 + key->exit_reasons = sie_icpt_prog_codes; 54 + } 55 + 56 + static struct child_event_ops child_events[] = { 57 + { .name = "kvm:kvm_s390_intercept_instruction", 58 + .get_key = event_icpt_insn_get_key }, 59 + { .name = "kvm:kvm_s390_handle_sigp", 60 + .get_key = event_sigp_get_key }, 61 + { .name = "kvm:kvm_s390_handle_diag", 62 + .get_key = event_diag_get_key }, 63 + { .name = "kvm:kvm_s390_intercept_prog", 64 + .get_key = event_icpt_prog_get_key }, 65 + { NULL, NULL }, 66 + }; 67 + 68 + static struct kvm_events_ops exit_events = { 69 + .is_begin_event = exit_event_begin, 70 + .is_end_event = exit_event_end, 71 + .child_ops = child_events, 72 + .decode_key = exit_event_decode_key, 73 + .name = "VM-EXIT" 74 + }; 75 + 76 + const char * const kvm_events_tp[] = { 77 + "kvm:kvm_s390_sie_enter", 78 + "kvm:kvm_s390_sie_exit", 79 + "kvm:kvm_s390_intercept_instruction", 80 + "kvm:kvm_s390_handle_sigp", 81 + "kvm:kvm_s390_handle_diag", 82 + "kvm:kvm_s390_intercept_prog", 83 + NULL, 84 + }; 85 + 86 + struct kvm_reg_events_ops kvm_reg_events_ops[] = { 87 + { .name = "vmexit", .ops = &exit_events }, 88 + { NULL, NULL }, 89 + }; 90 + 91 + const char * const kvm_skip_events[] = { 92 + "Wait state", 93 + NULL, 94 + }; 95 + 96 + int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid) 97 + { 98 + if (strstr(cpuid, "IBM/S390")) { 99 + kvm->exit_reasons = sie_exit_reasons; 100 + kvm->exit_reasons_isa = "SIE"; 101 + } else 102 + return -ENOTSUP; 103 + 104 + return 0; 105 + }
+2
tools/perf/arch/x86/Makefile
··· 15 15 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o 16 16 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o 17 17 LIB_H += arch/$(ARCH)/util/tsc.h 18 + HAVE_KVM_STAT_SUPPORT := 1 19 + LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/kvm-stat.o
+1
tools/perf/arch/x86/tests/dwarf-unwind.c
··· 3 3 #include "thread.h" 4 4 #include "map.h" 5 5 #include "event.h" 6 + #include "debug.h" 6 7 #include "tests/tests.h" 7 8 8 9 #define STACK_SIZE 8192
+156
tools/perf/arch/x86/util/kvm-stat.c
··· 1 + #include "../../util/kvm-stat.h" 2 + #include <asm/kvm_perf.h> 3 + 4 + define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS); 5 + define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS); 6 + 7 + static struct kvm_events_ops exit_events = { 8 + .is_begin_event = exit_event_begin, 9 + .is_end_event = exit_event_end, 10 + .decode_key = exit_event_decode_key, 11 + .name = "VM-EXIT" 12 + }; 13 + 14 + /* 15 + * For the mmio events, we treat: 16 + * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry 17 + * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...). 18 + */ 19 + static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample, 20 + struct event_key *key) 21 + { 22 + key->key = perf_evsel__intval(evsel, sample, "gpa"); 23 + key->info = perf_evsel__intval(evsel, sample, "type"); 24 + } 25 + 26 + #define KVM_TRACE_MMIO_READ_UNSATISFIED 0 27 + #define KVM_TRACE_MMIO_READ 1 28 + #define KVM_TRACE_MMIO_WRITE 2 29 + 30 + static bool mmio_event_begin(struct perf_evsel *evsel, 31 + struct perf_sample *sample, struct event_key *key) 32 + { 33 + /* MMIO read begin event in kernel. */ 34 + if (kvm_exit_event(evsel)) 35 + return true; 36 + 37 + /* MMIO write begin event in kernel. */ 38 + if (!strcmp(evsel->name, "kvm:kvm_mmio") && 39 + perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) { 40 + mmio_event_get_key(evsel, sample, key); 41 + return true; 42 + } 43 + 44 + return false; 45 + } 46 + 47 + static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample, 48 + struct event_key *key) 49 + { 50 + /* MMIO write end event in kernel. */ 51 + if (kvm_entry_event(evsel)) 52 + return true; 53 + 54 + /* MMIO read end event in kernel.*/ 55 + if (!strcmp(evsel->name, "kvm:kvm_mmio") && 56 + perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) { 57 + mmio_event_get_key(evsel, sample, key); 58 + return true; 59 + } 60 + 61 + return false; 62 + } 63 + 64 + static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused, 65 + struct event_key *key, 66 + char *decode) 67 + { 68 + scnprintf(decode, DECODE_STR_LEN, "%#lx:%s", 69 + (unsigned long)key->key, 70 + key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R"); 71 + } 72 + 73 + static struct kvm_events_ops mmio_events = { 74 + .is_begin_event = mmio_event_begin, 75 + .is_end_event = mmio_event_end, 76 + .decode_key = mmio_event_decode_key, 77 + .name = "MMIO Access" 78 + }; 79 + 80 + /* The time of emulation pio access is from kvm_pio to kvm_entry. */ 81 + static void ioport_event_get_key(struct perf_evsel *evsel, 82 + struct perf_sample *sample, 83 + struct event_key *key) 84 + { 85 + key->key = perf_evsel__intval(evsel, sample, "port"); 86 + key->info = perf_evsel__intval(evsel, sample, "rw"); 87 + } 88 + 89 + static bool ioport_event_begin(struct perf_evsel *evsel, 90 + struct perf_sample *sample, 91 + struct event_key *key) 92 + { 93 + if (!strcmp(evsel->name, "kvm:kvm_pio")) { 94 + ioport_event_get_key(evsel, sample, key); 95 + return true; 96 + } 97 + 98 + return false; 99 + } 100 + 101 + static bool ioport_event_end(struct perf_evsel *evsel, 102 + struct perf_sample *sample __maybe_unused, 103 + struct event_key *key __maybe_unused) 104 + { 105 + return kvm_entry_event(evsel); 106 + } 107 + 108 + static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused, 109 + struct event_key *key, 110 + char *decode) 111 + { 112 + scnprintf(decode, DECODE_STR_LEN, "%#llx:%s", 113 + (unsigned long long)key->key, 114 + key->info ? "POUT" : "PIN"); 115 + } 116 + 117 + static struct kvm_events_ops ioport_events = { 118 + .is_begin_event = ioport_event_begin, 119 + .is_end_event = ioport_event_end, 120 + .decode_key = ioport_event_decode_key, 121 + .name = "IO Port Access" 122 + }; 123 + 124 + const char * const kvm_events_tp[] = { 125 + "kvm:kvm_entry", 126 + "kvm:kvm_exit", 127 + "kvm:kvm_mmio", 128 + "kvm:kvm_pio", 129 + NULL, 130 + }; 131 + 132 + struct kvm_reg_events_ops kvm_reg_events_ops[] = { 133 + { .name = "vmexit", .ops = &exit_events }, 134 + { .name = "mmio", .ops = &mmio_events }, 135 + { .name = "ioport", .ops = &ioport_events }, 136 + { NULL, NULL }, 137 + }; 138 + 139 + const char * const kvm_skip_events[] = { 140 + "HLT", 141 + NULL, 142 + }; 143 + 144 + int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid) 145 + { 146 + if (strstr(cpuid, "Intel")) { 147 + kvm->exit_reasons = vmx_exit_reasons; 148 + kvm->exit_reasons_isa = "VMX"; 149 + } else if (strstr(cpuid, "AMD")) { 150 + kvm->exit_reasons = svm_exit_reasons; 151 + kvm->exit_reasons_isa = "SVM"; 152 + } else 153 + return -ENOTSUP; 154 + 155 + return 0; 156 + }
+10 -21
tools/perf/arch/x86/util/tsc.c
··· 6 6 #include "../../perf.h" 7 7 #include <linux/types.h> 8 8 #include "../../util/debug.h" 9 + #include "../../util/tsc.h" 9 10 #include "tsc.h" 10 - 11 - u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc) 12 - { 13 - u64 t, quot, rem; 14 - 15 - t = ns - tc->time_zero; 16 - quot = t / tc->time_mult; 17 - rem = t % tc->time_mult; 18 - return (quot << tc->time_shift) + 19 - (rem << tc->time_shift) / tc->time_mult; 20 - } 21 - 22 - u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc) 23 - { 24 - u64 quot, rem; 25 - 26 - quot = cyc >> tc->time_shift; 27 - rem = cyc & ((1 << tc->time_shift) - 1); 28 - return tc->time_zero + quot * tc->time_mult + 29 - ((rem * tc->time_mult) >> tc->time_shift); 30 - } 31 11 32 12 int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, 33 13 struct perf_tsc_conversion *tc) ··· 36 56 return -EOPNOTSUPP; 37 57 38 58 return 0; 59 + } 60 + 61 + u64 rdtsc(void) 62 + { 63 + unsigned int low, high; 64 + 65 + asm volatile("rdtsc" : "=a" (low), "=d" (high)); 66 + 67 + return low | ((u64)high) << 32; 39 68 }
-3
tools/perf/arch/x86/util/tsc.h
··· 14 14 int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, 15 15 struct perf_tsc_conversion *tc); 16 16 17 - u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc); 18 - u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc); 19 - 20 17 #endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
+1
tools/perf/arch/x86/util/unwind-libunwind.c
··· 3 3 #include <libunwind.h> 4 4 #include "perf_regs.h" 5 5 #include "../../util/unwind.h" 6 + #include "../../util/debug.h" 6 7 7 8 #ifdef HAVE_ARCH_X86_64_SUPPORT 8 9 int libunwind__arch_reg_id(int regnum)
+1
tools/perf/bench/bench.h
··· 43 43 #define BENCH_FORMAT_UNKNOWN -1 44 44 45 45 extern int bench_format; 46 + extern unsigned int bench_repeat; 46 47 47 48 #endif
+1 -9
tools/perf/bench/futex-requeue.c
··· 29 29 */ 30 30 static unsigned int nrequeue = 1; 31 31 32 - /* 33 - * There can be significant variance from run to run, 34 - * the more repeats, the more exact the overall avg and 35 - * the better idea of the futex latency. 36 - */ 37 - static unsigned int repeat = 10; 38 - 39 32 static pthread_t *worker; 40 33 static bool done = 0, silent = 0; 41 34 static pthread_mutex_t thread_lock; ··· 39 46 static const struct option options[] = { 40 47 OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"), 41 48 OPT_UINTEGER('q', "nrequeue", &nrequeue, "Specify amount of threads to requeue at once"), 42 - OPT_UINTEGER('r', "repeat", &repeat, "Specify amount of times to repeat the run"), 43 49 OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"), 44 50 OPT_END() 45 51 }; ··· 138 146 pthread_cond_init(&thread_parent, NULL); 139 147 pthread_cond_init(&thread_worker, NULL); 140 148 141 - for (j = 0; j < repeat && !done; j++) { 149 + for (j = 0; j < bench_repeat && !done; j++) { 142 150 unsigned int nrequeued = 0; 143 151 struct timeval start, end, runtime; 144 152
+2 -10
tools/perf/bench/futex-wake.c
··· 30 30 */ 31 31 static unsigned int nwakes = 1; 32 32 33 - /* 34 - * There can be significant variance from run to run, 35 - * the more repeats, the more exact the overall avg and 36 - * the better idea of the futex latency. 37 - */ 38 - static unsigned int repeat = 10; 39 - 40 33 pthread_t *worker; 41 - static bool done = 0, silent = 0; 34 + static bool done = false, silent = false; 42 35 static pthread_mutex_t thread_lock; 43 36 static pthread_cond_t thread_parent, thread_worker; 44 37 static struct stats waketime_stats, wakeup_stats; ··· 40 47 static const struct option options[] = { 41 48 OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"), 42 49 OPT_UINTEGER('w', "nwakes", &nwakes, "Specify amount of threads to wake at once"), 43 - OPT_UINTEGER('r', "repeat", &repeat, "Specify amount of times to repeat the run"), 44 50 OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"), 45 51 OPT_END() 46 52 }; ··· 141 149 pthread_cond_init(&thread_parent, NULL); 142 150 pthread_cond_init(&thread_worker, NULL); 143 151 144 - for (j = 0; j < repeat && !done; j++) { 152 + for (j = 0; j < bench_repeat && !done; j++) { 145 153 unsigned int nwoken = 0; 146 154 struct timeval start, end, runtime; 147 155
+8 -1
tools/perf/bench/mem-memcpy.c
··· 10 10 #include "../util/util.h" 11 11 #include "../util/parse-options.h" 12 12 #include "../util/header.h" 13 + #include "../util/cloexec.h" 13 14 #include "bench.h" 14 15 #include "mem-memcpy-arch.h" 15 16 ··· 84 83 85 84 static void init_cycle(void) 86 85 { 87 - cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0); 86 + cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 87 + perf_event_open_cloexec_flag()); 88 88 89 89 if (cycle_fd < 0 && errno == ENOSYS) 90 90 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); ··· 190 188 191 189 argc = parse_options(argc, argv, options, 192 190 bench_mem_memcpy_usage, 0); 191 + 192 + if (no_prefault && only_prefault) { 193 + fprintf(stderr, "Invalid options: -o and -n are mutually exclusive\n"); 194 + return 1; 195 + } 193 196 194 197 if (use_cycle) 195 198 init_cycle();
+8 -1
tools/perf/bench/mem-memset.c
··· 10 10 #include "../util/util.h" 11 11 #include "../util/parse-options.h" 12 12 #include "../util/header.h" 13 + #include "../util/cloexec.h" 13 14 #include "bench.h" 14 15 #include "mem-memset-arch.h" 15 16 ··· 84 83 85 84 static void init_cycle(void) 86 85 { 87 - cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0); 86 + cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 87 + perf_event_open_cloexec_flag()); 88 88 89 89 if (cycle_fd < 0 && errno == ENOSYS) 90 90 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); ··· 182 180 183 181 argc = parse_options(argc, argv, options, 184 182 bench_mem_memset_usage, 0); 183 + 184 + if (no_prefault && only_prefault) { 185 + fprintf(stderr, "Invalid options: -o and -n are mutually exclusive\n"); 186 + return 1; 187 + } 185 188 186 189 if (use_cycle) 187 190 init_cycle();
+21 -26
tools/perf/bench/sched-messaging.c
··· 28 28 #include <sys/time.h> 29 29 #include <sys/poll.h> 30 30 #include <limits.h> 31 + #include <err.h> 31 32 32 33 #define DATASIZE 100 33 34 ··· 51 50 int wakefd; 52 51 }; 53 52 54 - static void barf(const char *msg) 55 - { 56 - fprintf(stderr, "%s (error: %s)\n", msg, strerror(errno)); 57 - exit(1); 58 - } 59 - 60 53 static void fdpair(int fds[2]) 61 54 { 62 55 if (use_pipes) { ··· 61 66 return; 62 67 } 63 68 64 - barf(use_pipes ? "pipe()" : "socketpair()"); 69 + err(EXIT_FAILURE, use_pipes ? "pipe()" : "socketpair()"); 65 70 } 66 71 67 72 /* Block until we're ready to go */ ··· 72 77 73 78 /* Tell them we're ready. */ 74 79 if (write(ready_out, &dummy, 1) != 1) 75 - barf("CLIENT: ready write"); 80 + err(EXIT_FAILURE, "CLIENT: ready write"); 76 81 77 82 /* Wait for "GO" signal */ 78 83 if (poll(&pollfd, 1, -1) != 1) 79 - barf("poll"); 84 + err(EXIT_FAILURE, "poll"); 80 85 } 81 86 82 87 /* Sender sprays loops messages down each file descriptor */ ··· 96 101 ret = write(ctx->out_fds[j], data + done, 97 102 sizeof(data)-done); 98 103 if (ret < 0) 99 - barf("SENDER: write"); 104 + err(EXIT_FAILURE, "SENDER: write"); 100 105 done += ret; 101 106 if (done < DATASIZE) 102 107 goto again; ··· 126 131 again: 127 132 ret = read(ctx->in_fds[0], data + done, DATASIZE - done); 128 133 if (ret < 0) 129 - barf("SERVER: read"); 134 + err(EXIT_FAILURE, "SERVER: read"); 130 135 done += ret; 131 136 if (done < DATASIZE) 132 137 goto again; ··· 139 144 { 140 145 pthread_attr_t attr; 141 146 pthread_t childid; 142 - int err; 147 + int ret; 143 148 144 149 if (!thread_mode) { 145 150 /* process mode */ 146 151 /* Fork the receiver. */ 147 152 switch (fork()) { 148 153 case -1: 149 - barf("fork()"); 154 + err(EXIT_FAILURE, "fork()"); 150 155 break; 151 156 case 0: 152 157 (*func) (ctx); ··· 160 165 } 161 166 162 167 if (pthread_attr_init(&attr) != 0) 163 - barf("pthread_attr_init:"); 168 + err(EXIT_FAILURE, "pthread_attr_init:"); 164 169 165 170 #ifndef __ia64__ 166 171 if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN) != 0) 167 - barf("pthread_attr_setstacksize"); 172 + err(EXIT_FAILURE, "pthread_attr_setstacksize"); 168 173 #endif 169 174 170 - err = pthread_create(&childid, &attr, func, ctx); 171 - if (err != 0) { 172 - fprintf(stderr, "pthread_create failed: %s (%d)\n", 173 - strerror(err), err); 174 - exit(-1); 175 - } 175 + ret = pthread_create(&childid, &attr, func, ctx); 176 + if (ret != 0) 177 + err(EXIT_FAILURE, "pthread_create failed"); 178 + 176 179 return childid; 177 180 } 178 181 ··· 200 207 + num_fds * sizeof(int)); 201 208 202 209 if (!snd_ctx) 203 - barf("malloc()"); 210 + err(EXIT_FAILURE, "malloc()"); 204 211 205 212 for (i = 0; i < num_fds; i++) { 206 213 int fds[2]; 207 214 struct receiver_context *ctx = malloc(sizeof(*ctx)); 208 215 209 216 if (!ctx) 210 - barf("malloc()"); 217 + err(EXIT_FAILURE, "malloc()"); 211 218 212 219 213 220 /* Create the pipe between client and server */ ··· 274 281 275 282 pth_tab = malloc(num_fds * 2 * num_groups * sizeof(pthread_t)); 276 283 if (!pth_tab) 277 - barf("main:malloc()"); 284 + err(EXIT_FAILURE, "main:malloc()"); 278 285 279 286 fdpair(readyfds); 280 287 fdpair(wakefds); ··· 287 294 /* Wait for everyone to be ready */ 288 295 for (i = 0; i < total_children; i++) 289 296 if (read(readyfds[0], &dummy, 1) != 1) 290 - barf("Reading for readyfds"); 297 + err(EXIT_FAILURE, "Reading for readyfds"); 291 298 292 299 gettimeofday(&start, NULL); 293 300 294 301 /* Kick them off */ 295 302 if (write(wakefds[1], &dummy, 1) != 1) 296 - barf("Writing to start them"); 303 + err(EXIT_FAILURE, "Writing to start them"); 297 304 298 305 /* Reap them all */ 299 306 for (i = 0; i < total_children; i++) ··· 324 331 exit(1); 325 332 break; 326 333 } 334 + 335 + free(pth_tab); 327 336 328 337 return 0; 329 338 }
+7
tools/perf/builtin-bench.c
··· 104 104 105 105 /* Output/formatting style, exported to benchmark modules: */ 106 106 int bench_format = BENCH_FORMAT_DEFAULT; 107 + unsigned int bench_repeat = 10; /* default number of times to repeat the run */ 107 108 108 109 static const struct option bench_options[] = { 109 110 OPT_STRING('f', "format", &bench_format_str, "default", "Specify format style"), 111 + OPT_UINTEGER('r', "repeat", &bench_repeat, "Specify amount of times to repeat the run"), 110 112 OPT_END() 111 113 }; 112 114 ··· 225 223 bench_format = bench_str2int(bench_format_str); 226 224 if (bench_format == BENCH_FORMAT_UNKNOWN) { 227 225 printf("Unknown format descriptor: '%s'\n", bench_format_str); 226 + goto end; 227 + } 228 + 229 + if (bench_repeat == 0) { 230 + printf("Invalid repeat option: Must specify a positive value\n"); 228 231 goto end; 229 232 } 230 233
+5 -3
tools/perf/builtin-buildid-cache.c
··· 125 125 return ret; 126 126 } 127 127 128 - static int build_id_cache__add_kcore(const char *filename, const char *debugdir) 128 + static int build_id_cache__add_kcore(const char *filename, const char *debugdir, 129 + bool force) 129 130 { 130 131 char dir[32], sbuildid[BUILD_ID_SIZE * 2 + 1]; 131 132 char from_dir[PATH_MAX], to_dir[PATH_MAX]; ··· 145 144 scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s", 146 145 debugdir, sbuildid); 147 146 148 - if (!build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) { 147 + if (!force && 148 + !build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) { 149 149 pr_debug("same kcore found in %s\n", to_dir); 150 150 return 0; 151 151 } ··· 391 389 } 392 390 393 391 if (kcore_filename && 394 - build_id_cache__add_kcore(kcore_filename, debugdir)) 392 + build_id_cache__add_kcore(kcore_filename, debugdir, force)) 395 393 pr_warning("Couldn't add %s\n", kcore_filename); 396 394 397 395 return ret;
+1
tools/perf/builtin-evlist.c
··· 15 15 #include "util/parse-options.h" 16 16 #include "util/session.h" 17 17 #include "util/data.h" 18 + #include "util/debug.h" 18 19 19 20 static int __cmd_evlist(const char *file_name, struct perf_attr_details *details) 20 21 {
+1
tools/perf/builtin-help.c
··· 11 11 #include "util/parse-options.h" 12 12 #include "util/run-command.h" 13 13 #include "util/help.h" 14 + #include "util/debug.h" 14 15 15 16 static struct man_viewer_list { 16 17 struct man_viewer_list *next;
+5
tools/perf/builtin-inject.c
··· 389 389 ret = perf_session__process_events(session, &inject->tool); 390 390 391 391 if (!file_out->is_pipe) { 392 + if (inject->build_ids) 393 + perf_header__set_feat(&session->header, 394 + HEADER_BUILD_ID); 392 395 session->header.data_size = inject->bytes_written; 393 396 perf_session__write_header(session, session->evlist, file_out->fd, true); 394 397 } ··· 439 436 "where and how long tasks slept"), 440 437 OPT_INCR('v', "verbose", &verbose, 441 438 "be more verbose (show build ids, etc)"), 439 + OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file", 440 + "kallsyms pathname"), 442 441 OPT_END() 443 442 }; 444 443 const char * const inject_usage[] = {
+122 -294
tools/perf/builtin-kvm.c
··· 29 29 #include <pthread.h> 30 30 #include <math.h> 31 31 32 - #if defined(__i386__) || defined(__x86_64__) 33 - #include <asm/svm.h> 34 - #include <asm/vmx.h> 35 - #include <asm/kvm.h> 32 + #ifdef HAVE_KVM_STAT_SUPPORT 33 + #include <asm/kvm_perf.h> 34 + #include "util/kvm-stat.h" 36 35 37 - struct event_key { 38 - #define INVALID_KEY (~0ULL) 39 - u64 key; 40 - int info; 41 - }; 42 - 43 - struct kvm_event_stats { 44 - u64 time; 45 - struct stats stats; 46 - }; 47 - 48 - struct kvm_event { 49 - struct list_head hash_entry; 50 - struct rb_node rb; 51 - 52 - struct event_key key; 53 - 54 - struct kvm_event_stats total; 55 - 56 - #define DEFAULT_VCPU_NUM 8 57 - int max_vcpu; 58 - struct kvm_event_stats *vcpu; 59 - }; 60 - 61 - typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int); 62 - 63 - struct kvm_event_key { 64 - const char *name; 65 - key_cmp_fun key; 66 - }; 67 - 68 - 69 - struct perf_kvm_stat; 70 - 71 - struct kvm_events_ops { 72 - bool (*is_begin_event)(struct perf_evsel *evsel, 73 - struct perf_sample *sample, 74 - struct event_key *key); 75 - bool (*is_end_event)(struct perf_evsel *evsel, 76 - struct perf_sample *sample, struct event_key *key); 77 - void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key, 78 - char decode[20]); 79 - const char *name; 80 - }; 81 - 82 - struct exit_reasons_table { 83 - unsigned long exit_code; 84 - const char *reason; 85 - }; 86 - 87 - #define EVENTS_BITS 12 88 - #define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS) 89 - 90 - struct perf_kvm_stat { 91 - struct perf_tool tool; 92 - struct record_opts opts; 93 - struct perf_evlist *evlist; 94 - struct perf_session *session; 95 - 96 - const char *file_name; 97 - const char *report_event; 98 - const char *sort_key; 99 - int trace_vcpu; 100 - 101 - struct exit_reasons_table *exit_reasons; 102 - int exit_reasons_size; 103 - const char *exit_reasons_isa; 104 - 105 - struct kvm_events_ops *events_ops; 106 - key_cmp_fun compare; 107 - struct list_head kvm_events_cache[EVENTS_CACHE_SIZE]; 108 - 109 - u64 total_time; 110 - u64 total_count; 111 - u64 lost_events; 112 - u64 duration; 113 - 114 - const char *pid_str; 115 - struct intlist *pid_list; 116 - 117 - struct rb_root result; 118 - 119 - int timerfd; 120 - unsigned int display_time; 121 - bool live; 122 - }; 123 - 124 - 125 - static void exit_event_get_key(struct perf_evsel *evsel, 126 - struct perf_sample *sample, 127 - struct event_key *key) 36 + void exit_event_get_key(struct perf_evsel *evsel, 37 + struct perf_sample *sample, 38 + struct event_key *key) 128 39 { 129 40 key->info = 0; 130 - key->key = perf_evsel__intval(evsel, sample, "exit_reason"); 41 + key->key = perf_evsel__intval(evsel, sample, KVM_EXIT_REASON); 131 42 } 132 43 133 - static bool kvm_exit_event(struct perf_evsel *evsel) 44 + bool kvm_exit_event(struct perf_evsel *evsel) 134 45 { 135 - return !strcmp(evsel->name, "kvm:kvm_exit"); 46 + return !strcmp(evsel->name, KVM_EXIT_TRACE); 136 47 } 137 48 138 - static bool exit_event_begin(struct perf_evsel *evsel, 139 - struct perf_sample *sample, struct event_key *key) 49 + bool exit_event_begin(struct perf_evsel *evsel, 50 + struct perf_sample *sample, struct event_key *key) 140 51 { 141 52 if (kvm_exit_event(evsel)) { 142 53 exit_event_get_key(evsel, sample, key); ··· 57 146 return false; 58 147 } 59 148 60 - static bool kvm_entry_event(struct perf_evsel *evsel) 149 + bool kvm_entry_event(struct perf_evsel *evsel) 61 150 { 62 - return !strcmp(evsel->name, "kvm:kvm_entry"); 151 + return !strcmp(evsel->name, KVM_ENTRY_TRACE); 63 152 } 64 153 65 - static bool exit_event_end(struct perf_evsel *evsel, 66 - struct perf_sample *sample __maybe_unused, 67 - struct event_key *key __maybe_unused) 154 + bool exit_event_end(struct perf_evsel *evsel, 155 + struct perf_sample *sample __maybe_unused, 156 + struct event_key *key __maybe_unused) 68 157 { 69 158 return kvm_entry_event(evsel); 70 159 } 71 160 72 - static struct exit_reasons_table vmx_exit_reasons[] = { 73 - VMX_EXIT_REASONS 74 - }; 75 - 76 - static struct exit_reasons_table svm_exit_reasons[] = { 77 - SVM_EXIT_REASONS 78 - }; 79 - 80 - static const char *get_exit_reason(struct perf_kvm_stat *kvm, u64 exit_code) 161 + static const char *get_exit_reason(struct perf_kvm_stat *kvm, 162 + struct exit_reasons_table *tbl, 163 + u64 exit_code) 81 164 { 82 - int i = kvm->exit_reasons_size; 83 - struct exit_reasons_table *tbl = kvm->exit_reasons; 84 - 85 - while (i--) { 165 + while (tbl->reason != NULL) { 86 166 if (tbl->exit_code == exit_code) 87 167 return tbl->reason; 88 168 tbl++; ··· 84 182 return "UNKNOWN"; 85 183 } 86 184 87 - static void exit_event_decode_key(struct perf_kvm_stat *kvm, 88 - struct event_key *key, 89 - char decode[20]) 185 + void exit_event_decode_key(struct perf_kvm_stat *kvm, 186 + struct event_key *key, 187 + char *decode) 90 188 { 91 - const char *exit_reason = get_exit_reason(kvm, key->key); 189 + const char *exit_reason = get_exit_reason(kvm, key->exit_reasons, 190 + key->key); 92 191 93 - scnprintf(decode, 20, "%s", exit_reason); 192 + scnprintf(decode, DECODE_STR_LEN, "%s", exit_reason); 94 193 } 95 - 96 - static struct kvm_events_ops exit_events = { 97 - .is_begin_event = exit_event_begin, 98 - .is_end_event = exit_event_end, 99 - .decode_key = exit_event_decode_key, 100 - .name = "VM-EXIT" 101 - }; 102 - 103 - /* 104 - * For the mmio events, we treat: 105 - * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry 106 - * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...). 107 - */ 108 - static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample, 109 - struct event_key *key) 110 - { 111 - key->key = perf_evsel__intval(evsel, sample, "gpa"); 112 - key->info = perf_evsel__intval(evsel, sample, "type"); 113 - } 114 - 115 - #define KVM_TRACE_MMIO_READ_UNSATISFIED 0 116 - #define KVM_TRACE_MMIO_READ 1 117 - #define KVM_TRACE_MMIO_WRITE 2 118 - 119 - static bool mmio_event_begin(struct perf_evsel *evsel, 120 - struct perf_sample *sample, struct event_key *key) 121 - { 122 - /* MMIO read begin event in kernel. */ 123 - if (kvm_exit_event(evsel)) 124 - return true; 125 - 126 - /* MMIO write begin event in kernel. */ 127 - if (!strcmp(evsel->name, "kvm:kvm_mmio") && 128 - perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) { 129 - mmio_event_get_key(evsel, sample, key); 130 - return true; 131 - } 132 - 133 - return false; 134 - } 135 - 136 - static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample, 137 - struct event_key *key) 138 - { 139 - /* MMIO write end event in kernel. */ 140 - if (kvm_entry_event(evsel)) 141 - return true; 142 - 143 - /* MMIO read end event in kernel.*/ 144 - if (!strcmp(evsel->name, "kvm:kvm_mmio") && 145 - perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) { 146 - mmio_event_get_key(evsel, sample, key); 147 - return true; 148 - } 149 - 150 - return false; 151 - } 152 - 153 - static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused, 154 - struct event_key *key, 155 - char decode[20]) 156 - { 157 - scnprintf(decode, 20, "%#lx:%s", (unsigned long)key->key, 158 - key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R"); 159 - } 160 - 161 - static struct kvm_events_ops mmio_events = { 162 - .is_begin_event = mmio_event_begin, 163 - .is_end_event = mmio_event_end, 164 - .decode_key = mmio_event_decode_key, 165 - .name = "MMIO Access" 166 - }; 167 - 168 - /* The time of emulation pio access is from kvm_pio to kvm_entry. */ 169 - static void ioport_event_get_key(struct perf_evsel *evsel, 170 - struct perf_sample *sample, 171 - struct event_key *key) 172 - { 173 - key->key = perf_evsel__intval(evsel, sample, "port"); 174 - key->info = perf_evsel__intval(evsel, sample, "rw"); 175 - } 176 - 177 - static bool ioport_event_begin(struct perf_evsel *evsel, 178 - struct perf_sample *sample, 179 - struct event_key *key) 180 - { 181 - if (!strcmp(evsel->name, "kvm:kvm_pio")) { 182 - ioport_event_get_key(evsel, sample, key); 183 - return true; 184 - } 185 - 186 - return false; 187 - } 188 - 189 - static bool ioport_event_end(struct perf_evsel *evsel, 190 - struct perf_sample *sample __maybe_unused, 191 - struct event_key *key __maybe_unused) 192 - { 193 - return kvm_entry_event(evsel); 194 - } 195 - 196 - static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused, 197 - struct event_key *key, 198 - char decode[20]) 199 - { 200 - scnprintf(decode, 20, "%#llx:%s", (unsigned long long)key->key, 201 - key->info ? "POUT" : "PIN"); 202 - } 203 - 204 - static struct kvm_events_ops ioport_events = { 205 - .is_begin_event = ioport_event_begin, 206 - .is_end_event = ioport_event_end, 207 - .decode_key = ioport_event_decode_key, 208 - .name = "IO Port Access" 209 - }; 210 194 211 195 static bool register_kvm_events_ops(struct perf_kvm_stat *kvm) 212 196 { 213 - bool ret = true; 197 + struct kvm_reg_events_ops *events_ops = kvm_reg_events_ops; 214 198 215 - if (!strcmp(kvm->report_event, "vmexit")) 216 - kvm->events_ops = &exit_events; 217 - else if (!strcmp(kvm->report_event, "mmio")) 218 - kvm->events_ops = &mmio_events; 219 - else if (!strcmp(kvm->report_event, "ioport")) 220 - kvm->events_ops = &ioport_events; 221 - else { 222 - pr_err("Unknown report event:%s\n", kvm->report_event); 223 - ret = false; 199 + for (events_ops = kvm_reg_events_ops; events_ops->name; events_ops++) { 200 + if (!strcmp(events_ops->name, kvm->report_event)) { 201 + kvm->events_ops = events_ops->ops; 202 + return true; 203 + } 224 204 } 225 205 226 - return ret; 206 + return false; 227 207 } 228 208 229 209 struct vcpu_event_record { ··· 261 477 return true; 262 478 } 263 479 480 + static bool is_child_event(struct perf_kvm_stat *kvm, 481 + struct perf_evsel *evsel, 482 + struct perf_sample *sample, 483 + struct event_key *key) 484 + { 485 + struct child_event_ops *child_ops; 486 + 487 + child_ops = kvm->events_ops->child_ops; 488 + 489 + if (!child_ops) 490 + return false; 491 + 492 + for (; child_ops->name; child_ops++) { 493 + if (!strcmp(evsel->name, child_ops->name)) { 494 + child_ops->get_key(evsel, sample, key); 495 + return true; 496 + } 497 + } 498 + 499 + return false; 500 + } 501 + 502 + static bool handle_child_event(struct perf_kvm_stat *kvm, 503 + struct vcpu_event_record *vcpu_record, 504 + struct event_key *key, 505 + struct perf_sample *sample __maybe_unused) 506 + { 507 + struct kvm_event *event = NULL; 508 + 509 + if (key->key != INVALID_KEY) 510 + event = find_create_kvm_event(kvm, key); 511 + 512 + vcpu_record->last_event = event; 513 + 514 + return true; 515 + } 516 + 517 + static bool skip_event(const char *event) 518 + { 519 + const char * const *skip_events; 520 + 521 + for (skip_events = kvm_skip_events; *skip_events; skip_events++) 522 + if (!strcmp(event, *skip_events)) 523 + return true; 524 + 525 + return false; 526 + } 527 + 264 528 static bool handle_end_event(struct perf_kvm_stat *kvm, 265 529 struct vcpu_event_record *vcpu_record, 266 530 struct event_key *key, ··· 357 525 time_diff = sample->time - time_begin; 358 526 359 527 if (kvm->duration && time_diff > kvm->duration) { 360 - char decode[32]; 528 + char decode[DECODE_STR_LEN]; 361 529 362 530 kvm->events_ops->decode_key(kvm, &event->key, decode); 363 - if (strcmp(decode, "HLT")) { 531 + if (!skip_event(decode)) { 364 532 pr_info("%" PRIu64 " VM %d, vcpu %d: %s event took %" PRIu64 "usec\n", 365 533 sample->time, sample->pid, vcpu_record->vcpu_id, 366 534 decode, time_diff/1000); ··· 385 553 return NULL; 386 554 } 387 555 388 - vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, "vcpu_id"); 556 + vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, VCPU_ID); 389 557 thread->priv = vcpu_record; 390 558 } 391 559 ··· 398 566 struct perf_sample *sample) 399 567 { 400 568 struct vcpu_event_record *vcpu_record; 401 - struct event_key key = {.key = INVALID_KEY}; 569 + struct event_key key = { .key = INVALID_KEY, 570 + .exit_reasons = kvm->exit_reasons }; 402 571 403 572 vcpu_record = per_vcpu_record(thread, evsel, sample); 404 573 if (!vcpu_record) ··· 412 579 413 580 if (kvm->events_ops->is_begin_event(evsel, sample, &key)) 414 581 return handle_begin_event(kvm, vcpu_record, &key, sample->time); 582 + 583 + if (is_child_event(kvm, evsel, sample, &key)) 584 + return handle_child_event(kvm, vcpu_record, &key, sample); 415 585 416 586 if (kvm->events_ops->is_end_event(evsel, sample, &key)) 417 587 return handle_end_event(kvm, vcpu_record, &key, sample); ··· 576 740 577 741 static void print_result(struct perf_kvm_stat *kvm) 578 742 { 579 - char decode[20]; 743 + char decode[DECODE_STR_LEN]; 580 744 struct kvm_event *event; 581 745 int vcpu = kvm->trace_vcpu; 582 746 ··· 587 751 588 752 pr_info("\n\n"); 589 753 print_vcpu_info(kvm); 590 - pr_info("%20s ", kvm->events_ops->name); 754 + pr_info("%*s ", DECODE_STR_LEN, kvm->events_ops->name); 591 755 pr_info("%10s ", "Samples"); 592 756 pr_info("%9s ", "Samples%"); 593 757 ··· 606 770 min = get_event_min(event, vcpu); 607 771 608 772 kvm->events_ops->decode_key(kvm, &event->key, decode); 609 - pr_info("%20s ", decode); 773 + pr_info("%*s ", DECODE_STR_LEN, decode); 610 774 pr_info("%10llu ", (unsigned long long)ecount); 611 775 pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100); 612 776 pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100); ··· 675 839 static int cpu_isa_config(struct perf_kvm_stat *kvm) 676 840 { 677 841 char buf[64], *cpuid; 678 - int err, isa; 842 + int err; 679 843 680 844 if (kvm->live) { 681 845 err = get_cpuid(buf, sizeof(buf)); 682 846 if (err != 0) { 683 - pr_err("Failed to look up CPU type (Intel or AMD)\n"); 847 + pr_err("Failed to look up CPU type\n"); 684 848 return err; 685 849 } 686 850 cpuid = buf; 687 851 } else 688 852 cpuid = kvm->session->header.env.cpuid; 689 853 690 - if (strstr(cpuid, "Intel")) 691 - isa = 1; 692 - else if (strstr(cpuid, "AMD")) 693 - isa = 0; 694 - else { 854 + if (!cpuid) { 855 + pr_err("Failed to look up CPU type\n"); 856 + return -EINVAL; 857 + } 858 + 859 + err = cpu_isa_init(kvm, cpuid); 860 + if (err == -ENOTSUP) 695 861 pr_err("CPU %s is not supported.\n", cpuid); 696 - return -ENOTSUP; 697 - } 698 862 699 - if (isa == 1) { 700 - kvm->exit_reasons = vmx_exit_reasons; 701 - kvm->exit_reasons_size = ARRAY_SIZE(vmx_exit_reasons); 702 - kvm->exit_reasons_isa = "VMX"; 703 - } 704 - 705 - return 0; 863 + return err; 706 864 } 707 865 708 866 static bool verify_vcpu(int vcpu) ··· 1130 1300 return ret; 1131 1301 } 1132 1302 1133 - static const char * const kvm_events_tp[] = { 1134 - "kvm:kvm_entry", 1135 - "kvm:kvm_exit", 1136 - "kvm:kvm_mmio", 1137 - "kvm:kvm_pio", 1138 - }; 1139 - 1140 1303 #define STRDUP_FAIL_EXIT(s) \ 1141 1304 ({ char *_p; \ 1142 1305 _p = strdup(s); \ ··· 1141 1318 static int 1142 1319 kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) 1143 1320 { 1144 - unsigned int rec_argc, i, j; 1321 + unsigned int rec_argc, i, j, events_tp_size; 1145 1322 const char **rec_argv; 1146 1323 const char * const record_args[] = { 1147 1324 "record", ··· 1149 1326 "-m", "1024", 1150 1327 "-c", "1", 1151 1328 }; 1329 + const char * const *events_tp; 1330 + events_tp_size = 0; 1331 + 1332 + for (events_tp = kvm_events_tp; *events_tp; events_tp++) 1333 + events_tp_size++; 1152 1334 1153 1335 rec_argc = ARRAY_SIZE(record_args) + argc + 2 + 1154 - 2 * ARRAY_SIZE(kvm_events_tp); 1336 + 2 * events_tp_size; 1155 1337 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1156 1338 1157 1339 if (rec_argv == NULL) ··· 1165 1337 for (i = 0; i < ARRAY_SIZE(record_args); i++) 1166 1338 rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]); 1167 1339 1168 - for (j = 0; j < ARRAY_SIZE(kvm_events_tp); j++) { 1340 + for (j = 0; j < events_tp_size; j++) { 1169 1341 rec_argv[i++] = "-e"; 1170 1342 rec_argv[i++] = STRDUP_FAIL_EXIT(kvm_events_tp[j]); 1171 1343 } ··· 1184 1356 { 1185 1357 const struct option kvm_events_report_options[] = { 1186 1358 OPT_STRING(0, "event", &kvm->report_event, "report event", 1187 - "event for reporting: vmexit, mmio, ioport"), 1359 + "event for reporting: vmexit, " 1360 + "mmio (x86 only), ioport (x86 only)"), 1188 1361 OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu, 1189 1362 "vcpu id to report"), 1190 1363 OPT_STRING('k', "key", &kvm->sort_key, "sort-key", ··· 1220 1391 { 1221 1392 struct perf_evlist *evlist; 1222 1393 char *tp, *name, *sys; 1223 - unsigned int j; 1224 1394 int err = -1; 1395 + const char * const *events_tp; 1225 1396 1226 1397 evlist = perf_evlist__new(); 1227 1398 if (evlist == NULL) 1228 1399 return NULL; 1229 1400 1230 - for (j = 0; j < ARRAY_SIZE(kvm_events_tp); j++) { 1401 + for (events_tp = kvm_events_tp; *events_tp; events_tp++) { 1231 1402 1232 - tp = strdup(kvm_events_tp[j]); 1403 + tp = strdup(*events_tp); 1233 1404 if (tp == NULL) 1234 1405 goto out; 1235 1406 ··· 1238 1409 name = strchr(tp, ':'); 1239 1410 if (name == NULL) { 1240 1411 pr_err("Error parsing %s tracepoint: subsystem delimiter not found\n", 1241 - kvm_events_tp[j]); 1412 + *events_tp); 1242 1413 free(tp); 1243 1414 goto out; 1244 1415 } ··· 1246 1417 name++; 1247 1418 1248 1419 if (perf_evlist__add_newtp(evlist, sys, name, NULL)) { 1249 - pr_err("Failed to add %s tracepoint to the list\n", kvm_events_tp[j]); 1420 + pr_err("Failed to add %s tracepoint to the list\n", *events_tp); 1250 1421 free(tp); 1251 1422 goto out; 1252 1423 } ··· 1291 1462 "key for sorting: sample(sort by samples number)" 1292 1463 " time (sort by avg time)"), 1293 1464 OPT_U64(0, "duration", &kvm->duration, 1294 - "show events other than HALT that take longer than duration usecs"), 1465 + "show events other than" 1466 + " HLT (x86 only) or Wait state (s390 only)" 1467 + " that take longer than duration usecs"), 1295 1468 OPT_END() 1296 1469 }; 1297 1470 const char * const live_usage[] = { ··· 1416 1585 .report_event = "vmexit", 1417 1586 .sort_key = "sample", 1418 1587 1419 - .exit_reasons = svm_exit_reasons, 1420 - .exit_reasons_size = ARRAY_SIZE(svm_exit_reasons), 1421 - .exit_reasons_isa = "SVM", 1422 1588 }; 1423 1589 1424 1590 if (argc == 1) { ··· 1437 1609 perf_stat: 1438 1610 return cmd_stat(argc, argv, NULL); 1439 1611 } 1440 - #endif 1612 + #endif /* HAVE_KVM_STAT_SUPPORT */ 1441 1613 1442 1614 static int __cmd_record(const char *file_name, int argc, const char **argv) 1443 1615 { ··· 1554 1726 return cmd_top(argc, argv, NULL); 1555 1727 else if (!strncmp(argv[0], "buildid-list", 12)) 1556 1728 return __cmd_buildid_list(file_name, argc, argv); 1557 - #if defined(__i386__) || defined(__x86_64__) 1729 + #ifdef HAVE_KVM_STAT_SUPPORT 1558 1730 else if (!strncmp(argv[0], "stat", 4)) 1559 1731 return kvm_cmd_stat(file_name, argc, argv); 1560 1732 #endif
+6 -1
tools/perf/builtin-record.c
··· 238 238 239 239 static int record__mmap_read_all(struct record *rec) 240 240 { 241 + u64 bytes_written = rec->bytes_written; 241 242 int i; 242 243 int rc = 0; 243 244 ··· 251 250 } 252 251 } 253 252 254 - if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) 253 + /* 254 + * Mark the round finished in case we wrote 255 + * at least one event. 256 + */ 257 + if (bytes_written != rec->bytes_written) 255 258 rc = record__write(rec, &finished_round_event, sizeof(finished_round_event)); 256 259 257 260 out:
+9 -7
tools/perf/builtin-sched.c
··· 10 10 #include "util/header.h" 11 11 #include "util/session.h" 12 12 #include "util/tool.h" 13 + #include "util/cloexec.h" 13 14 14 15 #include "util/parse-options.h" 15 16 #include "util/trace-event.h" ··· 435 434 attr.type = PERF_TYPE_SOFTWARE; 436 435 attr.config = PERF_COUNT_SW_TASK_CLOCK; 437 436 438 - fd = sys_perf_event_open(&attr, 0, -1, -1, 0); 437 + fd = sys_perf_event_open(&attr, 0, -1, -1, 438 + perf_event_open_cloexec_flag()); 439 439 440 440 if (fd < 0) 441 441 pr_err("Error: sys_perf_event_open() syscall returned " ··· 937 935 return -1; 938 936 } 939 937 940 - sched_out = machine__findnew_thread(machine, 0, prev_pid); 941 - sched_in = machine__findnew_thread(machine, 0, next_pid); 938 + sched_out = machine__findnew_thread(machine, -1, prev_pid); 939 + sched_in = machine__findnew_thread(machine, -1, next_pid); 942 940 943 941 out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid); 944 942 if (!out_events) { ··· 981 979 { 982 980 const u32 pid = perf_evsel__intval(evsel, sample, "pid"); 983 981 const u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); 984 - struct thread *thread = machine__findnew_thread(machine, 0, pid); 982 + struct thread *thread = machine__findnew_thread(machine, -1, pid); 985 983 struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid); 986 984 u64 timestamp = sample->time; 987 985 int cpu = sample->cpu; ··· 1014 1012 struct thread *wakee; 1015 1013 u64 timestamp = sample->time; 1016 1014 1017 - wakee = machine__findnew_thread(machine, 0, pid); 1015 + wakee = machine__findnew_thread(machine, -1, pid); 1018 1016 atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid); 1019 1017 if (!atoms) { 1020 1018 if (thread_atoms_insert(sched, wakee)) ··· 1074 1072 if (sched->profile_cpu == -1) 1075 1073 return 0; 1076 1074 1077 - migrant = machine__findnew_thread(machine, 0, pid); 1075 + migrant = machine__findnew_thread(machine, -1, pid); 1078 1076 atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); 1079 1077 if (!atoms) { 1080 1078 if (thread_atoms_insert(sched, migrant)) ··· 1292 1290 return -1; 1293 1291 } 1294 1292 1295 - sched_in = machine__findnew_thread(machine, 0, next_pid); 1293 + sched_in = machine__findnew_thread(machine, -1, next_pid); 1296 1294 1297 1295 sched->curr_thread[this_cpu] = sched_in; 1298 1296
+19 -41
tools/perf/builtin-script.c
··· 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 361 static void print_sample_addr(union perf_event *event, 383 362 struct perf_sample *sample, 384 363 struct machine *machine, ··· 365 386 struct perf_event_attr *attr) 366 387 { 367 388 struct addr_location al; 368 - u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 369 389 370 390 printf("%16" PRIx64, sample->addr); 371 391 372 392 if (!sample_addr_correlates_sym(attr)) 373 393 return; 374 394 375 - thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 376 - sample->addr, &al); 377 - if (!al.map) 378 - thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE, 379 - sample->addr, &al); 380 - 381 - al.cpu = sample->cpu; 382 - al.sym = NULL; 383 - 384 - if (al.map) 385 - al.sym = map__find_symbol(al.map, al.addr, NULL); 395 + perf_event__preprocess_sample_addr(event, sample, machine, thread, &al); 386 396 387 397 if (PRINT_FIELD(SYM)) { 388 398 printf(" "); ··· 395 427 struct addr_location *al) 396 428 { 397 429 struct perf_event_attr *attr = &evsel->attr; 430 + bool print_srcline_last = false; 398 431 399 432 /* print branch_from information */ 400 433 if (PRINT_FIELD(IP)) { 401 - if (!symbol_conf.use_callchain) 402 - printf(" "); 403 - else 434 + unsigned int print_opts = output[attr->type].print_ip_opts; 435 + 436 + if (symbol_conf.use_callchain && sample->callchain) { 404 437 printf("\n"); 405 - perf_evsel__print_ip(evsel, sample, al, 406 - output[attr->type].print_ip_opts, 438 + } else { 439 + printf(" "); 440 + if (print_opts & PRINT_IP_OPT_SRCLINE) { 441 + print_srcline_last = true; 442 + print_opts &= ~PRINT_IP_OPT_SRCLINE; 443 + } 444 + } 445 + perf_evsel__print_ip(evsel, sample, al, print_opts, 407 446 PERF_MAX_STACK_DEPTH); 408 447 } 409 - 410 - printf(" => "); 411 448 412 449 /* print branch_to information */ 413 450 if (PRINT_FIELD(ADDR) || 414 451 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && 415 - !output[attr->type].user_set)) 452 + !output[attr->type].user_set)) { 453 + printf(" => "); 416 454 print_sample_addr(event, sample, al->machine, thread, attr); 455 + } 456 + 457 + if (print_srcline_last) 458 + map__fprintf_srcline(al->map, al->addr, "\n ", stdout); 417 459 418 460 printf("\n"); 419 461 }
+1 -1
tools/perf/builtin-stat.c
··· 184 184 static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) 185 185 { 186 186 evsel->priv = zalloc(sizeof(struct perf_stat)); 187 - if (evsel == NULL) 187 + if (evsel->priv == NULL) 188 188 return -ENOMEM; 189 189 perf_evsel__reset_stat_priv(evsel); 190 190 return 0;
+675 -19
tools/perf/builtin-timechart.c
··· 37 37 #include "util/svghelper.h" 38 38 #include "util/tool.h" 39 39 #include "util/data.h" 40 + #include "util/debug.h" 40 41 41 42 #define SUPPORT_OLD_POWER_EVENTS 1 42 43 #define PWR_EVENT_EXIT -1 ··· 61 60 tasks_only, 62 61 with_backtrace, 63 62 topology; 63 + /* IO related settings */ 64 + u64 io_events; 65 + bool io_only, 66 + skip_eagain; 67 + u64 min_time, 68 + merge_dist; 64 69 }; 65 70 66 71 struct per_pidcomm; 67 72 struct cpu_sample; 73 + struct io_sample; 68 74 69 75 /* 70 76 * Datastructure layout: ··· 92 84 u64 start_time; 93 85 u64 end_time; 94 86 u64 total_time; 87 + u64 total_bytes; 95 88 int display; 96 89 97 90 struct per_pidcomm *all; ··· 106 97 u64 start_time; 107 98 u64 end_time; 108 99 u64 total_time; 100 + u64 max_bytes; 101 + u64 total_bytes; 109 102 110 103 int Y; 111 104 int display; ··· 118 107 char *comm; 119 108 120 109 struct cpu_sample *samples; 110 + struct io_sample *io_samples; 121 111 }; 122 112 123 113 struct sample_wrapper { ··· 141 129 int type; 142 130 int cpu; 143 131 const char *backtrace; 132 + }; 133 + 134 + enum { 135 + IOTYPE_READ, 136 + IOTYPE_WRITE, 137 + IOTYPE_SYNC, 138 + IOTYPE_TX, 139 + IOTYPE_RX, 140 + IOTYPE_POLL, 141 + }; 142 + 143 + struct io_sample { 144 + struct io_sample *next; 145 + 146 + u64 start_time; 147 + u64 end_time; 148 + u64 bytes; 149 + int type; 150 + int fd; 151 + int err; 152 + int merges; 144 153 }; 145 154 146 155 #define CSTATE 1 ··· 246 213 pid_set_comm(tchart, pid, pp->current->comm); 247 214 248 215 p->start_time = timestamp; 249 - if (p->current) { 216 + if (p->current && !p->current->start_time) { 250 217 p->current->start_time = timestamp; 251 218 p->current->state_since = timestamp; 252 219 } ··· 715 682 } 716 683 } 717 684 685 + static int pid_begin_io_sample(struct timechart *tchart, int pid, int type, 686 + u64 start, int fd) 687 + { 688 + struct per_pid *p = find_create_pid(tchart, pid); 689 + struct per_pidcomm *c = p->current; 690 + struct io_sample *sample; 691 + struct io_sample *prev; 692 + 693 + if (!c) { 694 + c = zalloc(sizeof(*c)); 695 + if (!c) 696 + return -ENOMEM; 697 + p->current = c; 698 + c->next = p->all; 699 + p->all = c; 700 + } 701 + 702 + prev = c->io_samples; 703 + 704 + if (prev && prev->start_time && !prev->end_time) { 705 + pr_warning("Skip invalid start event: " 706 + "previous event already started!\n"); 707 + 708 + /* remove previous event that has been started, 709 + * we are not sure we will ever get an end for it */ 710 + c->io_samples = prev->next; 711 + free(prev); 712 + return 0; 713 + } 714 + 715 + sample = zalloc(sizeof(*sample)); 716 + if (!sample) 717 + return -ENOMEM; 718 + sample->start_time = start; 719 + sample->type = type; 720 + sample->fd = fd; 721 + sample->next = c->io_samples; 722 + c->io_samples = sample; 723 + 724 + if (c->start_time == 0 || c->start_time > start) 725 + c->start_time = start; 726 + 727 + return 0; 728 + } 729 + 730 + static int pid_end_io_sample(struct timechart *tchart, int pid, int type, 731 + u64 end, long ret) 732 + { 733 + struct per_pid *p = find_create_pid(tchart, pid); 734 + struct per_pidcomm *c = p->current; 735 + struct io_sample *sample, *prev; 736 + 737 + if (!c) { 738 + pr_warning("Invalid pidcomm!\n"); 739 + return -1; 740 + } 741 + 742 + sample = c->io_samples; 743 + 744 + if (!sample) /* skip partially captured events */ 745 + return 0; 746 + 747 + if (sample->end_time) { 748 + pr_warning("Skip invalid end event: " 749 + "previous event already ended!\n"); 750 + return 0; 751 + } 752 + 753 + if (sample->type != type) { 754 + pr_warning("Skip invalid end event: invalid event type!\n"); 755 + return 0; 756 + } 757 + 758 + sample->end_time = end; 759 + prev = sample->next; 760 + 761 + /* we want to be able to see small and fast transfers, so make them 762 + * at least min_time long, but don't overlap them */ 763 + if (sample->end_time - sample->start_time < tchart->min_time) 764 + sample->end_time = sample->start_time + tchart->min_time; 765 + if (prev && sample->start_time < prev->end_time) { 766 + if (prev->err) /* try to make errors more visible */ 767 + sample->start_time = prev->end_time; 768 + else 769 + prev->end_time = sample->start_time; 770 + } 771 + 772 + if (ret < 0) { 773 + sample->err = ret; 774 + } else if (type == IOTYPE_READ || type == IOTYPE_WRITE || 775 + type == IOTYPE_TX || type == IOTYPE_RX) { 776 + 777 + if ((u64)ret > c->max_bytes) 778 + c->max_bytes = ret; 779 + 780 + c->total_bytes += ret; 781 + p->total_bytes += ret; 782 + sample->bytes = ret; 783 + } 784 + 785 + /* merge two requests to make svg smaller and render-friendly */ 786 + if (prev && 787 + prev->type == sample->type && 788 + prev->err == sample->err && 789 + prev->fd == sample->fd && 790 + prev->end_time + tchart->merge_dist >= sample->start_time) { 791 + 792 + sample->bytes += prev->bytes; 793 + sample->merges += prev->merges + 1; 794 + 795 + sample->start_time = prev->start_time; 796 + sample->next = prev->next; 797 + free(prev); 798 + 799 + if (!sample->err && sample->bytes > c->max_bytes) 800 + c->max_bytes = sample->bytes; 801 + } 802 + 803 + tchart->io_events++; 804 + 805 + return 0; 806 + } 807 + 808 + static int 809 + process_enter_read(struct timechart *tchart, 810 + struct perf_evsel *evsel, 811 + struct perf_sample *sample) 812 + { 813 + long fd = perf_evsel__intval(evsel, sample, "fd"); 814 + return pid_begin_io_sample(tchart, sample->tid, IOTYPE_READ, 815 + sample->time, fd); 816 + } 817 + 818 + static int 819 + process_exit_read(struct timechart *tchart, 820 + struct perf_evsel *evsel, 821 + struct perf_sample *sample) 822 + { 823 + long ret = perf_evsel__intval(evsel, sample, "ret"); 824 + return pid_end_io_sample(tchart, sample->tid, IOTYPE_READ, 825 + sample->time, ret); 826 + } 827 + 828 + static int 829 + process_enter_write(struct timechart *tchart, 830 + struct perf_evsel *evsel, 831 + struct perf_sample *sample) 832 + { 833 + long fd = perf_evsel__intval(evsel, sample, "fd"); 834 + return pid_begin_io_sample(tchart, sample->tid, IOTYPE_WRITE, 835 + sample->time, fd); 836 + } 837 + 838 + static int 839 + process_exit_write(struct timechart *tchart, 840 + struct perf_evsel *evsel, 841 + struct perf_sample *sample) 842 + { 843 + long ret = perf_evsel__intval(evsel, sample, "ret"); 844 + return pid_end_io_sample(tchart, sample->tid, IOTYPE_WRITE, 845 + sample->time, ret); 846 + } 847 + 848 + static int 849 + process_enter_sync(struct timechart *tchart, 850 + struct perf_evsel *evsel, 851 + struct perf_sample *sample) 852 + { 853 + long fd = perf_evsel__intval(evsel, sample, "fd"); 854 + return pid_begin_io_sample(tchart, sample->tid, IOTYPE_SYNC, 855 + sample->time, fd); 856 + } 857 + 858 + static int 859 + process_exit_sync(struct timechart *tchart, 860 + struct perf_evsel *evsel, 861 + struct perf_sample *sample) 862 + { 863 + long ret = perf_evsel__intval(evsel, sample, "ret"); 864 + return pid_end_io_sample(tchart, sample->tid, IOTYPE_SYNC, 865 + sample->time, ret); 866 + } 867 + 868 + static int 869 + process_enter_tx(struct timechart *tchart, 870 + struct perf_evsel *evsel, 871 + struct perf_sample *sample) 872 + { 873 + long fd = perf_evsel__intval(evsel, sample, "fd"); 874 + return pid_begin_io_sample(tchart, sample->tid, IOTYPE_TX, 875 + sample->time, fd); 876 + } 877 + 878 + static int 879 + process_exit_tx(struct timechart *tchart, 880 + struct perf_evsel *evsel, 881 + struct perf_sample *sample) 882 + { 883 + long ret = perf_evsel__intval(evsel, sample, "ret"); 884 + return pid_end_io_sample(tchart, sample->tid, IOTYPE_TX, 885 + sample->time, ret); 886 + } 887 + 888 + static int 889 + process_enter_rx(struct timechart *tchart, 890 + struct perf_evsel *evsel, 891 + struct perf_sample *sample) 892 + { 893 + long fd = perf_evsel__intval(evsel, sample, "fd"); 894 + return pid_begin_io_sample(tchart, sample->tid, IOTYPE_RX, 895 + sample->time, fd); 896 + } 897 + 898 + static int 899 + process_exit_rx(struct timechart *tchart, 900 + struct perf_evsel *evsel, 901 + struct perf_sample *sample) 902 + { 903 + long ret = perf_evsel__intval(evsel, sample, "ret"); 904 + return pid_end_io_sample(tchart, sample->tid, IOTYPE_RX, 905 + sample->time, ret); 906 + } 907 + 908 + static int 909 + process_enter_poll(struct timechart *tchart, 910 + struct perf_evsel *evsel, 911 + struct perf_sample *sample) 912 + { 913 + long fd = perf_evsel__intval(evsel, sample, "fd"); 914 + return pid_begin_io_sample(tchart, sample->tid, IOTYPE_POLL, 915 + sample->time, fd); 916 + } 917 + 918 + static int 919 + process_exit_poll(struct timechart *tchart, 920 + struct perf_evsel *evsel, 921 + struct perf_sample *sample) 922 + { 923 + long ret = perf_evsel__intval(evsel, sample, "ret"); 924 + return pid_end_io_sample(tchart, sample->tid, IOTYPE_POLL, 925 + sample->time, ret); 926 + } 927 + 718 928 /* 719 929 * Sort the pid datastructure 720 930 */ ··· 1128 852 } 1129 853 } 1130 854 855 + static void draw_io_bars(struct timechart *tchart) 856 + { 857 + const char *suf; 858 + double bytes; 859 + char comm[256]; 860 + struct per_pid *p; 861 + struct per_pidcomm *c; 862 + struct io_sample *sample; 863 + int Y = 1; 864 + 865 + p = tchart->all_data; 866 + while (p) { 867 + c = p->all; 868 + while (c) { 869 + if (!c->display) { 870 + c->Y = 0; 871 + c = c->next; 872 + continue; 873 + } 874 + 875 + svg_box(Y, c->start_time, c->end_time, "process3"); 876 + sample = c->io_samples; 877 + for (sample = c->io_samples; sample; sample = sample->next) { 878 + double h = (double)sample->bytes / c->max_bytes; 879 + 880 + if (tchart->skip_eagain && 881 + sample->err == -EAGAIN) 882 + continue; 883 + 884 + if (sample->err) 885 + h = 1; 886 + 887 + if (sample->type == IOTYPE_SYNC) 888 + svg_fbox(Y, 889 + sample->start_time, 890 + sample->end_time, 891 + 1, 892 + sample->err ? "error" : "sync", 893 + sample->fd, 894 + sample->err, 895 + sample->merges); 896 + else if (sample->type == IOTYPE_POLL) 897 + svg_fbox(Y, 898 + sample->start_time, 899 + sample->end_time, 900 + 1, 901 + sample->err ? "error" : "poll", 902 + sample->fd, 903 + sample->err, 904 + sample->merges); 905 + else if (sample->type == IOTYPE_READ) 906 + svg_ubox(Y, 907 + sample->start_time, 908 + sample->end_time, 909 + h, 910 + sample->err ? "error" : "disk", 911 + sample->fd, 912 + sample->err, 913 + sample->merges); 914 + else if (sample->type == IOTYPE_WRITE) 915 + svg_lbox(Y, 916 + sample->start_time, 917 + sample->end_time, 918 + h, 919 + sample->err ? "error" : "disk", 920 + sample->fd, 921 + sample->err, 922 + sample->merges); 923 + else if (sample->type == IOTYPE_RX) 924 + svg_ubox(Y, 925 + sample->start_time, 926 + sample->end_time, 927 + h, 928 + sample->err ? "error" : "net", 929 + sample->fd, 930 + sample->err, 931 + sample->merges); 932 + else if (sample->type == IOTYPE_TX) 933 + svg_lbox(Y, 934 + sample->start_time, 935 + sample->end_time, 936 + h, 937 + sample->err ? "error" : "net", 938 + sample->fd, 939 + sample->err, 940 + sample->merges); 941 + } 942 + 943 + suf = ""; 944 + bytes = c->total_bytes; 945 + if (bytes > 1024) { 946 + bytes = bytes / 1024; 947 + suf = "K"; 948 + } 949 + if (bytes > 1024) { 950 + bytes = bytes / 1024; 951 + suf = "M"; 952 + } 953 + if (bytes > 1024) { 954 + bytes = bytes / 1024; 955 + suf = "G"; 956 + } 957 + 958 + 959 + sprintf(comm, "%s:%i (%3.1f %sbytes)", c->comm ?: "", p->pid, bytes, suf); 960 + svg_text(Y, c->start_time, comm); 961 + 962 + c->Y = Y; 963 + Y++; 964 + c = c->next; 965 + } 966 + p = p->next; 967 + } 968 + } 969 + 1131 970 static void draw_process_bars(struct timechart *tchart) 1132 971 { 1133 972 struct per_pid *p; ··· 1378 987 struct per_pidcomm *c; 1379 988 int count = 0; 1380 989 1381 - if (process_filter) 1382 - return determine_display_tasks_filtered(tchart); 1383 - 1384 990 p = tchart->all_data; 1385 991 while (p) { 1386 992 p->display = 0; ··· 1413 1025 return count; 1414 1026 } 1415 1027 1028 + static int determine_display_io_tasks(struct timechart *timechart, u64 threshold) 1029 + { 1030 + struct per_pid *p; 1031 + struct per_pidcomm *c; 1032 + int count = 0; 1416 1033 1034 + p = timechart->all_data; 1035 + while (p) { 1036 + /* no exit marker, task kept running to the end */ 1037 + if (p->end_time == 0) 1038 + p->end_time = timechart->last_time; 1417 1039 1040 + c = p->all; 1041 + 1042 + while (c) { 1043 + c->display = 0; 1044 + 1045 + if (c->total_bytes >= threshold) { 1046 + c->display = 1; 1047 + count++; 1048 + } 1049 + 1050 + if (c->end_time == 0) 1051 + c->end_time = timechart->last_time; 1052 + 1053 + c = c->next; 1054 + } 1055 + p = p->next; 1056 + } 1057 + return count; 1058 + } 1059 + 1060 + #define BYTES_THRESH (1 * 1024 * 1024) 1418 1061 #define TIME_THRESH 10000000 1419 1062 1420 1063 static void write_svg_file(struct timechart *tchart, const char *filename) 1421 1064 { 1422 1065 u64 i; 1423 1066 int count; 1424 - int thresh = TIME_THRESH; 1067 + int thresh = tchart->io_events ? BYTES_THRESH : TIME_THRESH; 1425 1068 1426 1069 if (tchart->power_only) 1427 1070 tchart->proc_num = 0; ··· 1460 1041 /* We'd like to show at least proc_num tasks; 1461 1042 * be less picky if we have fewer */ 1462 1043 do { 1463 - count = determine_display_tasks(tchart, thresh); 1044 + if (process_filter) 1045 + count = determine_display_tasks_filtered(tchart); 1046 + else if (tchart->io_events) 1047 + count = determine_display_io_tasks(tchart, thresh); 1048 + else 1049 + count = determine_display_tasks(tchart, thresh); 1464 1050 thresh /= 10; 1465 1051 } while (!process_filter && thresh && count < tchart->proc_num); 1466 1052 1467 1053 if (!tchart->proc_num) 1468 1054 count = 0; 1469 1055 1470 - open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time); 1056 + if (tchart->io_events) { 1057 + open_svg(filename, 0, count, tchart->first_time, tchart->last_time); 1471 1058 1472 - svg_time_grid(); 1473 - svg_legenda(); 1059 + svg_time_grid(0.5); 1060 + svg_io_legenda(); 1474 1061 1475 - for (i = 0; i < tchart->numcpus; i++) 1476 - svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency); 1062 + draw_io_bars(tchart); 1063 + } else { 1064 + open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time); 1477 1065 1478 - draw_cpu_usage(tchart); 1479 - if (tchart->proc_num) 1480 - draw_process_bars(tchart); 1481 - if (!tchart->tasks_only) 1482 - draw_c_p_states(tchart); 1483 - if (tchart->proc_num) 1484 - draw_wakeups(tchart); 1066 + svg_time_grid(0); 1067 + 1068 + svg_legenda(); 1069 + 1070 + for (i = 0; i < tchart->numcpus; i++) 1071 + svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency); 1072 + 1073 + draw_cpu_usage(tchart); 1074 + if (tchart->proc_num) 1075 + draw_process_bars(tchart); 1076 + if (!tchart->tasks_only) 1077 + draw_c_p_states(tchart); 1078 + if (tchart->proc_num) 1079 + draw_wakeups(tchart); 1080 + } 1485 1081 1486 1082 svg_close(); 1487 1083 } ··· 1544 1110 { "power:power_end", process_sample_power_end }, 1545 1111 { "power:power_frequency", process_sample_power_frequency }, 1546 1112 #endif 1113 + 1114 + { "syscalls:sys_enter_read", process_enter_read }, 1115 + { "syscalls:sys_enter_pread64", process_enter_read }, 1116 + { "syscalls:sys_enter_readv", process_enter_read }, 1117 + { "syscalls:sys_enter_preadv", process_enter_read }, 1118 + { "syscalls:sys_enter_write", process_enter_write }, 1119 + { "syscalls:sys_enter_pwrite64", process_enter_write }, 1120 + { "syscalls:sys_enter_writev", process_enter_write }, 1121 + { "syscalls:sys_enter_pwritev", process_enter_write }, 1122 + { "syscalls:sys_enter_sync", process_enter_sync }, 1123 + { "syscalls:sys_enter_sync_file_range", process_enter_sync }, 1124 + { "syscalls:sys_enter_fsync", process_enter_sync }, 1125 + { "syscalls:sys_enter_msync", process_enter_sync }, 1126 + { "syscalls:sys_enter_recvfrom", process_enter_rx }, 1127 + { "syscalls:sys_enter_recvmmsg", process_enter_rx }, 1128 + { "syscalls:sys_enter_recvmsg", process_enter_rx }, 1129 + { "syscalls:sys_enter_sendto", process_enter_tx }, 1130 + { "syscalls:sys_enter_sendmsg", process_enter_tx }, 1131 + { "syscalls:sys_enter_sendmmsg", process_enter_tx }, 1132 + { "syscalls:sys_enter_epoll_pwait", process_enter_poll }, 1133 + { "syscalls:sys_enter_epoll_wait", process_enter_poll }, 1134 + { "syscalls:sys_enter_poll", process_enter_poll }, 1135 + { "syscalls:sys_enter_ppoll", process_enter_poll }, 1136 + { "syscalls:sys_enter_pselect6", process_enter_poll }, 1137 + { "syscalls:sys_enter_select", process_enter_poll }, 1138 + 1139 + { "syscalls:sys_exit_read", process_exit_read }, 1140 + { "syscalls:sys_exit_pread64", process_exit_read }, 1141 + { "syscalls:sys_exit_readv", process_exit_read }, 1142 + { "syscalls:sys_exit_preadv", process_exit_read }, 1143 + { "syscalls:sys_exit_write", process_exit_write }, 1144 + { "syscalls:sys_exit_pwrite64", process_exit_write }, 1145 + { "syscalls:sys_exit_writev", process_exit_write }, 1146 + { "syscalls:sys_exit_pwritev", process_exit_write }, 1147 + { "syscalls:sys_exit_sync", process_exit_sync }, 1148 + { "syscalls:sys_exit_sync_file_range", process_exit_sync }, 1149 + { "syscalls:sys_exit_fsync", process_exit_sync }, 1150 + { "syscalls:sys_exit_msync", process_exit_sync }, 1151 + { "syscalls:sys_exit_recvfrom", process_exit_rx }, 1152 + { "syscalls:sys_exit_recvmmsg", process_exit_rx }, 1153 + { "syscalls:sys_exit_recvmsg", process_exit_rx }, 1154 + { "syscalls:sys_exit_sendto", process_exit_tx }, 1155 + { "syscalls:sys_exit_sendmsg", process_exit_tx }, 1156 + { "syscalls:sys_exit_sendmmsg", process_exit_tx }, 1157 + { "syscalls:sys_exit_epoll_pwait", process_exit_poll }, 1158 + { "syscalls:sys_exit_epoll_wait", process_exit_poll }, 1159 + { "syscalls:sys_exit_poll", process_exit_poll }, 1160 + { "syscalls:sys_exit_ppoll", process_exit_poll }, 1161 + { "syscalls:sys_exit_pselect6", process_exit_poll }, 1162 + { "syscalls:sys_exit_select", process_exit_poll }, 1547 1163 }; 1548 1164 struct perf_data_file file = { 1549 1165 .path = input_name, ··· 1637 1153 perf_session__delete(session); 1638 1154 return ret; 1639 1155 } 1156 + 1157 + static int timechart__io_record(int argc, const char **argv) 1158 + { 1159 + unsigned int rec_argc, i; 1160 + const char **rec_argv; 1161 + const char **p; 1162 + char *filter = NULL; 1163 + 1164 + const char * const common_args[] = { 1165 + "record", "-a", "-R", "-c", "1", 1166 + }; 1167 + unsigned int common_args_nr = ARRAY_SIZE(common_args); 1168 + 1169 + const char * const disk_events[] = { 1170 + "syscalls:sys_enter_read", 1171 + "syscalls:sys_enter_pread64", 1172 + "syscalls:sys_enter_readv", 1173 + "syscalls:sys_enter_preadv", 1174 + "syscalls:sys_enter_write", 1175 + "syscalls:sys_enter_pwrite64", 1176 + "syscalls:sys_enter_writev", 1177 + "syscalls:sys_enter_pwritev", 1178 + "syscalls:sys_enter_sync", 1179 + "syscalls:sys_enter_sync_file_range", 1180 + "syscalls:sys_enter_fsync", 1181 + "syscalls:sys_enter_msync", 1182 + 1183 + "syscalls:sys_exit_read", 1184 + "syscalls:sys_exit_pread64", 1185 + "syscalls:sys_exit_readv", 1186 + "syscalls:sys_exit_preadv", 1187 + "syscalls:sys_exit_write", 1188 + "syscalls:sys_exit_pwrite64", 1189 + "syscalls:sys_exit_writev", 1190 + "syscalls:sys_exit_pwritev", 1191 + "syscalls:sys_exit_sync", 1192 + "syscalls:sys_exit_sync_file_range", 1193 + "syscalls:sys_exit_fsync", 1194 + "syscalls:sys_exit_msync", 1195 + }; 1196 + unsigned int disk_events_nr = ARRAY_SIZE(disk_events); 1197 + 1198 + const char * const net_events[] = { 1199 + "syscalls:sys_enter_recvfrom", 1200 + "syscalls:sys_enter_recvmmsg", 1201 + "syscalls:sys_enter_recvmsg", 1202 + "syscalls:sys_enter_sendto", 1203 + "syscalls:sys_enter_sendmsg", 1204 + "syscalls:sys_enter_sendmmsg", 1205 + 1206 + "syscalls:sys_exit_recvfrom", 1207 + "syscalls:sys_exit_recvmmsg", 1208 + "syscalls:sys_exit_recvmsg", 1209 + "syscalls:sys_exit_sendto", 1210 + "syscalls:sys_exit_sendmsg", 1211 + "syscalls:sys_exit_sendmmsg", 1212 + }; 1213 + unsigned int net_events_nr = ARRAY_SIZE(net_events); 1214 + 1215 + const char * const poll_events[] = { 1216 + "syscalls:sys_enter_epoll_pwait", 1217 + "syscalls:sys_enter_epoll_wait", 1218 + "syscalls:sys_enter_poll", 1219 + "syscalls:sys_enter_ppoll", 1220 + "syscalls:sys_enter_pselect6", 1221 + "syscalls:sys_enter_select", 1222 + 1223 + "syscalls:sys_exit_epoll_pwait", 1224 + "syscalls:sys_exit_epoll_wait", 1225 + "syscalls:sys_exit_poll", 1226 + "syscalls:sys_exit_ppoll", 1227 + "syscalls:sys_exit_pselect6", 1228 + "syscalls:sys_exit_select", 1229 + }; 1230 + unsigned int poll_events_nr = ARRAY_SIZE(poll_events); 1231 + 1232 + rec_argc = common_args_nr + 1233 + disk_events_nr * 4 + 1234 + net_events_nr * 4 + 1235 + poll_events_nr * 4 + 1236 + argc; 1237 + rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1238 + 1239 + if (rec_argv == NULL) 1240 + return -ENOMEM; 1241 + 1242 + if (asprintf(&filter, "common_pid != %d", getpid()) < 0) 1243 + return -ENOMEM; 1244 + 1245 + p = rec_argv; 1246 + for (i = 0; i < common_args_nr; i++) 1247 + *p++ = strdup(common_args[i]); 1248 + 1249 + for (i = 0; i < disk_events_nr; i++) { 1250 + if (!is_valid_tracepoint(disk_events[i])) { 1251 + rec_argc -= 4; 1252 + continue; 1253 + } 1254 + 1255 + *p++ = "-e"; 1256 + *p++ = strdup(disk_events[i]); 1257 + *p++ = "--filter"; 1258 + *p++ = filter; 1259 + } 1260 + for (i = 0; i < net_events_nr; i++) { 1261 + if (!is_valid_tracepoint(net_events[i])) { 1262 + rec_argc -= 4; 1263 + continue; 1264 + } 1265 + 1266 + *p++ = "-e"; 1267 + *p++ = strdup(net_events[i]); 1268 + *p++ = "--filter"; 1269 + *p++ = filter; 1270 + } 1271 + for (i = 0; i < poll_events_nr; i++) { 1272 + if (!is_valid_tracepoint(poll_events[i])) { 1273 + rec_argc -= 4; 1274 + continue; 1275 + } 1276 + 1277 + *p++ = "-e"; 1278 + *p++ = strdup(poll_events[i]); 1279 + *p++ = "--filter"; 1280 + *p++ = filter; 1281 + } 1282 + 1283 + for (i = 0; i < (unsigned int)argc; i++) 1284 + *p++ = argv[i]; 1285 + 1286 + return cmd_record(rec_argc, rec_argv, NULL); 1287 + } 1288 + 1640 1289 1641 1290 static int timechart__record(struct timechart *tchart, int argc, const char **argv) 1642 1291 { ··· 1887 1270 return 0; 1888 1271 } 1889 1272 1273 + static int 1274 + parse_time(const struct option *opt, const char *arg, int __maybe_unused unset) 1275 + { 1276 + char unit = 'n'; 1277 + u64 *value = opt->value; 1278 + 1279 + if (sscanf(arg, "%" PRIu64 "%cs", value, &unit) > 0) { 1280 + switch (unit) { 1281 + case 'm': 1282 + *value *= 1000000; 1283 + break; 1284 + case 'u': 1285 + *value *= 1000; 1286 + break; 1287 + case 'n': 1288 + break; 1289 + default: 1290 + return -1; 1291 + } 1292 + } 1293 + 1294 + return 0; 1295 + } 1296 + 1890 1297 int cmd_timechart(int argc, const char **argv, 1891 1298 const char *prefix __maybe_unused) 1892 1299 { ··· 1923 1282 .ordered_samples = true, 1924 1283 }, 1925 1284 .proc_num = 15, 1285 + .min_time = 1000000, 1286 + .merge_dist = 1000, 1926 1287 }; 1927 1288 const char *output_name = "output.svg"; 1928 1289 const struct option timechart_options[] = { ··· 1946 1303 "min. number of tasks to print"), 1947 1304 OPT_BOOLEAN('t', "topology", &tchart.topology, 1948 1305 "sort CPUs according to topology"), 1306 + OPT_BOOLEAN(0, "io-skip-eagain", &tchart.skip_eagain, 1307 + "skip EAGAIN errors"), 1308 + OPT_CALLBACK(0, "io-min-time", &tchart.min_time, "time", 1309 + "all IO faster than min-time will visually appear longer", 1310 + parse_time), 1311 + OPT_CALLBACK(0, "io-merge-dist", &tchart.merge_dist, "time", 1312 + "merge events that are merge-dist us apart", 1313 + parse_time), 1949 1314 OPT_END() 1950 1315 }; 1951 1316 const char * const timechart_usage[] = { ··· 1965 1314 OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"), 1966 1315 OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only, 1967 1316 "output processes data only"), 1317 + OPT_BOOLEAN('I', "io-only", &tchart.io_only, 1318 + "record only IO data"), 1968 1319 OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"), 1969 1320 OPT_END() 1970 1321 }; ··· 1993 1340 return -1; 1994 1341 } 1995 1342 1996 - return timechart__record(&tchart, argc, argv); 1343 + if (tchart.io_only) 1344 + return timechart__io_record(argc, argv); 1345 + else 1346 + return timechart__record(&tchart, argc, argv); 1997 1347 } else if (argc) 1998 1348 usage_with_options(timechart_usage, timechart_options); 1999 1349
+221 -43
tools/perf/builtin-trace.c
··· 1108 1108 struct event_format *tp_format; 1109 1109 const char *name; 1110 1110 bool filtered; 1111 + bool is_exit; 1111 1112 struct syscall_fmt *fmt; 1112 1113 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg); 1113 1114 void **arg_parm; ··· 1133 1132 u64 exit_time; 1134 1133 bool entry_pending; 1135 1134 unsigned long nr_events; 1135 + unsigned long pfmaj, pfmin; 1136 1136 char *entry_str; 1137 1137 double runtime_ms; 1138 1138 struct { ··· 1179 1177 return NULL; 1180 1178 } 1181 1179 1180 + #define TRACE_PFMAJ (1 << 0) 1181 + #define TRACE_PFMIN (1 << 1) 1182 + 1182 1183 struct trace { 1183 1184 struct perf_tool tool; 1184 1185 struct { ··· 1216 1211 bool summary_only; 1217 1212 bool show_comm; 1218 1213 bool show_tool_stats; 1214 + bool trace_syscalls; 1215 + int trace_pgfaults; 1219 1216 }; 1220 1217 1221 1218 static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) ··· 1283 1276 if (fd < 0) 1284 1277 return NULL; 1285 1278 1286 - if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) 1279 + if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) { 1287 1280 if (!trace->live) 1288 1281 return NULL; 1289 1282 ++trace->stats.proc_getname; 1290 - if (thread__read_fd_path(thread, fd)) { 1283 + if (thread__read_fd_path(thread, fd)) 1291 1284 return NULL; 1292 1285 } 1293 1286 ··· 1480 1473 if (sc->tp_format == NULL) 1481 1474 return -1; 1482 1475 1476 + sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit"); 1477 + 1483 1478 return syscall__set_arg_fmts(sc); 1484 1479 } 1485 1480 ··· 1544 1535 } 1545 1536 1546 1537 typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel, 1538 + union perf_event *event, 1547 1539 struct perf_sample *sample); 1548 1540 1549 1541 static struct syscall *trace__syscall_info(struct trace *trace, ··· 1617 1607 } 1618 1608 1619 1609 static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, 1610 + union perf_event *event __maybe_unused, 1620 1611 struct perf_sample *sample) 1621 1612 { 1622 1613 char *msg; ··· 1640 1629 return -1; 1641 1630 1642 1631 args = perf_evsel__sc_tp_ptr(evsel, args, sample); 1643 - ttrace = thread->priv; 1644 1632 1645 1633 if (ttrace->entry_str == NULL) { 1646 1634 ttrace->entry_str = malloc(1024); ··· 1654 1644 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, 1655 1645 args, trace, thread); 1656 1646 1657 - if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) { 1647 + if (sc->is_exit) { 1658 1648 if (!trace->duration_filter && !trace->summary_only) { 1659 1649 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output); 1660 1650 fprintf(trace->output, "%-70s\n", ttrace->entry_str); ··· 1666 1656 } 1667 1657 1668 1658 static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, 1659 + union perf_event *event __maybe_unused, 1669 1660 struct perf_sample *sample) 1670 1661 { 1671 1662 int ret; ··· 1697 1686 trace->last_vfs_getname = NULL; 1698 1687 ++trace->stats.vfs_getname; 1699 1688 } 1700 - 1701 - ttrace = thread->priv; 1702 1689 1703 1690 ttrace->exit_time = sample->time; 1704 1691 ··· 1744 1735 } 1745 1736 1746 1737 static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel, 1738 + union perf_event *event __maybe_unused, 1747 1739 struct perf_sample *sample) 1748 1740 { 1749 1741 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname"); ··· 1752 1742 } 1753 1743 1754 1744 static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel, 1745 + union perf_event *event __maybe_unused, 1755 1746 struct perf_sample *sample) 1756 1747 { 1757 1748 u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); ··· 1779 1768 return 0; 1780 1769 } 1781 1770 1771 + static void print_location(FILE *f, struct perf_sample *sample, 1772 + struct addr_location *al, 1773 + bool print_dso, bool print_sym) 1774 + { 1775 + 1776 + if ((verbose || print_dso) && al->map) 1777 + fprintf(f, "%s@", al->map->dso->long_name); 1778 + 1779 + if ((verbose || print_sym) && al->sym) 1780 + fprintf(f, "%s+0x%" PRIx64, al->sym->name, 1781 + al->addr - al->sym->start); 1782 + else if (al->map) 1783 + fprintf(f, "0x%" PRIx64, al->addr); 1784 + else 1785 + fprintf(f, "0x%" PRIx64, sample->addr); 1786 + } 1787 + 1788 + static int trace__pgfault(struct trace *trace, 1789 + struct perf_evsel *evsel, 1790 + union perf_event *event, 1791 + struct perf_sample *sample) 1792 + { 1793 + struct thread *thread; 1794 + u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 1795 + struct addr_location al; 1796 + char map_type = 'd'; 1797 + struct thread_trace *ttrace; 1798 + 1799 + thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); 1800 + ttrace = thread__trace(thread, trace->output); 1801 + if (ttrace == NULL) 1802 + return -1; 1803 + 1804 + if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ) 1805 + ttrace->pfmaj++; 1806 + else 1807 + ttrace->pfmin++; 1808 + 1809 + if (trace->summary_only) 1810 + return 0; 1811 + 1812 + thread__find_addr_location(thread, trace->host, cpumode, MAP__FUNCTION, 1813 + sample->ip, &al); 1814 + 1815 + trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output); 1816 + 1817 + fprintf(trace->output, "%sfault [", 1818 + evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ? 1819 + "maj" : "min"); 1820 + 1821 + print_location(trace->output, sample, &al, false, true); 1822 + 1823 + fprintf(trace->output, "] => "); 1824 + 1825 + thread__find_addr_location(thread, trace->host, cpumode, MAP__VARIABLE, 1826 + sample->addr, &al); 1827 + 1828 + if (!al.map) { 1829 + thread__find_addr_location(thread, trace->host, cpumode, 1830 + MAP__FUNCTION, sample->addr, &al); 1831 + 1832 + if (al.map) 1833 + map_type = 'x'; 1834 + else 1835 + map_type = '?'; 1836 + } 1837 + 1838 + print_location(trace->output, sample, &al, true, false); 1839 + 1840 + fprintf(trace->output, " (%c%c)\n", map_type, al.level); 1841 + 1842 + return 0; 1843 + } 1844 + 1782 1845 static bool skip_sample(struct trace *trace, struct perf_sample *sample) 1783 1846 { 1784 1847 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) || ··· 1866 1781 } 1867 1782 1868 1783 static int trace__process_sample(struct perf_tool *tool, 1869 - union perf_event *event __maybe_unused, 1784 + union perf_event *event, 1870 1785 struct perf_sample *sample, 1871 1786 struct perf_evsel *evsel, 1872 1787 struct machine *machine __maybe_unused) ··· 1884 1799 1885 1800 if (handler) { 1886 1801 ++trace->nr_events; 1887 - handler(trace, evsel, sample); 1802 + handler(trace, evsel, event, sample); 1888 1803 } 1889 1804 1890 1805 return err; ··· 1911 1826 return 0; 1912 1827 } 1913 1828 1914 - static int trace__record(int argc, const char **argv) 1829 + static int trace__record(struct trace *trace, int argc, const char **argv) 1915 1830 { 1916 1831 unsigned int rec_argc, i, j; 1917 1832 const char **rec_argv; ··· 1920 1835 "-R", 1921 1836 "-m", "1024", 1922 1837 "-c", "1", 1923 - "-e", 1924 1838 }; 1925 1839 1840 + const char * const sc_args[] = { "-e", }; 1841 + unsigned int sc_args_nr = ARRAY_SIZE(sc_args); 1842 + const char * const majpf_args[] = { "-e", "major-faults" }; 1843 + unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args); 1844 + const char * const minpf_args[] = { "-e", "minor-faults" }; 1845 + unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args); 1846 + 1926 1847 /* +1 is for the event string below */ 1927 - rec_argc = ARRAY_SIZE(record_args) + 1 + argc; 1848 + rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 + 1849 + majpf_args_nr + minpf_args_nr + argc; 1928 1850 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1929 1851 1930 1852 if (rec_argv == NULL) 1931 1853 return -ENOMEM; 1932 1854 1855 + j = 0; 1933 1856 for (i = 0; i < ARRAY_SIZE(record_args); i++) 1934 - rec_argv[i] = record_args[i]; 1857 + rec_argv[j++] = record_args[i]; 1935 1858 1936 - /* event string may be different for older kernels - e.g., RHEL6 */ 1937 - if (is_valid_tracepoint("raw_syscalls:sys_enter")) 1938 - rec_argv[i] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit"; 1939 - else if (is_valid_tracepoint("syscalls:sys_enter")) 1940 - rec_argv[i] = "syscalls:sys_enter,syscalls:sys_exit"; 1941 - else { 1942 - pr_err("Neither raw_syscalls nor syscalls events exist.\n"); 1943 - return -1; 1859 + if (trace->trace_syscalls) { 1860 + for (i = 0; i < sc_args_nr; i++) 1861 + rec_argv[j++] = sc_args[i]; 1862 + 1863 + /* event string may be different for older kernels - e.g., RHEL6 */ 1864 + if (is_valid_tracepoint("raw_syscalls:sys_enter")) 1865 + rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit"; 1866 + else if (is_valid_tracepoint("syscalls:sys_enter")) 1867 + rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit"; 1868 + else { 1869 + pr_err("Neither raw_syscalls nor syscalls events exist.\n"); 1870 + return -1; 1871 + } 1944 1872 } 1945 - i++; 1946 1873 1947 - for (j = 0; j < (unsigned int)argc; j++, i++) 1948 - rec_argv[i] = argv[j]; 1874 + if (trace->trace_pgfaults & TRACE_PFMAJ) 1875 + for (i = 0; i < majpf_args_nr; i++) 1876 + rec_argv[j++] = majpf_args[i]; 1949 1877 1950 - return cmd_record(i, rec_argv, NULL); 1878 + if (trace->trace_pgfaults & TRACE_PFMIN) 1879 + for (i = 0; i < minpf_args_nr; i++) 1880 + rec_argv[j++] = minpf_args[i]; 1881 + 1882 + for (i = 0; i < (unsigned int)argc; i++) 1883 + rec_argv[j++] = argv[i]; 1884 + 1885 + return cmd_record(j, rec_argv, NULL); 1951 1886 } 1952 1887 1953 1888 static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp); ··· 1987 1882 perf_evlist__add(evlist, evsel); 1988 1883 } 1989 1884 1885 + static int perf_evlist__add_pgfault(struct perf_evlist *evlist, 1886 + u64 config) 1887 + { 1888 + struct perf_evsel *evsel; 1889 + struct perf_event_attr attr = { 1890 + .type = PERF_TYPE_SOFTWARE, 1891 + .mmap_data = 1, 1892 + }; 1893 + 1894 + attr.config = config; 1895 + attr.sample_period = 1; 1896 + 1897 + event_attr_init(&attr); 1898 + 1899 + evsel = perf_evsel__new(&attr); 1900 + if (!evsel) 1901 + return -ENOMEM; 1902 + 1903 + evsel->handler = trace__pgfault; 1904 + perf_evlist__add(evlist, evsel); 1905 + 1906 + return 0; 1907 + } 1908 + 1990 1909 static int trace__run(struct trace *trace, int argc, const char **argv) 1991 1910 { 1992 1911 struct perf_evlist *evlist = perf_evlist__new(); ··· 2026 1897 goto out; 2027 1898 } 2028 1899 2029 - if (perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, trace__sys_exit)) 1900 + if (trace->trace_syscalls && 1901 + perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, 1902 + trace__sys_exit)) 2030 1903 goto out_error_tp; 2031 1904 2032 - perf_evlist__add_vfs_getname(evlist); 1905 + if (trace->trace_syscalls) 1906 + perf_evlist__add_vfs_getname(evlist); 1907 + 1908 + if ((trace->trace_pgfaults & TRACE_PFMAJ) && 1909 + perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) 1910 + goto out_error_tp; 1911 + 1912 + if ((trace->trace_pgfaults & TRACE_PFMIN) && 1913 + perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN)) 1914 + goto out_error_tp; 2033 1915 2034 1916 if (trace->sched && 2035 1917 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", ··· 2122 1982 goto next_event; 2123 1983 } 2124 1984 2125 - if (sample.raw_data == NULL) { 1985 + if (evsel->attr.type == PERF_TYPE_TRACEPOINT && 1986 + sample.raw_data == NULL) { 2126 1987 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", 2127 1988 perf_evsel__name(evsel), sample.tid, 2128 1989 sample.cpu, sample.raw_size); ··· 2131 1990 } 2132 1991 2133 1992 handler = evsel->handler; 2134 - handler(trace, evsel, &sample); 1993 + handler(trace, evsel, event, &sample); 2135 1994 next_event: 2136 1995 perf_evlist__mmap_consume(evlist, i); 2137 1996 ··· 2234 2093 if (evsel == NULL) 2235 2094 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, 2236 2095 "syscalls:sys_enter"); 2237 - if (evsel == NULL) { 2238 - pr_err("Data file does not have raw_syscalls:sys_enter event\n"); 2239 - goto out; 2240 - } 2241 2096 2242 - if (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 || 2243 - perf_evsel__init_sc_tp_ptr_field(evsel, args)) { 2097 + if (evsel && 2098 + (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 || 2099 + perf_evsel__init_sc_tp_ptr_field(evsel, args))) { 2244 2100 pr_err("Error during initialize raw_syscalls:sys_enter event\n"); 2245 2101 goto out; 2246 2102 } ··· 2247 2109 if (evsel == NULL) 2248 2110 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, 2249 2111 "syscalls:sys_exit"); 2250 - if (evsel == NULL) { 2251 - pr_err("Data file does not have raw_syscalls:sys_exit event\n"); 2112 + if (evsel && 2113 + (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 || 2114 + perf_evsel__init_sc_tp_uint_field(evsel, ret))) { 2115 + pr_err("Error during initialize raw_syscalls:sys_exit event\n"); 2252 2116 goto out; 2253 2117 } 2254 2118 2255 - if (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 || 2256 - perf_evsel__init_sc_tp_uint_field(evsel, ret)) { 2257 - pr_err("Error during initialize raw_syscalls:sys_exit event\n"); 2258 - goto out; 2119 + evlist__for_each(session->evlist, evsel) { 2120 + if (evsel->attr.type == PERF_TYPE_SOFTWARE && 2121 + (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ || 2122 + evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN || 2123 + evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS)) 2124 + evsel->handler = trace__pgfault; 2259 2125 } 2260 2126 2261 2127 err = parse_target_str(trace); ··· 2359 2217 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid); 2360 2218 printed += fprintf(fp, "%lu events, ", ttrace->nr_events); 2361 2219 printed += fprintf(fp, "%.1f%%", ratio); 2220 + if (ttrace->pfmaj) 2221 + printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj); 2222 + if (ttrace->pfmin) 2223 + printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin); 2362 2224 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms); 2363 2225 printed += thread__dump_stats(ttrace, trace, fp); 2364 2226 ··· 2410 2264 return trace->output == NULL ? -errno : 0; 2411 2265 } 2412 2266 2267 + static int parse_pagefaults(const struct option *opt, const char *str, 2268 + int unset __maybe_unused) 2269 + { 2270 + int *trace_pgfaults = opt->value; 2271 + 2272 + if (strcmp(str, "all") == 0) 2273 + *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN; 2274 + else if (strcmp(str, "maj") == 0) 2275 + *trace_pgfaults |= TRACE_PFMAJ; 2276 + else if (strcmp(str, "min") == 0) 2277 + *trace_pgfaults |= TRACE_PFMIN; 2278 + else 2279 + return -1; 2280 + 2281 + return 0; 2282 + } 2283 + 2413 2284 int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) 2414 2285 { 2415 2286 const char * const trace_usage[] = { ··· 2456 2293 }, 2457 2294 .output = stdout, 2458 2295 .show_comm = true, 2296 + .trace_syscalls = true, 2459 2297 }; 2460 2298 const char *output_name = NULL; 2461 2299 const char *ev_qualifier_str = NULL; ··· 2494 2330 "Show only syscall summary with statistics"), 2495 2331 OPT_BOOLEAN('S', "with-summary", &trace.summary, 2496 2332 "Show all syscalls and summary with statistics"), 2333 + OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min", 2334 + "Trace pagefaults", parse_pagefaults, "maj"), 2335 + OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"), 2497 2336 OPT_END() 2498 2337 }; 2499 2338 int err; 2500 2339 char bf[BUFSIZ]; 2501 2340 2502 - if ((argc > 1) && (strcmp(argv[1], "record") == 0)) 2503 - return trace__record(argc-2, &argv[2]); 2341 + argc = parse_options(argc, argv, trace_options, trace_usage, 2342 + PARSE_OPT_STOP_AT_NON_OPTION); 2504 2343 2505 - argc = parse_options(argc, argv, trace_options, trace_usage, 0); 2344 + if (trace.trace_pgfaults) { 2345 + trace.opts.sample_address = true; 2346 + trace.opts.sample_time = true; 2347 + } 2348 + 2349 + if ((argc >= 1) && (strcmp(argv[0], "record") == 0)) 2350 + return trace__record(&trace, argc-1, &argv[1]); 2506 2351 2507 2352 /* summary_only implies summary option, but don't overwrite summary if set */ 2508 2353 if (trace.summary_only) 2509 2354 trace.summary = trace.summary_only; 2355 + 2356 + if (!trace.trace_syscalls && !trace.trace_pgfaults) { 2357 + pr_err("Please specify something to trace.\n"); 2358 + return -1; 2359 + } 2510 2360 2511 2361 if (output_name != NULL) { 2512 2362 err = trace__open_output(&trace, output_name);
+14
tools/perf/config/Makefile
··· 48 48 NO_LIBDW_DWARF_UNWIND := 1 49 49 endif 50 50 51 + ifeq ($(ARCH),powerpc) 52 + CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX 53 + endif 54 + 51 55 ifeq ($(LIBUNWIND_LIBS),) 52 56 NO_LIBUNWIND := 1 53 57 else ··· 164 160 backtrace \ 165 161 dwarf \ 166 162 fortify-source \ 163 + sync-compare-and-swap \ 167 164 glibc \ 168 165 gtk2 \ 169 166 gtk2-infobar \ ··· 200 195 VF_FEATURE_TESTS = \ 201 196 backtrace \ 202 197 fortify-source \ 198 + sync-compare-and-swap \ 203 199 gtk2-infobar \ 204 200 libelf-getphdrnum \ 205 201 libelf-mmap \ ··· 273 267 CFLAGS += -I$(LIB_INCLUDE) 274 268 275 269 CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 270 + 271 + ifeq ($(feature-sync-compare-and-swap), 1) 272 + CFLAGS += -DHAVE_SYNC_COMPARE_AND_SWAP_SUPPORT 273 + endif 276 274 277 275 ifndef NO_BIONIC 278 276 $(call feature_check,bionic) ··· 598 588 CFLAGS += -DHAVE_LIBNUMA_SUPPORT 599 589 EXTLIBS += -lnuma 600 590 endif 591 + endif 592 + 593 + ifdef HAVE_KVM_STAT_SUPPORT 594 + CFLAGS += -DHAVE_KVM_STAT_SUPPORT 601 595 endif 602 596 603 597 # Among the variables below, these:
+4
tools/perf/config/feature-checks/Makefile
··· 5 5 test-bionic.bin \ 6 6 test-dwarf.bin \ 7 7 test-fortify-source.bin \ 8 + test-sync-compare-and-swap.bin \ 8 9 test-glibc.bin \ 9 10 test-gtk2.bin \ 10 11 test-gtk2-infobar.bin \ ··· 141 140 142 141 test-libdw-dwarf-unwind.bin: 143 142 $(BUILD) 143 + 144 + test-sync-compare-and-swap.bin: 145 + $(BUILD) -Werror 144 146 145 147 -include *.d 146 148
+5
tools/perf/config/feature-checks/test-all.c
··· 89 89 # include "test-libdw-dwarf-unwind.c" 90 90 #undef main 91 91 92 + #define main main_test_sync_compare_and_swap 93 + # include "test-sync-compare-and-swap.c" 94 + #undef main 95 + 92 96 int main(int argc, char *argv[]) 93 97 { 94 98 main_test_libpython(); ··· 115 111 main_test_timerfd(); 116 112 main_test_stackprotector_all(); 117 113 main_test_libdw_dwarf_unwind(); 114 + main_test_sync_compare_and_swap(argc, argv); 118 115 119 116 return 0; 120 117 }
+14
tools/perf/config/feature-checks/test-sync-compare-and-swap.c
··· 1 + #include <stdint.h> 2 + 3 + volatile uint64_t x; 4 + 5 + int main(int argc, char *argv[]) 6 + { 7 + uint64_t old, new = argc; 8 + 9 + argv = argv; 10 + do { 11 + old = __sync_val_compare_and_swap(&x, 0, 0); 12 + } while (!__sync_bool_compare_and_swap(&x, old, new)); 13 + return old == new; 14 + }
+1
tools/perf/perf-sys.h
··· 54 54 #define mb() asm volatile("bcr 15,0" ::: "memory") 55 55 #define wmb() asm volatile("bcr 15,0" ::: "memory") 56 56 #define rmb() asm volatile("bcr 15,0" ::: "memory") 57 + #define CPUINFO_PROC "vendor_id" 57 58 #endif 58 59 59 60 #ifdef __sh__
+12 -1
tools/perf/perf.c
··· 13 13 #include "util/quote.h" 14 14 #include "util/run-command.h" 15 15 #include "util/parse-events.h" 16 + #include "util/debug.h" 16 17 #include <api/fs/debugfs.h> 17 18 #include <pthread.h> 18 19 19 20 const char perf_usage_string[] = 20 - "perf [--version] [--help] COMMAND [ARGS]"; 21 + "perf [--version] [--help] [OPTIONS] COMMAND [ARGS]"; 21 22 22 23 const char perf_more_info_string[] = 23 24 "See 'perf help COMMAND' for more information on a specific command."; ··· 213 212 printf("%s ", p->cmd); 214 213 } 215 214 exit(0); 215 + } else if (!strcmp(cmd, "--debug")) { 216 + if (*argc < 2) { 217 + fprintf(stderr, "No variable specified for --debug.\n"); 218 + usage(perf_usage_string); 219 + } 220 + if (perf_debug_option((*argv)[1])) 221 + usage(perf_usage_string); 222 + 223 + (*argv)++; 224 + (*argc)--; 216 225 } else { 217 226 fprintf(stderr, "Unknown option: %s\n", cmd); 218 227 usage(perf_usage_string);
+2 -1
tools/perf/scripts/perl/bin/failed-syscalls-record
··· 1 1 #!/bin/bash 2 - perf record -e raw_syscalls:sys_exit $@ 2 + (perf record -e raw_syscalls:sys_exit $@ || \ 3 + perf record -e syscalls:sys_exit $@) 2> /dev/null
+5
tools/perf/scripts/perl/failed-syscalls.pl
··· 26 26 } 27 27 } 28 28 29 + sub syscalls::sys_exit 30 + { 31 + raw_syscalls::sys_exit(@_) 32 + } 33 + 29 34 sub trace_end 30 35 { 31 36 printf("\nfailed syscalls by comm:\n\n");
+2 -1
tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
··· 107 107 108 108 class EventHeaders: 109 109 def __init__(self, common_cpu, common_secs, common_nsecs, 110 - common_pid, common_comm): 110 + common_pid, common_comm, common_callchain): 111 111 self.cpu = common_cpu 112 112 self.secs = common_secs 113 113 self.nsecs = common_nsecs 114 114 self.pid = common_pid 115 115 self.comm = common_comm 116 + self.callchain = common_callchain 116 117 117 118 def ts(self): 118 119 return (self.secs * (10 ** 9)) + self.nsecs
+2 -1
tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
··· 1 1 #!/bin/bash 2 - perf record -e raw_syscalls:sys_exit $@ 2 + (perf record -e raw_syscalls:sys_exit $@ || \ 3 + perf record -e syscalls:sys_exit $@) 2> /dev/null
+2 -1
tools/perf/scripts/python/bin/sctop-record
··· 1 1 #!/bin/bash 2 - perf record -e raw_syscalls:sys_enter $@ 2 + (perf record -e raw_syscalls:sys_enter $@ || \ 3 + perf record -e syscalls:sys_enter $@) 2> /dev/null
+2 -1
tools/perf/scripts/python/bin/syscall-counts-by-pid-record
··· 1 1 #!/bin/bash 2 - perf record -e raw_syscalls:sys_enter $@ 2 + (perf record -e raw_syscalls:sys_enter $@ || \ 3 + perf record -e syscalls:sys_enter $@) 2> /dev/null
+2 -1
tools/perf/scripts/python/bin/syscall-counts-record
··· 1 1 #!/bin/bash 2 - perf record -e raw_syscalls:sys_enter $@ 2 + (perf record -e raw_syscalls:sys_enter $@ || \ 3 + perf record -e syscalls:sys_enter $@) 2> /dev/null
+2 -2
tools/perf/scripts/python/check-perf-trace.py
··· 27 27 28 28 def irq__softirq_entry(event_name, context, common_cpu, 29 29 common_secs, common_nsecs, common_pid, common_comm, 30 - vec): 30 + common_callchain, vec): 31 31 print_header(event_name, common_cpu, common_secs, common_nsecs, 32 32 common_pid, common_comm) 33 33 ··· 38 38 39 39 def kmem__kmalloc(event_name, context, common_cpu, 40 40 common_secs, common_nsecs, common_pid, common_comm, 41 - call_site, ptr, bytes_req, bytes_alloc, 41 + common_callchain, call_site, ptr, bytes_req, bytes_alloc, 42 42 gfp_flags): 43 43 print_header(event_name, common_cpu, common_secs, common_nsecs, 44 44 common_pid, common_comm)
+6 -1
tools/perf/scripts/python/failed-syscalls-by-pid.py
··· 39 39 40 40 def raw_syscalls__sys_exit(event_name, context, common_cpu, 41 41 common_secs, common_nsecs, common_pid, common_comm, 42 - id, ret): 42 + common_callchain, id, ret): 43 43 if (for_comm and common_comm != for_comm) or \ 44 44 (for_pid and common_pid != for_pid ): 45 45 return ··· 49 49 syscalls[common_comm][common_pid][id][ret] += 1 50 50 except TypeError: 51 51 syscalls[common_comm][common_pid][id][ret] = 1 52 + 53 + def syscalls__sys_exit(event_name, context, common_cpu, 54 + common_secs, common_nsecs, common_pid, common_comm, 55 + id, ret): 56 + raw_syscalls__sys_exit(**locals()) 52 57 53 58 def print_error_totals(): 54 59 if for_comm is not None:
+2 -2
tools/perf/scripts/python/futex-contention.py
··· 21 21 lock_waits = {} # long-lived stats on (tid,lock) blockage elapsed time 22 22 process_names = {} # long-lived pid-to-execname mapping 23 23 24 - def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm, 24 + def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm, callchain, 25 25 nr, uaddr, op, val, utime, uaddr2, val3): 26 26 cmd = op & FUTEX_CMD_MASK 27 27 if cmd != FUTEX_WAIT: ··· 31 31 thread_thislock[tid] = uaddr 32 32 thread_blocktime[tid] = nsecs(s, ns) 33 33 34 - def syscalls__sys_exit_futex(event, ctxt, cpu, s, ns, tid, comm, 34 + def syscalls__sys_exit_futex(event, ctxt, cpu, s, ns, tid, comm, callchain, 35 35 nr, ret): 36 36 if thread_blocktime.has_key(tid): 37 37 elapsed = nsecs(s, ns) - thread_blocktime[tid]
+1 -1
tools/perf/scripts/python/net_dropmonitor.py
··· 66 66 print_drop_table() 67 67 68 68 # called from perf, when it finds a correspoinding event 69 - def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, 69 + def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, callchain, 70 70 skbaddr, location, protocol): 71 71 slocation = str(location) 72 72 try:
+13 -13
tools/perf/scripts/python/netdev-times.py
··· 224 224 (len(rx_skb_list), of_count_rx_skb_list) 225 225 226 226 # called from perf, when it finds a correspoinding event 227 - def irq__softirq_entry(name, context, cpu, sec, nsec, pid, comm, vec): 227 + def irq__softirq_entry(name, context, cpu, sec, nsec, pid, comm, callchain, vec): 228 228 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": 229 229 return 230 230 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) 231 231 all_event_list.append(event_info) 232 232 233 - def irq__softirq_exit(name, context, cpu, sec, nsec, pid, comm, vec): 233 + def irq__softirq_exit(name, context, cpu, sec, nsec, pid, comm, callchain, vec): 234 234 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": 235 235 return 236 236 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) 237 237 all_event_list.append(event_info) 238 238 239 - def irq__softirq_raise(name, context, cpu, sec, nsec, pid, comm, vec): 239 + def irq__softirq_raise(name, context, cpu, sec, nsec, pid, comm, callchain, vec): 240 240 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": 241 241 return 242 242 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) 243 243 all_event_list.append(event_info) 244 244 245 245 def irq__irq_handler_entry(name, context, cpu, sec, nsec, pid, comm, 246 - irq, irq_name): 246 + callchain, irq, irq_name): 247 247 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 248 248 irq, irq_name) 249 249 all_event_list.append(event_info) 250 250 251 - def irq__irq_handler_exit(name, context, cpu, sec, nsec, pid, comm, irq, ret): 251 + def irq__irq_handler_exit(name, context, cpu, sec, nsec, pid, comm, callchain, irq, ret): 252 252 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, irq, ret) 253 253 all_event_list.append(event_info) 254 254 255 - def napi__napi_poll(name, context, cpu, sec, nsec, pid, comm, napi, dev_name): 255 + def napi__napi_poll(name, context, cpu, sec, nsec, pid, comm, callchain, napi, dev_name): 256 256 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 257 257 napi, dev_name) 258 258 all_event_list.append(event_info) 259 259 260 - def net__netif_receive_skb(name, context, cpu, sec, nsec, pid, comm, skbaddr, 260 + def net__netif_receive_skb(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr, 261 261 skblen, dev_name): 262 262 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 263 263 skbaddr, skblen, dev_name) 264 264 all_event_list.append(event_info) 265 265 266 - def net__netif_rx(name, context, cpu, sec, nsec, pid, comm, skbaddr, 266 + def net__netif_rx(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr, 267 267 skblen, dev_name): 268 268 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 269 269 skbaddr, skblen, dev_name) 270 270 all_event_list.append(event_info) 271 271 272 - def net__net_dev_queue(name, context, cpu, sec, nsec, pid, comm, 272 + def net__net_dev_queue(name, context, cpu, sec, nsec, pid, comm, callchain, 273 273 skbaddr, skblen, dev_name): 274 274 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 275 275 skbaddr, skblen, dev_name) 276 276 all_event_list.append(event_info) 277 277 278 - def net__net_dev_xmit(name, context, cpu, sec, nsec, pid, comm, 278 + def net__net_dev_xmit(name, context, cpu, sec, nsec, pid, comm, callchain, 279 279 skbaddr, skblen, rc, dev_name): 280 280 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 281 281 skbaddr, skblen, rc ,dev_name) 282 282 all_event_list.append(event_info) 283 283 284 - def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, 284 + def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, callchain, 285 285 skbaddr, protocol, location): 286 286 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 287 287 skbaddr, protocol, location) 288 288 all_event_list.append(event_info) 289 289 290 - def skb__consume_skb(name, context, cpu, sec, nsec, pid, comm, skbaddr): 290 + def skb__consume_skb(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr): 291 291 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 292 292 skbaddr) 293 293 all_event_list.append(event_info) 294 294 295 - def skb__skb_copy_datagram_iovec(name, context, cpu, sec, nsec, pid, comm, 295 + def skb__skb_copy_datagram_iovec(name, context, cpu, sec, nsec, pid, comm, callchain, 296 296 skbaddr, skblen): 297 297 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 298 298 skbaddr, skblen)
+20 -21
tools/perf/scripts/python/sched-migration.py
··· 369 369 370 370 def sched__sched_stat_runtime(event_name, context, common_cpu, 371 371 common_secs, common_nsecs, common_pid, common_comm, 372 - comm, pid, runtime, vruntime): 372 + common_callchain, comm, pid, runtime, vruntime): 373 373 pass 374 374 375 375 def sched__sched_stat_iowait(event_name, context, common_cpu, 376 376 common_secs, common_nsecs, common_pid, common_comm, 377 - comm, pid, delay): 377 + common_callchain, comm, pid, delay): 378 378 pass 379 379 380 380 def sched__sched_stat_sleep(event_name, context, common_cpu, 381 381 common_secs, common_nsecs, common_pid, common_comm, 382 - comm, pid, delay): 382 + common_callchain, comm, pid, delay): 383 383 pass 384 384 385 385 def sched__sched_stat_wait(event_name, context, common_cpu, 386 386 common_secs, common_nsecs, common_pid, common_comm, 387 - comm, pid, delay): 387 + common_callchain, comm, pid, delay): 388 388 pass 389 389 390 390 def sched__sched_process_fork(event_name, context, common_cpu, 391 391 common_secs, common_nsecs, common_pid, common_comm, 392 - parent_comm, parent_pid, child_comm, child_pid): 392 + common_callchain, parent_comm, parent_pid, child_comm, child_pid): 393 393 pass 394 394 395 395 def sched__sched_process_wait(event_name, context, common_cpu, 396 396 common_secs, common_nsecs, common_pid, common_comm, 397 - comm, pid, prio): 397 + common_callchain, comm, pid, prio): 398 398 pass 399 399 400 400 def sched__sched_process_exit(event_name, context, common_cpu, 401 401 common_secs, common_nsecs, common_pid, common_comm, 402 - comm, pid, prio): 402 + common_callchain, comm, pid, prio): 403 403 pass 404 404 405 405 def sched__sched_process_free(event_name, context, common_cpu, 406 406 common_secs, common_nsecs, common_pid, common_comm, 407 - comm, pid, prio): 407 + common_callchain, comm, pid, prio): 408 408 pass 409 409 410 410 def sched__sched_migrate_task(event_name, context, common_cpu, 411 411 common_secs, common_nsecs, common_pid, common_comm, 412 - comm, pid, prio, orig_cpu, 412 + common_callchain, comm, pid, prio, orig_cpu, 413 413 dest_cpu): 414 414 headers = EventHeaders(common_cpu, common_secs, common_nsecs, 415 - common_pid, common_comm) 415 + common_pid, common_comm, common_callchain) 416 416 parser.migrate(headers, pid, prio, orig_cpu, dest_cpu) 417 417 418 418 def sched__sched_switch(event_name, context, common_cpu, 419 - common_secs, common_nsecs, common_pid, common_comm, 419 + common_secs, common_nsecs, common_pid, common_comm, common_callchain, 420 420 prev_comm, prev_pid, prev_prio, prev_state, 421 421 next_comm, next_pid, next_prio): 422 422 423 423 headers = EventHeaders(common_cpu, common_secs, common_nsecs, 424 - common_pid, common_comm) 424 + common_pid, common_comm, common_callchain) 425 425 parser.sched_switch(headers, prev_comm, prev_pid, prev_prio, prev_state, 426 426 next_comm, next_pid, next_prio) 427 427 428 428 def sched__sched_wakeup_new(event_name, context, common_cpu, 429 429 common_secs, common_nsecs, common_pid, common_comm, 430 - comm, pid, prio, success, 430 + common_callchain, comm, pid, prio, success, 431 431 target_cpu): 432 432 headers = EventHeaders(common_cpu, common_secs, common_nsecs, 433 - common_pid, common_comm) 433 + common_pid, common_comm, common_callchain) 434 434 parser.wake_up(headers, comm, pid, success, target_cpu, 1) 435 435 436 436 def sched__sched_wakeup(event_name, context, common_cpu, 437 437 common_secs, common_nsecs, common_pid, common_comm, 438 - comm, pid, prio, success, 438 + common_callchain, comm, pid, prio, success, 439 439 target_cpu): 440 440 headers = EventHeaders(common_cpu, common_secs, common_nsecs, 441 - common_pid, common_comm) 441 + common_pid, common_comm, common_callchain) 442 442 parser.wake_up(headers, comm, pid, success, target_cpu, 0) 443 443 444 444 def sched__sched_wait_task(event_name, context, common_cpu, 445 445 common_secs, common_nsecs, common_pid, common_comm, 446 - comm, pid, prio): 446 + common_callchain, comm, pid, prio): 447 447 pass 448 448 449 449 def sched__sched_kthread_stop_ret(event_name, context, common_cpu, 450 450 common_secs, common_nsecs, common_pid, common_comm, 451 - ret): 451 + common_callchain, ret): 452 452 pass 453 453 454 454 def sched__sched_kthread_stop(event_name, context, common_cpu, 455 455 common_secs, common_nsecs, common_pid, common_comm, 456 - comm, pid): 456 + common_callchain, comm, pid): 457 457 pass 458 458 459 - def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs, 460 - common_pid, common_comm): 459 + def trace_unhandled(event_name, context, event_fields_dict): 461 460 pass
+6 -1
tools/perf/scripts/python/sctop.py
··· 44 44 45 45 def raw_syscalls__sys_enter(event_name, context, common_cpu, 46 46 common_secs, common_nsecs, common_pid, common_comm, 47 - id, args): 47 + common_callchain, id, args): 48 48 if for_comm is not None: 49 49 if common_comm != for_comm: 50 50 return ··· 52 52 syscalls[id] += 1 53 53 except TypeError: 54 54 syscalls[id] = 1 55 + 56 + def syscalls__sys_enter(event_name, context, common_cpu, 57 + common_secs, common_nsecs, common_pid, common_comm, 58 + id, args): 59 + raw_syscalls__sys_enter(**locals()) 55 60 56 61 def print_syscall_totals(interval): 57 62 while 1:
+6 -1
tools/perf/scripts/python/syscall-counts-by-pid.py
··· 38 38 39 39 def raw_syscalls__sys_enter(event_name, context, common_cpu, 40 40 common_secs, common_nsecs, common_pid, common_comm, 41 - id, args): 41 + common_callchain, id, args): 42 42 43 43 if (for_comm and common_comm != for_comm) or \ 44 44 (for_pid and common_pid != for_pid ): ··· 47 47 syscalls[common_comm][common_pid][id] += 1 48 48 except TypeError: 49 49 syscalls[common_comm][common_pid][id] = 1 50 + 51 + def syscalls__sys_enter(event_name, context, common_cpu, 52 + common_secs, common_nsecs, common_pid, common_comm, 53 + id, args): 54 + raw_syscalls__sys_enter(**locals()) 50 55 51 56 def print_syscall_totals(): 52 57 if for_comm is not None:
+6 -1
tools/perf/scripts/python/syscall-counts.py
··· 35 35 36 36 def raw_syscalls__sys_enter(event_name, context, common_cpu, 37 37 common_secs, common_nsecs, common_pid, common_comm, 38 - id, args): 38 + common_callchain, id, args): 39 39 if for_comm is not None: 40 40 if common_comm != for_comm: 41 41 return ··· 43 43 syscalls[id] += 1 44 44 except TypeError: 45 45 syscalls[id] = 1 46 + 47 + def syscalls__sys_enter(event_name, context, common_cpu, 48 + common_secs, common_nsecs, common_pid, common_comm, 49 + id, args): 50 + raw_syscalls__sys_enter(**locals()) 46 51 47 52 def print_syscall_totals(): 48 53 if for_comm is not None:
+2 -1
tools/perf/tests/attr/base-record
··· 1 1 [event] 2 2 fd=1 3 3 group_fd=-1 4 - flags=0 4 + # 0 or PERF_FLAG_FD_CLOEXEC flag 5 + flags=0|8 5 6 cpu=* 6 7 type=0|1 7 8 size=96
+2 -1
tools/perf/tests/attr/base-stat
··· 1 1 [event] 2 2 fd=1 3 3 group_fd=-1 4 - flags=0 4 + # 0 or PERF_FLAG_FD_CLOEXEC flag 5 + flags=0|8 5 6 cpu=* 6 7 type=0 7 8 size=96
+3 -1
tools/perf/tests/bp_signal.c
··· 25 25 #include "tests.h" 26 26 #include "debug.h" 27 27 #include "perf.h" 28 + #include "cloexec.h" 28 29 29 30 static int fd1; 30 31 static int fd2; ··· 79 78 pe.exclude_kernel = 1; 80 79 pe.exclude_hv = 1; 81 80 82 - fd = sys_perf_event_open(&pe, 0, -1, -1, 0); 81 + fd = sys_perf_event_open(&pe, 0, -1, -1, 82 + perf_event_open_cloexec_flag()); 83 83 if (fd < 0) { 84 84 pr_debug("failed opening event %llx\n", pe.config); 85 85 return TEST_FAIL;
+3 -1
tools/perf/tests/bp_signal_overflow.c
··· 24 24 #include "tests.h" 25 25 #include "debug.h" 26 26 #include "perf.h" 27 + #include "cloexec.h" 27 28 28 29 static int overflows; 29 30 ··· 92 91 pe.exclude_kernel = 1; 93 92 pe.exclude_hv = 1; 94 93 95 - fd = sys_perf_event_open(&pe, 0, -1, -1, 0); 94 + fd = sys_perf_event_open(&pe, 0, -1, -1, 95 + perf_event_open_cloexec_flag()); 96 96 if (fd < 0) { 97 97 pr_debug("failed opening event %llx\n", pe.config); 98 98 return TEST_FAIL;
+1
tools/perf/tests/dso-data.c
··· 10 10 #include "machine.h" 11 11 #include "symbol.h" 12 12 #include "tests.h" 13 + #include "debug.h" 13 14 14 15 static char *test_file(int size) 15 16 {
+1
tools/perf/tests/evsel-roundtrip-name.c
··· 2 2 #include "evsel.h" 3 3 #include "parse-events.h" 4 4 #include "tests.h" 5 + #include "debug.h" 5 6 6 7 static int perf_evsel__roundtrip_cache_name_test(void) 7 8 {
+1
tools/perf/tests/evsel-tp-sched.c
··· 1 1 #include <traceevent/event-parse.h> 2 2 #include "evsel.h" 3 3 #include "tests.h" 4 + #include "debug.h" 4 5 5 6 static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name, 6 7 int size, bool should_be_signed)
+1
tools/perf/tests/open-syscall-tp-fields.c
··· 3 3 #include "evsel.h" 4 4 #include "thread_map.h" 5 5 #include "tests.h" 6 + #include "debug.h" 6 7 7 8 int test__syscall_open_tp_fields(void) 8 9 {
+1
tools/perf/tests/parse-events.c
··· 5 5 #include <api/fs/fs.h> 6 6 #include <api/fs/debugfs.h> 7 7 #include "tests.h" 8 + #include "debug.h" 8 9 #include <linux/hw_breakpoint.h> 9 10 10 11 #define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \
+1
tools/perf/tests/parse-no-sample-id-all.c
··· 7 7 #include "evlist.h" 8 8 #include "header.h" 9 9 #include "util.h" 10 + #include "debug.h" 10 11 11 12 static int process_event(struct perf_evlist **pevlist, union perf_event *event) 12 13 {
+1 -11
tools/perf/tests/perf-time-to-tsc.c
··· 8 8 #include "evsel.h" 9 9 #include "thread_map.h" 10 10 #include "cpumap.h" 11 + #include "tsc.h" 11 12 #include "tests.h" 12 - 13 - #include "../arch/x86/util/tsc.h" 14 13 15 14 #define CHECK__(x) { \ 16 15 while ((x) < 0) { \ ··· 23 24 pr_debug(#x " failed!\n"); \ 24 25 goto out_err; \ 25 26 } \ 26 - } 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 27 } 36 28 37 29 /**
+3 -1
tools/perf/tests/rdpmc.c
··· 6 6 #include "perf.h" 7 7 #include "debug.h" 8 8 #include "tests.h" 9 + #include "cloexec.h" 9 10 10 11 #if defined(__x86_64__) || defined(__i386__) 11 12 ··· 105 104 sa.sa_sigaction = segfault_handler; 106 105 sigaction(SIGSEGV, &sa, NULL); 107 106 108 - fd = sys_perf_event_open(&attr, 0, -1, -1, 0); 107 + fd = sys_perf_event_open(&attr, 0, -1, -1, 108 + perf_event_open_cloexec_flag()); 109 109 if (fd < 0) { 110 110 pr_err("Error: sys_perf_event_open() syscall returned " 111 111 "with %d (%s)\n", fd, strerror(errno));
+1
tools/perf/tests/sample-parsing.c
··· 4 4 #include "util.h" 5 5 #include "event.h" 6 6 #include "evsel.h" 7 + #include "debug.h" 7 8 8 9 #include "tests.h" 9 10
+1
tools/perf/tests/thread-mg-share.c
··· 2 2 #include "machine.h" 3 3 #include "thread.h" 4 4 #include "map.h" 5 + #include "debug.h" 5 6 6 7 int test__thread_mg_share(void) 7 8 {
+21 -18
tools/perf/ui/browser.c
··· 150 150 while (nd != NULL) { 151 151 ui_browser__gotorc(browser, row, 0); 152 152 browser->write(browser, nd, row); 153 - if (++row == browser->height) 153 + if (++row == browser->rows) 154 154 break; 155 155 nd = rb_next(nd); 156 156 } ··· 166 166 void ui_browser__refresh_dimensions(struct ui_browser *browser) 167 167 { 168 168 browser->width = SLtt_Screen_Cols - 1; 169 - browser->height = SLtt_Screen_Rows - 2; 169 + browser->height = browser->rows = SLtt_Screen_Rows - 2; 170 170 browser->y = 1; 171 171 browser->x = 0; 172 172 } ··· 250 250 int err; 251 251 va_list ap; 252 252 253 - ui_browser__refresh_dimensions(browser); 253 + if (browser->refresh_dimensions == NULL) 254 + browser->refresh_dimensions = ui_browser__refresh_dimensions; 255 + 256 + browser->refresh_dimensions(browser); 254 257 255 258 pthread_mutex_lock(&ui__lock); 256 259 __ui_browser__show_title(browser, title); ··· 282 279 { 283 280 int height = browser->height, h = 0, pct = 0, 284 281 col = browser->width, 285 - row = browser->y - 1; 282 + row = 0; 286 283 287 284 if (browser->nr_entries > 1) { 288 285 pct = ((browser->index * (browser->height - 1)) / ··· 370 367 371 368 if (key == K_RESIZE) { 372 369 ui__refresh_dimensions(false); 373 - ui_browser__refresh_dimensions(browser); 370 + browser->refresh_dimensions(browser); 374 371 __ui_browser__show_title(browser, browser->title); 375 372 ui_helpline__puts(browser->helpline); 376 373 continue; ··· 392 389 if (browser->index == browser->nr_entries - 1) 393 390 break; 394 391 ++browser->index; 395 - if (browser->index == browser->top_idx + browser->height) { 392 + if (browser->index == browser->top_idx + browser->rows) { 396 393 ++browser->top_idx; 397 394 browser->seek(browser, +1, SEEK_CUR); 398 395 } ··· 408 405 break; 409 406 case K_PGDN: 410 407 case ' ': 411 - if (browser->top_idx + browser->height > browser->nr_entries - 1) 408 + if (browser->top_idx + browser->rows > browser->nr_entries - 1) 412 409 break; 413 410 414 - offset = browser->height; 411 + offset = browser->rows; 415 412 if (browser->index + offset > browser->nr_entries - 1) 416 413 offset = browser->nr_entries - 1 - browser->index; 417 414 browser->index += offset; ··· 422 419 if (browser->top_idx == 0) 423 420 break; 424 421 425 - if (browser->top_idx < browser->height) 422 + if (browser->top_idx < browser->rows) 426 423 offset = browser->top_idx; 427 424 else 428 - offset = browser->height; 425 + offset = browser->rows; 429 426 430 427 browser->index -= offset; 431 428 browser->top_idx -= offset; ··· 435 432 ui_browser__reset_index(browser); 436 433 break; 437 434 case K_END: 438 - offset = browser->height - 1; 435 + offset = browser->rows - 1; 439 436 if (offset >= browser->nr_entries) 440 437 offset = browser->nr_entries - 1; 441 438 ··· 465 462 if (!browser->filter || !browser->filter(browser, pos)) { 466 463 ui_browser__gotorc(browser, row, 0); 467 464 browser->write(browser, pos, row); 468 - if (++row == browser->height) 465 + if (++row == browser->rows) 469 466 break; 470 467 } 471 468 } ··· 590 587 if (!browser->filter || !browser->filter(browser, *pos)) { 591 588 ui_browser__gotorc(browser, row, 0); 592 589 browser->write(browser, pos, row); 593 - if (++row == browser->height) 590 + if (++row == browser->rows) 594 591 break; 595 592 } 596 593 ··· 626 623 627 624 SLsmg_set_char_set(1); 628 625 629 - if (start < browser->top_idx + browser->height) { 626 + if (start < browser->top_idx + browser->rows) { 630 627 row = start - browser->top_idx; 631 628 ui_browser__gotorc(browser, row, column); 632 629 SLsmg_write_char(SLSMG_LLCORN_CHAR); ··· 636 633 if (row-- == 0) 637 634 goto out; 638 635 } else 639 - row = browser->height - 1; 636 + row = browser->rows - 1; 640 637 641 638 if (end > browser->top_idx) 642 639 end_row = end - browser->top_idx; ··· 678 675 } else 679 676 row = 0; 680 677 681 - if (end >= browser->top_idx + browser->height) 682 - end_row = browser->height - 1; 678 + if (end >= browser->top_idx + browser->rows) 679 + end_row = browser->rows - 1; 683 680 else 684 681 end_row = end - browser->top_idx; 685 682 ··· 687 684 SLsmg_draw_vline(end_row - row + 1); 688 685 689 686 ui_browser__gotorc(browser, end_row, column); 690 - if (end < browser->top_idx + browser->height) { 687 + if (end < browser->top_idx + browser->rows) { 691 688 SLsmg_write_char(SLSMG_LLCORN_CHAR); 692 689 ui_browser__gotorc(browser, end_row, column + 1); 693 690 SLsmg_write_char(SLSMG_HLINE_CHAR);
+2 -1
tools/perf/ui/browser.h
··· 14 14 struct ui_browser { 15 15 u64 index, top_idx; 16 16 void *top, *entries; 17 - u16 y, x, width, height; 17 + u16 y, x, width, height, rows; 18 18 int current_color; 19 19 void *priv; 20 20 const char *title; 21 21 char *helpline; 22 + void (*refresh_dimensions)(struct ui_browser *browser); 22 23 unsigned int (*refresh)(struct ui_browser *browser); 23 24 void (*write)(struct ui_browser *browser, void *entry, int row); 24 25 void (*seek)(struct ui_browser *browser, off_t offset, int whence);
+122 -31
tools/perf/ui/browsers/hists.c
··· 26 26 struct map_symbol *selection; 27 27 int print_seq; 28 28 bool show_dso; 29 + bool show_headers; 29 30 float min_pcnt; 30 31 u64 nr_non_filtered_entries; 31 32 u64 nr_callchain_rows; ··· 34 33 35 34 extern void hist_browser__init_hpp(void); 36 35 37 - static int hists__browser_title(struct hists *hists, char *bf, size_t size, 38 - const char *ev_name); 36 + static int hists__browser_title(struct hists *hists, char *bf, size_t size); 39 37 static void hist_browser__update_nr_entries(struct hist_browser *hb); 40 38 41 39 static struct rb_node *hists__filter_entries(struct rb_node *nd, ··· 57 57 return nr_entries + hb->nr_callchain_rows; 58 58 } 59 59 60 - static void hist_browser__refresh_dimensions(struct hist_browser *browser) 60 + static void hist_browser__update_rows(struct hist_browser *hb) 61 61 { 62 + struct ui_browser *browser = &hb->b; 63 + u16 header_offset = hb->show_headers ? 1 : 0, index_row; 64 + 65 + browser->rows = browser->height - header_offset; 66 + /* 67 + * Verify if we were at the last line and that line isn't 68 + * visibe because we now show the header line(s). 69 + */ 70 + index_row = browser->index - browser->top_idx; 71 + if (index_row >= browser->rows) 72 + browser->index -= index_row - browser->rows + 1; 73 + } 74 + 75 + static void hist_browser__refresh_dimensions(struct ui_browser *browser) 76 + { 77 + struct hist_browser *hb = container_of(browser, struct hist_browser, b); 78 + 62 79 /* 3 == +/- toggle symbol before actual hist_entry rendering */ 63 - browser->b.width = 3 + (hists__sort_list_width(browser->hists) + 64 - sizeof("[k]")); 80 + browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]")); 81 + /* 82 + * FIXME: Just keeping existing behaviour, but this really should be 83 + * before updating browser->width, as it will invalidate the 84 + * calculation above. Fix this and the fallout in another 85 + * changeset. 86 + */ 87 + ui_browser__refresh_dimensions(browser); 88 + hist_browser__update_rows(hb); 89 + } 90 + 91 + static void hist_browser__gotorc(struct hist_browser *browser, int row, int column) 92 + { 93 + u16 header_offset = browser->show_headers ? 1 : 0; 94 + 95 + ui_browser__gotorc(&browser->b, row + header_offset, column); 65 96 } 66 97 67 98 static void hist_browser__reset(struct hist_browser *browser) ··· 105 74 106 75 hist_browser__update_nr_entries(browser); 107 76 browser->b.nr_entries = hist_browser__nr_entries(browser); 108 - hist_browser__refresh_dimensions(browser); 77 + hist_browser__refresh_dimensions(&browser->b); 109 78 ui_browser__reset_index(&browser->b); 110 79 } 111 80 ··· 377 346 "Or reduce the sampling frequency."); 378 347 } 379 348 380 - static int hist_browser__run(struct hist_browser *browser, const char *ev_name, 349 + static int hist_browser__run(struct hist_browser *browser, 381 350 struct hist_browser_timer *hbt) 382 351 { 383 352 int key; ··· 387 356 browser->b.entries = &browser->hists->entries; 388 357 browser->b.nr_entries = hist_browser__nr_entries(browser); 389 358 390 - hist_browser__refresh_dimensions(browser); 391 - hists__browser_title(browser->hists, title, sizeof(title), ev_name); 359 + hists__browser_title(browser->hists, title, sizeof(title)); 392 360 393 361 if (ui_browser__show(&browser->b, title, 394 362 "Press '?' for help on key bindings") < 0) ··· 414 384 ui_browser__warn_lost_events(&browser->b); 415 385 } 416 386 417 - hists__browser_title(browser->hists, title, sizeof(title), ev_name); 387 + hists__browser_title(browser->hists, title, sizeof(title)); 418 388 ui_browser__show_title(&browser->b, title); 419 389 continue; 420 390 } ··· 423 393 struct hist_entry *h = rb_entry(browser->b.top, 424 394 struct hist_entry, rb_node); 425 395 ui_helpline__pop(); 426 - ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", 396 + ui_helpline__fpush("%d: nr_ent=(%d,%d), rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", 427 397 seq++, browser->b.nr_entries, 428 398 browser->hists->nr_entries, 429 - browser->b.height, 399 + browser->b.rows, 430 400 browser->b.index, 431 401 browser->b.top_idx, 432 402 h->row_offset, h->nr_rows); ··· 439 409 case 'E': 440 410 /* Expand the whole world. */ 441 411 hist_browser__set_folding(browser, true); 412 + break; 413 + case 'H': 414 + browser->show_headers = !browser->show_headers; 415 + hist_browser__update_rows(browser); 442 416 break; 443 417 case K_ENTER: 444 418 if (hist_browser__toggle_fold(browser)) ··· 543 509 } 544 510 545 511 ui_browser__set_color(&browser->b, color); 546 - ui_browser__gotorc(&browser->b, row, 0); 512 + hist_browser__gotorc(browser, row, 0); 547 513 slsmg_write_nstring(" ", offset + extra_offset); 548 514 slsmg_printf("%c ", folded_sign); 549 515 slsmg_write_nstring(str, width); 550 516 free(alloc_str); 551 517 552 - if (++row == browser->b.height) 518 + if (++row == browser->b.rows) 553 519 goto out; 554 520 do_next: 555 521 if (folded_sign == '+') ··· 562 528 new_level, row, row_offset, 563 529 is_current_entry); 564 530 } 565 - if (row == browser->b.height) 531 + if (row == browser->b.rows) 566 532 goto out; 567 533 node = next; 568 534 } ··· 602 568 603 569 s = callchain_list__sym_name(chain, bf, sizeof(bf), 604 570 browser->show_dso); 605 - ui_browser__gotorc(&browser->b, row, 0); 571 + hist_browser__gotorc(browser, row, 0); 606 572 ui_browser__set_color(&browser->b, color); 607 573 slsmg_write_nstring(" ", offset); 608 574 slsmg_printf("%c ", folded_sign); 609 575 slsmg_write_nstring(s, width - 2); 610 576 611 - if (++row == browser->b.height) 577 + if (++row == browser->b.rows) 612 578 goto out; 613 579 } 614 580 ··· 637 603 row += hist_browser__show_callchain_node(browser, node, level, 638 604 row, row_offset, 639 605 is_current_entry); 640 - if (row == browser->b.height) 606 + if (row == browser->b.rows) 641 607 break; 642 608 } 643 609 ··· 767 733 .ptr = &arg, 768 734 }; 769 735 770 - ui_browser__gotorc(&browser->b, row, 0); 736 + hist_browser__gotorc(browser, row, 0); 771 737 772 738 perf_hpp__for_each_format(fmt) { 773 739 if (perf_hpp__should_skip(fmt)) ··· 811 777 } else 812 778 --row_offset; 813 779 814 - if (folded_sign == '-' && row != browser->b.height) { 780 + if (folded_sign == '-' && row != browser->b.rows) { 815 781 printed += hist_browser__show_callchain(browser, &entry->sorted_chain, 816 782 1, row, &row_offset, 817 783 &current_entry); ··· 820 786 } 821 787 822 788 return printed; 789 + } 790 + 791 + static int advance_hpp_check(struct perf_hpp *hpp, int inc) 792 + { 793 + advance_hpp(hpp, inc); 794 + return hpp->size <= 0; 795 + } 796 + 797 + static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists) 798 + { 799 + struct perf_hpp dummy_hpp = { 800 + .buf = buf, 801 + .size = size, 802 + }; 803 + struct perf_hpp_fmt *fmt; 804 + size_t ret = 0; 805 + 806 + if (symbol_conf.use_callchain) { 807 + ret = scnprintf(buf, size, " "); 808 + if (advance_hpp_check(&dummy_hpp, ret)) 809 + return ret; 810 + } 811 + 812 + perf_hpp__for_each_format(fmt) { 813 + if (perf_hpp__should_skip(fmt)) 814 + continue; 815 + 816 + /* We need to add the length of the columns header. */ 817 + perf_hpp__reset_width(fmt, hists); 818 + 819 + ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); 820 + if (advance_hpp_check(&dummy_hpp, ret)) 821 + break; 822 + 823 + ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " "); 824 + if (advance_hpp_check(&dummy_hpp, ret)) 825 + break; 826 + } 827 + 828 + return ret; 829 + } 830 + 831 + static void hist_browser__show_headers(struct hist_browser *browser) 832 + { 833 + char headers[1024]; 834 + 835 + hists__scnprintf_headers(headers, sizeof(headers), browser->hists); 836 + ui_browser__gotorc(&browser->b, 0, 0); 837 + ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); 838 + slsmg_write_nstring(headers, browser->b.width + 1); 823 839 } 824 840 825 841 static void ui_browser__hists_init_top(struct ui_browser *browser) ··· 885 801 static unsigned int hist_browser__refresh(struct ui_browser *browser) 886 802 { 887 803 unsigned row = 0; 804 + u16 header_offset = 0; 888 805 struct rb_node *nd; 889 806 struct hist_browser *hb = container_of(browser, struct hist_browser, b); 807 + 808 + if (hb->show_headers) { 809 + hist_browser__show_headers(hb); 810 + header_offset = 1; 811 + } 890 812 891 813 ui_browser__hists_init_top(browser); 892 814 ··· 908 818 continue; 909 819 910 820 row += hist_browser__show_entry(hb, h, row); 911 - if (row == browser->height) 821 + if (row == browser->rows) 912 822 break; 913 823 } 914 824 915 - return row; 825 + return row + header_offset; 916 826 } 917 827 918 828 static struct rb_node *hists__filter_entries(struct rb_node *nd, ··· 1281 1191 if (browser) { 1282 1192 browser->hists = hists; 1283 1193 browser->b.refresh = hist_browser__refresh; 1194 + browser->b.refresh_dimensions = hist_browser__refresh_dimensions; 1284 1195 browser->b.seek = ui_browser__hists_seek; 1285 1196 browser->b.use_navkeypressed = true; 1197 + browser->show_headers = symbol_conf.show_hist_headers; 1286 1198 } 1287 1199 1288 1200 return browser; ··· 1305 1213 return browser->he_selection->thread; 1306 1214 } 1307 1215 1308 - static int hists__browser_title(struct hists *hists, char *bf, size_t size, 1309 - const char *ev_name) 1216 + static int hists__browser_title(struct hists *hists, char *bf, size_t size) 1310 1217 { 1311 1218 char unit; 1312 1219 int printed; ··· 1314 1223 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 1315 1224 u64 nr_events = hists->stats.total_period; 1316 1225 struct perf_evsel *evsel = hists_to_evsel(hists); 1226 + const char *ev_name = perf_evsel__name(evsel); 1317 1227 char buf[512]; 1318 1228 size_t buflen = sizeof(buf); 1319 1229 ··· 1482 1390 } 1483 1391 1484 1392 static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 1485 - const char *helpline, const char *ev_name, 1393 + const char *helpline, 1486 1394 bool left_exits, 1487 1395 struct hist_browser_timer *hbt, 1488 1396 float min_pcnt, ··· 1514 1422 "d Zoom into current DSO\n" \ 1515 1423 "E Expand all callchains\n" \ 1516 1424 "F Toggle percentage of filtered entries\n" \ 1425 + "H Display column headers\n" \ 1517 1426 1518 1427 /* help messages are sorted by lexical order of the hotkey */ 1519 1428 const char report_help[] = HIST_BROWSER_HELP_COMMON ··· 1558 1465 1559 1466 nr_options = 0; 1560 1467 1561 - key = hist_browser__run(browser, ev_name, hbt); 1468 + key = hist_browser__run(browser, hbt); 1562 1469 1563 1470 if (browser->he_selection != NULL) { 1564 1471 thread = hist_browser__selected_thread(browser); ··· 1936 1843 { 1937 1844 struct perf_evlist *evlist = menu->b.priv; 1938 1845 struct perf_evsel *pos; 1939 - const char *ev_name, *title = "Available samples"; 1846 + const char *title = "Available samples"; 1940 1847 int delay_secs = hbt ? hbt->refresh : 0; 1941 1848 int key; 1942 1849 ··· 1969 1876 */ 1970 1877 if (hbt) 1971 1878 hbt->timer(hbt->arg); 1972 - ev_name = perf_evsel__name(pos); 1973 1879 key = perf_evsel__hists_browse(pos, nr_events, help, 1974 - ev_name, true, hbt, 1880 + true, hbt, 1975 1881 menu->min_pcnt, 1976 1882 menu->env); 1977 1883 ui_browser__show_title(&menu->b, title); ··· 2074 1982 single_entry: 2075 1983 if (nr_entries == 1) { 2076 1984 struct perf_evsel *first = perf_evlist__first(evlist); 2077 - const char *ev_name = perf_evsel__name(first); 2078 1985 2079 1986 return perf_evsel__hists_browse(first, nr_entries, help, 2080 - ev_name, false, hbt, min_pcnt, 1987 + false, hbt, min_pcnt, 2081 1988 env); 2082 1989 } 2083 1990
+1 -1
tools/perf/ui/stdio/hist.c
··· 479 479 480 480 if (h->ms.map == NULL && verbose > 1) { 481 481 __map_groups__fprintf_maps(h->thread->mg, 482 - MAP__FUNCTION, verbose, fp); 482 + MAP__FUNCTION, fp); 483 483 fprintf(fp, "%.10s end\n", graph_dotted_line); 484 484 } 485 485 }
+1 -1
tools/perf/util/callchain.c
··· 626 626 627 627 int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample) 628 628 { 629 - if (!symbol_conf.use_callchain) 629 + if (!symbol_conf.use_callchain || sample->callchain == NULL) 630 630 return 0; 631 631 return callchain_append(he->callchain, &callchain_cursor, sample->period); 632 632 }
+13
tools/perf/util/callchain.h
··· 176 176 dest->first = src->curr; 177 177 dest->nr -= src->pos; 178 178 } 179 + 180 + #ifdef HAVE_SKIP_CALLCHAIN_IDX 181 + extern int arch_skip_callchain_idx(struct machine *machine, 182 + struct thread *thread, struct ip_callchain *chain); 183 + #else 184 + static inline int arch_skip_callchain_idx(struct machine *machine __maybe_unused, 185 + struct thread *thread __maybe_unused, 186 + struct ip_callchain *chain __maybe_unused) 187 + { 188 + return -1; 189 + } 190 + #endif 191 + 179 192 #endif /* __PERF_CALLCHAIN_H */
+57
tools/perf/util/cloexec.c
··· 1 + #include "util.h" 2 + #include "../perf.h" 3 + #include "cloexec.h" 4 + #include "asm/bug.h" 5 + 6 + static unsigned long flag = PERF_FLAG_FD_CLOEXEC; 7 + 8 + static int perf_flag_probe(void) 9 + { 10 + /* use 'safest' configuration as used in perf_evsel__fallback() */ 11 + struct perf_event_attr attr = { 12 + .type = PERF_COUNT_SW_CPU_CLOCK, 13 + .config = PERF_COUNT_SW_CPU_CLOCK, 14 + }; 15 + int fd; 16 + int err; 17 + 18 + /* check cloexec flag */ 19 + fd = sys_perf_event_open(&attr, 0, -1, -1, 20 + PERF_FLAG_FD_CLOEXEC); 21 + err = errno; 22 + 23 + if (fd >= 0) { 24 + close(fd); 25 + return 1; 26 + } 27 + 28 + WARN_ONCE(err != EINVAL, 29 + "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n", 30 + err, strerror(err)); 31 + 32 + /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ 33 + fd = sys_perf_event_open(&attr, 0, -1, -1, 0); 34 + err = errno; 35 + 36 + if (WARN_ONCE(fd < 0, 37 + "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n", 38 + err, strerror(err))) 39 + return -1; 40 + 41 + close(fd); 42 + 43 + return 0; 44 + } 45 + 46 + unsigned long perf_event_open_cloexec_flag(void) 47 + { 48 + static bool probed; 49 + 50 + if (!probed) { 51 + if (perf_flag_probe() <= 0) 52 + flag = 0; 53 + probed = true; 54 + } 55 + 56 + return flag; 57 + }
+6
tools/perf/util/cloexec.h
··· 1 + #ifndef __PERF_CLOEXEC_H 2 + #define __PERF_CLOEXEC_H 3 + 4 + unsigned long perf_event_open_cloexec_flag(void); 5 + 6 + #endif /* __PERF_CLOEXEC_H */
+13
tools/perf/util/config.c
··· 350 350 return 0; 351 351 } 352 352 353 + static int perf_ui_config(const char *var, const char *value) 354 + { 355 + /* Add other config variables here. */ 356 + if (!strcmp(var, "ui.show-headers")) { 357 + symbol_conf.show_hist_headers = perf_config_bool(var, value); 358 + return 0; 359 + } 360 + return 0; 361 + } 362 + 353 363 int perf_default_config(const char *var, const char *value, 354 364 void *dummy __maybe_unused) 355 365 { ··· 368 358 369 359 if (!prefixcmp(var, "hist.")) 370 360 return perf_hist_config(var, value); 361 + 362 + if (!prefixcmp(var, "ui.")) 363 + return perf_ui_config(var, value); 371 364 372 365 /* Add other config variables here. */ 373 366 return 0;
+2 -1
tools/perf/util/data.c
··· 7 7 8 8 #include "data.h" 9 9 #include "util.h" 10 + #include "debug.h" 10 11 11 12 static bool check_pipe(struct perf_data_file *file) 12 13 { ··· 66 65 goto out_close; 67 66 68 67 if (!file->force && st.st_uid && (st.st_uid != geteuid())) { 69 - pr_err("file %s not owned by current user or root\n", 68 + pr_err("File %s not owned by current user or root (use -f to override)\n", 70 69 file->path); 71 70 goto out_close; 72 71 }
+50 -6
tools/perf/util/debug.c
··· 16 16 int verbose; 17 17 bool dump_trace = false, quiet = false; 18 18 19 - static int _eprintf(int level, const char *fmt, va_list args) 19 + static int _eprintf(int level, int var, const char *fmt, va_list args) 20 20 { 21 21 int ret = 0; 22 22 23 - if (verbose >= level) { 23 + if (var >= level) { 24 24 if (use_browser >= 1) 25 25 ui_helpline__vshow(fmt, args); 26 26 else ··· 30 30 return ret; 31 31 } 32 32 33 - int eprintf(int level, const char *fmt, ...) 33 + int eprintf(int level, int var, const char *fmt, ...) 34 34 { 35 35 va_list args; 36 36 int ret; 37 37 38 38 va_start(args, fmt); 39 - ret = _eprintf(level, fmt, args); 39 + ret = _eprintf(level, var, fmt, args); 40 40 va_end(args); 41 41 42 42 return ret; ··· 51 51 va_list args; 52 52 53 53 va_start(args, fmt); 54 - _eprintf(1, fmt, args); 54 + _eprintf(1, verbose, fmt, args); 55 55 va_end(args); 56 - eprintf(1, "\n"); 56 + eprintf(1, verbose, "\n"); 57 57 } 58 58 59 59 int dump_printf(const char *fmt, ...) ··· 104 104 } 105 105 } 106 106 printf(".\n"); 107 + } 108 + 109 + static struct debug_variable { 110 + const char *name; 111 + int *ptr; 112 + } debug_variables[] = { 113 + { .name = "verbose", .ptr = &verbose }, 114 + { .name = NULL, } 115 + }; 116 + 117 + int perf_debug_option(const char *str) 118 + { 119 + struct debug_variable *var = &debug_variables[0]; 120 + char *vstr, *s = strdup(str); 121 + int v = 1; 122 + 123 + vstr = strchr(s, '='); 124 + if (vstr) 125 + *vstr++ = 0; 126 + 127 + while (var->name) { 128 + if (!strcmp(s, var->name)) 129 + break; 130 + var++; 131 + } 132 + 133 + if (!var->name) { 134 + pr_err("Unknown debug variable name '%s'\n", s); 135 + free(s); 136 + return -1; 137 + } 138 + 139 + if (vstr) { 140 + v = atoi(vstr); 141 + /* 142 + * Allow only values in range (0, 10), 143 + * otherwise set 0. 144 + */ 145 + v = (v < 0) || (v > 10) ? 0 : v; 146 + } 147 + 148 + *var->ptr = v; 149 + free(s); 150 + return 0; 107 151 }
+22
tools/perf/util/debug.h
··· 11 11 extern int verbose; 12 12 extern bool quiet, dump_trace; 13 13 14 + #ifndef pr_fmt 15 + #define pr_fmt(fmt) fmt 16 + #endif 17 + 18 + #define pr_err(fmt, ...) \ 19 + eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__) 20 + #define pr_warning(fmt, ...) \ 21 + eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__) 22 + #define pr_info(fmt, ...) \ 23 + eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__) 24 + #define pr_debug(fmt, ...) \ 25 + eprintf(1, verbose, pr_fmt(fmt), ##__VA_ARGS__) 26 + #define pr_debugN(n, fmt, ...) \ 27 + eprintf(n, verbose, pr_fmt(fmt), ##__VA_ARGS__) 28 + #define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__) 29 + #define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) 30 + #define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__) 31 + 14 32 int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 15 33 void trace_event(union perf_event *event); 16 34 ··· 36 18 int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); 37 19 38 20 void pr_stat(const char *fmt, ...); 21 + 22 + int eprintf(int level, int var, const char *fmt, ...) __attribute__((format(printf, 3, 4))); 23 + 24 + int perf_debug_option(const char *str); 39 25 40 26 #endif /* __PERF_DEBUG_H */
+62 -9
tools/perf/util/dso.c
··· 216 216 { 217 217 int fd = __open_dso(dso, machine); 218 218 219 - if (fd > 0) { 219 + if (fd >= 0) { 220 220 dso__list_add(dso); 221 221 /* 222 222 * Check if we crossed the allowed number ··· 331 331 }; 332 332 int i = 0; 333 333 334 + if (dso->data.status == DSO_DATA_STATUS_ERROR) 335 + return -1; 336 + 334 337 if (dso->data.fd >= 0) 335 - return dso->data.fd; 338 + goto out; 336 339 337 340 if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) { 338 341 dso->data.fd = open_dso(dso, machine); 339 - return dso->data.fd; 342 + goto out; 340 343 } 341 344 342 345 do { 343 - int fd; 344 - 345 346 dso->binary_type = binary_type_data[i++]; 346 347 347 - fd = open_dso(dso, machine); 348 - if (fd >= 0) 349 - return dso->data.fd = fd; 348 + dso->data.fd = open_dso(dso, machine); 349 + if (dso->data.fd >= 0) 350 + goto out; 350 351 351 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 374 static void ··· 542 524 } 543 525 544 526 return 0; 527 + } 528 + 529 + /** 530 + * dso__data_size - Return dso data size 531 + * @dso: dso object 532 + * @machine: machine object 533 + * 534 + * Return: dso data size 535 + */ 536 + off_t dso__data_size(struct dso *dso, struct machine *machine) 537 + { 538 + int fd; 539 + 540 + fd = dso__data_fd(dso, machine); 541 + if (fd < 0) 542 + return fd; 543 + 544 + if (data_file_size(dso)) 545 + return -1; 546 + 547 + /* For now just estimate dso data size is close to file size */ 548 + return dso->data.file_size; 545 549 } 546 550 547 551 static ssize_t data_read_offset(struct dso *dso, u64 offset, ··· 741 701 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; 742 702 dso->data.cache = RB_ROOT; 743 703 dso->data.fd = -1; 704 + dso->data.status = DSO_DATA_STATUS_UNKNOWN; 744 705 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; 745 706 dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND; 707 + dso->is_64_bit = (sizeof(void *) == 8); 746 708 dso->loaded = 0; 747 709 dso->rel = 0; 748 710 dso->sorted_by_name = 0; ··· 939 897 } 940 898 941 899 return ret; 900 + } 901 + 902 + enum dso_type dso__type(struct dso *dso, struct machine *machine) 903 + { 904 + int fd; 905 + 906 + fd = dso__data_fd(dso, machine); 907 + if (fd < 0) 908 + return DSO__TYPE_UNKNOWN; 909 + 910 + return dso__type_fd(fd); 942 911 }
+26
tools/perf/util/dso.h
··· 5 5 #include <linux/rbtree.h> 6 6 #include <stdbool.h> 7 7 #include <linux/types.h> 8 + #include <linux/bitops.h> 8 9 #include "map.h" 9 10 #include "build-id.h" 10 11 ··· 39 38 DSO_SWAP__UNSET, 40 39 DSO_SWAP__NO, 41 40 DSO_SWAP__YES, 41 + }; 42 + 43 + enum dso_data_status { 44 + DSO_DATA_STATUS_ERROR = -1, 45 + DSO_DATA_STATUS_UNKNOWN = 0, 46 + DSO_DATA_STATUS_OK = 1, 47 + }; 48 + 49 + enum dso_data_status_seen { 50 + DSO_DATA_STATUS_SEEN_ITRACE, 51 + }; 52 + 53 + enum dso_type { 54 + DSO__TYPE_UNKNOWN, 55 + DSO__TYPE_64BIT, 56 + DSO__TYPE_32BIT, 57 + DSO__TYPE_X32BIT, 42 58 }; 43 59 44 60 #define DSO__SWAP(dso, type, val) \ ··· 108 90 u8 annotate_warned:1; 109 91 u8 short_name_allocated:1; 110 92 u8 long_name_allocated:1; 93 + u8 is_64_bit:1; 111 94 u8 sorted_by_name; 112 95 u8 loaded; 113 96 u8 rel; ··· 122 103 struct { 123 104 struct rb_root cache; 124 105 int fd; 106 + int status; 107 + u32 status_seen; 125 108 size_t file_size; 126 109 struct list_head open_entry; 127 110 } data; ··· 174 153 * The dso__data_* external interface provides following functions: 175 154 * dso__data_fd 176 155 * dso__data_close 156 + * dso__data_size 177 157 * dso__data_read_offset 178 158 * dso__data_read_addr 179 159 * ··· 212 190 int dso__data_fd(struct dso *dso, struct machine *machine); 213 191 void dso__data_close(struct dso *dso); 214 192 193 + off_t dso__data_size(struct dso *dso, struct machine *machine); 215 194 ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 216 195 u64 offset, u8 *data, ssize_t size); 217 196 ssize_t dso__data_read_addr(struct dso *dso, struct map *map, 218 197 struct machine *machine, u64 addr, 219 198 u8 *data, ssize_t size); 199 + bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by); 220 200 221 201 struct map *dso__new_map(const char *name); 222 202 struct dso *dso__kernel_findnew(struct machine *machine, const char *name, ··· 252 228 } 253 229 254 230 void dso__free_a2l(struct dso *dso); 231 + 232 + enum dso_type dso__type(struct dso *dso, struct machine *machine); 255 233 256 234 #endif /* __PERF_DSO */
+51 -1
tools/perf/util/event.c
··· 603 603 604 604 size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) 605 605 { 606 - return fprintf(fp, ": %s:%d\n", event->comm.comm, event->comm.tid); 606 + const char *s; 607 + 608 + if (event->header.misc & PERF_RECORD_MISC_COMM_EXEC) 609 + s = " exec"; 610 + else 611 + s = ""; 612 + 613 + return fprintf(fp, "%s: %s:%d\n", s, event->comm.comm, event->comm.tid); 607 614 } 608 615 609 616 int perf_event__process_comm(struct perf_tool *tool __maybe_unused, ··· 788 781 cpumode == PERF_RECORD_MISC_USER && 789 782 machine && mg != &machine->kmaps) { 790 783 mg = &machine->kmaps; 784 + load_map = true; 791 785 goto try_again; 792 786 } 793 787 } else { ··· 873 865 } 874 866 875 867 return 0; 868 + } 869 + 870 + bool is_bts_event(struct perf_event_attr *attr) 871 + { 872 + return attr->type == PERF_TYPE_HARDWARE && 873 + (attr->config & PERF_COUNT_HW_BRANCH_INSTRUCTIONS) && 874 + attr->sample_period == 1; 875 + } 876 + 877 + bool sample_addr_correlates_sym(struct perf_event_attr *attr) 878 + { 879 + if (attr->type == PERF_TYPE_SOFTWARE && 880 + (attr->config == PERF_COUNT_SW_PAGE_FAULTS || 881 + attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN || 882 + attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)) 883 + return true; 884 + 885 + if (is_bts_event(attr)) 886 + return true; 887 + 888 + return false; 889 + } 890 + 891 + void perf_event__preprocess_sample_addr(union perf_event *event, 892 + struct perf_sample *sample, 893 + struct machine *machine, 894 + struct thread *thread, 895 + struct addr_location *al) 896 + { 897 + u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 898 + 899 + thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 900 + sample->addr, al); 901 + if (!al->map) 902 + thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE, 903 + sample->addr, al); 904 + 905 + al->cpu = sample->cpu; 906 + al->sym = NULL; 907 + 908 + if (al->map) 909 + al->sym = map__find_symbol(al->map, al->addr, NULL); 876 910 }
+10
tools/perf/util/event.h
··· 288 288 struct addr_location *al, 289 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 301 const char *perf_event__name(unsigned int id); 292 302 293 303 size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
+29 -22
tools/perf/util/evlist.c
··· 606 606 return evlist->mmap != NULL ? 0 : -ENOMEM; 607 607 } 608 608 609 - static int __perf_evlist__mmap(struct perf_evlist *evlist, 610 - int idx, int prot, int mask, int fd) 609 + struct mmap_params { 610 + int prot; 611 + int mask; 612 + }; 613 + 614 + static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx, 615 + struct mmap_params *mp, int fd) 611 616 { 612 617 evlist->mmap[idx].prev = 0; 613 - evlist->mmap[idx].mask = mask; 614 - evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot, 618 + evlist->mmap[idx].mask = mp->mask; 619 + evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, mp->prot, 615 620 MAP_SHARED, fd, 0); 616 621 if (evlist->mmap[idx].base == MAP_FAILED) { 617 622 pr_debug2("failed to mmap perf event ring buffer, error %d\n", ··· 630 625 } 631 626 632 627 static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, 633 - int prot, int mask, int cpu, int thread, 634 - int *output) 628 + struct mmap_params *mp, int cpu, 629 + int thread, int *output) 635 630 { 636 631 struct perf_evsel *evsel; 637 632 ··· 640 635 641 636 if (*output == -1) { 642 637 *output = fd; 643 - if (__perf_evlist__mmap(evlist, idx, prot, mask, 644 - *output) < 0) 638 + if (__perf_evlist__mmap(evlist, idx, mp, *output) < 0) 645 639 return -1; 646 640 } else { 647 641 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0) ··· 655 651 return 0; 656 652 } 657 653 658 - static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, 659 - int mask) 654 + static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, 655 + struct mmap_params *mp) 660 656 { 661 657 int cpu, thread; 662 658 int nr_cpus = cpu_map__nr(evlist->cpus); ··· 667 663 int output = -1; 668 664 669 665 for (thread = 0; thread < nr_threads; thread++) { 670 - if (perf_evlist__mmap_per_evsel(evlist, cpu, prot, mask, 671 - cpu, thread, &output)) 666 + if (perf_evlist__mmap_per_evsel(evlist, cpu, mp, cpu, 667 + thread, &output)) 672 668 goto out_unmap; 673 669 } 674 670 } ··· 681 677 return -1; 682 678 } 683 679 684 - static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, 685 - int mask) 680 + static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, 681 + struct mmap_params *mp) 686 682 { 687 683 int thread; 688 684 int nr_threads = thread_map__nr(evlist->threads); ··· 691 687 for (thread = 0; thread < nr_threads; thread++) { 692 688 int output = -1; 693 689 694 - if (perf_evlist__mmap_per_evsel(evlist, thread, prot, mask, 0, 695 - thread, &output)) 690 + if (perf_evlist__mmap_per_evsel(evlist, thread, mp, 0, thread, 691 + &output)) 696 692 goto out_unmap; 697 693 } 698 694 ··· 797 793 struct perf_evsel *evsel; 798 794 const struct cpu_map *cpus = evlist->cpus; 799 795 const struct thread_map *threads = evlist->threads; 800 - int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask; 796 + struct mmap_params mp = { 797 + .prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), 798 + }; 801 799 802 800 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) 803 801 return -ENOMEM; ··· 810 804 evlist->overwrite = overwrite; 811 805 evlist->mmap_len = perf_evlist__mmap_size(pages); 812 806 pr_debug("mmap size %zuB\n", evlist->mmap_len); 813 - mask = evlist->mmap_len - page_size - 1; 807 + mp.mask = evlist->mmap_len - page_size - 1; 814 808 815 809 evlist__for_each(evlist, evsel) { 816 810 if ((evsel->attr.read_format & PERF_FORMAT_ID) && ··· 820 814 } 821 815 822 816 if (cpu_map__empty(cpus)) 823 - return perf_evlist__mmap_per_thread(evlist, prot, mask); 817 + return perf_evlist__mmap_per_thread(evlist, &mp); 824 818 825 - return perf_evlist__mmap_per_cpu(evlist, prot, mask); 819 + return perf_evlist__mmap_per_cpu(evlist, &mp); 826 820 } 827 821 828 822 int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) ··· 1220 1214 "For your workloads it needs to be <= 1\nHint:\t"); 1221 1215 } 1222 1216 printed += scnprintf(buf + printed, size - printed, 1223 - "For system wide tracing it needs to be set to -1"); 1217 + "For system wide tracing it needs to be set to -1.\n"); 1224 1218 1225 1219 printed += scnprintf(buf + printed, size - printed, 1226 - ".\nHint:\tThe current value is %d.", value); 1220 + "Hint:\tTry: 'sudo sh -c \"echo -1 > /proc/sys/kernel/perf_event_paranoid\"'\n" 1221 + "Hint:\tThe current value is %d.", value); 1227 1222 break; 1228 1223 default: 1229 1224 scnprintf(buf, size, "%s", emsg);
+19 -7
tools/perf/util/evsel.c
··· 29 29 bool sample_id_all; 30 30 bool exclude_guest; 31 31 bool mmap2; 32 + bool cloexec; 32 33 } perf_missing_features; 33 34 34 35 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) ··· 624 623 attr->mmap_data = track; 625 624 } 626 625 627 - if (opts->call_graph_enabled) 626 + if (opts->call_graph_enabled && !evsel->no_aux_samples) 628 627 perf_evsel__config_callgraph(evsel, opts); 629 628 630 629 if (target__has_cpu(&opts->target)) ··· 638 637 target__has_cpu(&opts->target) || per_cpu)) 639 638 perf_evsel__set_sample_bit(evsel, TIME); 640 639 641 - if (opts->raw_samples) { 640 + if (opts->raw_samples && !evsel->no_aux_samples) { 642 641 perf_evsel__set_sample_bit(evsel, TIME); 643 642 perf_evsel__set_sample_bit(evsel, RAW); 644 643 perf_evsel__set_sample_bit(evsel, CPU); ··· 651 650 attr->watermark = 0; 652 651 attr->wakeup_events = 1; 653 652 } 654 - if (opts->branch_stack) { 653 + if (opts->branch_stack && !evsel->no_aux_samples) { 655 654 perf_evsel__set_sample_bit(evsel, BRANCH_STACK); 656 655 attr->branch_sample_type = opts->branch_stack; 657 656 } ··· 682 681 if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel) && 683 682 !opts->initial_delay) 684 683 attr->enable_on_exec = 1; 684 + 685 + if (evsel->immediate) { 686 + attr->disabled = 0; 687 + attr->enable_on_exec = 0; 688 + } 685 689 } 686 690 687 691 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) ··· 966 960 ret += PRINT_ATTR2(exclude_user, exclude_kernel); 967 961 ret += PRINT_ATTR2(exclude_hv, exclude_idle); 968 962 ret += PRINT_ATTR2(mmap, comm); 963 + ret += PRINT_ATTR2(mmap2, comm_exec); 969 964 ret += PRINT_ATTR2(freq, inherit_stat); 970 965 ret += PRINT_ATTR2(enable_on_exec, task); 971 966 ret += PRINT_ATTR2(watermark, precise_ip); ··· 974 967 ret += PRINT_ATTR2(exclude_host, exclude_guest); 975 968 ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel, 976 969 "excl.callchain_user", exclude_callchain_user); 977 - ret += PRINT_ATTR_U32(mmap2); 978 970 979 971 ret += PRINT_ATTR_U32(wakeup_events); 980 972 ret += PRINT_ATTR_U32(wakeup_watermark); ··· 995 989 struct thread_map *threads) 996 990 { 997 991 int cpu, thread; 998 - unsigned long flags = 0; 992 + unsigned long flags = PERF_FLAG_FD_CLOEXEC; 999 993 int pid = -1, err; 1000 994 enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE; 1001 995 ··· 1004 998 return -ENOMEM; 1005 999 1006 1000 if (evsel->cgrp) { 1007 - flags = PERF_FLAG_PID_CGROUP; 1001 + flags |= PERF_FLAG_PID_CGROUP; 1008 1002 pid = evsel->cgrp->fd; 1009 1003 } 1010 1004 1011 1005 fallback_missing_features: 1006 + if (perf_missing_features.cloexec) 1007 + flags &= ~(unsigned long)PERF_FLAG_FD_CLOEXEC; 1012 1008 if (perf_missing_features.mmap2) 1013 1009 evsel->attr.mmap2 = 0; 1014 1010 if (perf_missing_features.exclude_guest) ··· 1079 1071 if (err != -EINVAL || cpu > 0 || thread > 0) 1080 1072 goto out_close; 1081 1073 1082 - if (!perf_missing_features.mmap2 && evsel->attr.mmap2) { 1074 + if (!perf_missing_features.cloexec && (flags & PERF_FLAG_FD_CLOEXEC)) { 1075 + perf_missing_features.cloexec = true; 1076 + goto fallback_missing_features; 1077 + } else if (!perf_missing_features.mmap2 && evsel->attr.mmap2) { 1083 1078 perf_missing_features.mmap2 = true; 1084 1079 goto fallback_missing_features; 1085 1080 } else if (!perf_missing_features.exclude_guest && ··· 1951 1940 if_print(mmap); 1952 1941 if_print(mmap2); 1953 1942 if_print(comm); 1943 + if_print(comm_exec); 1954 1944 if_print(freq); 1955 1945 if_print(inherit_stat); 1956 1946 if_print(enable_on_exec);
+2
tools/perf/util/evsel.h
··· 83 83 int is_pos; 84 84 bool supported; 85 85 bool needs_swap; 86 + bool no_aux_samples; 87 + bool immediate; 86 88 /* parse modifier helper */ 87 89 int exclude_GH; 88 90 int nr_members;
+46 -5
tools/perf/util/header.c
··· 200 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 244 static int __dsos__write_buildid_table(struct list_head *head, 204 245 struct machine *machine, 205 246 pid_t pid, u16 misc, int fd) ··· 256 215 if (!pos->hit) 257 216 continue; 258 217 259 - if (is_vdso_map(pos->short_name)) { 260 - name = (char *) VDSO__MAP_NAME; 261 - name_len = sizeof(VDSO__MAP_NAME) + 1; 218 + if (dso__is_vdso(pos)) { 219 + name = pos->short_name; 220 + name_len = pos->short_name_len + 1; 262 221 } else if (dso__is_kcore(pos)) { 263 222 machine__mmap_name(machine, nm, sizeof(nm)); 264 223 name = nm; ··· 339 298 340 299 len = scnprintf(filename, size, "%s%s%s", 341 300 debugdir, slash ? "/" : "", 342 - is_vdso ? VDSO__MAP_NAME : realname); 301 + is_vdso ? DSO__NAME_VDSO : realname); 343 302 if (mkdir_p(filename, 0755)) 344 303 goto out_free; 345 304 ··· 427 386 const char *debugdir) 428 387 { 429 388 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; 430 - bool is_vdso = is_vdso_map(dso->short_name); 389 + bool is_vdso = dso__is_vdso(dso); 431 390 const char *name = dso->long_name; 432 391 char nm[PATH_MAX]; 433 392
+2
tools/perf/util/header.h
··· 151 151 struct perf_session *session); 152 152 bool is_perf_magic(u64 magic); 153 153 154 + int dsos__hit_all(struct perf_session *session); 155 + 154 156 /* 155 157 * arch specific callback 156 158 */
-21
tools/perf/util/include/linux/kernel.h
··· 94 94 return (i >= ssize) ? (ssize - 1) : i; 95 95 } 96 96 97 - int eprintf(int level, 98 - const char *fmt, ...) __attribute__((format(printf, 2, 3))); 99 - 100 - #ifndef pr_fmt 101 - #define pr_fmt(fmt) fmt 102 - #endif 103 - 104 - #define pr_err(fmt, ...) \ 105 - eprintf(0, pr_fmt(fmt), ##__VA_ARGS__) 106 - #define pr_warning(fmt, ...) \ 107 - eprintf(0, pr_fmt(fmt), ##__VA_ARGS__) 108 - #define pr_info(fmt, ...) \ 109 - eprintf(0, pr_fmt(fmt), ##__VA_ARGS__) 110 - #define pr_debug(fmt, ...) \ 111 - eprintf(1, pr_fmt(fmt), ##__VA_ARGS__) 112 - #define pr_debugN(n, fmt, ...) \ 113 - eprintf(n, pr_fmt(fmt), ##__VA_ARGS__) 114 - #define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__) 115 - #define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) 116 - #define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__) 117 - 118 97 /* 119 98 * This looks more complex than it should be. But we need to 120 99 * get the type for the ~ right in round_down (it needs to be
+140
tools/perf/util/kvm-stat.h
··· 1 + #ifndef __PERF_KVM_STAT_H 2 + #define __PERF_KVM_STAT_H 3 + 4 + #include "../perf.h" 5 + #include "evsel.h" 6 + #include "evlist.h" 7 + #include "session.h" 8 + #include "tool.h" 9 + #include "stat.h" 10 + 11 + struct event_key { 12 + #define INVALID_KEY (~0ULL) 13 + u64 key; 14 + int info; 15 + struct exit_reasons_table *exit_reasons; 16 + }; 17 + 18 + struct kvm_event_stats { 19 + u64 time; 20 + struct stats stats; 21 + }; 22 + 23 + struct kvm_event { 24 + struct list_head hash_entry; 25 + struct rb_node rb; 26 + 27 + struct event_key key; 28 + 29 + struct kvm_event_stats total; 30 + 31 + #define DEFAULT_VCPU_NUM 8 32 + int max_vcpu; 33 + struct kvm_event_stats *vcpu; 34 + }; 35 + 36 + typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int); 37 + 38 + struct kvm_event_key { 39 + const char *name; 40 + key_cmp_fun key; 41 + }; 42 + 43 + struct perf_kvm_stat; 44 + 45 + struct child_event_ops { 46 + void (*get_key)(struct perf_evsel *evsel, 47 + struct perf_sample *sample, 48 + struct event_key *key); 49 + const char *name; 50 + }; 51 + 52 + struct kvm_events_ops { 53 + bool (*is_begin_event)(struct perf_evsel *evsel, 54 + struct perf_sample *sample, 55 + struct event_key *key); 56 + bool (*is_end_event)(struct perf_evsel *evsel, 57 + struct perf_sample *sample, struct event_key *key); 58 + struct child_event_ops *child_ops; 59 + void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key, 60 + char *decode); 61 + const char *name; 62 + }; 63 + 64 + struct exit_reasons_table { 65 + unsigned long exit_code; 66 + const char *reason; 67 + }; 68 + 69 + #define EVENTS_BITS 12 70 + #define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS) 71 + 72 + struct perf_kvm_stat { 73 + struct perf_tool tool; 74 + struct record_opts opts; 75 + struct perf_evlist *evlist; 76 + struct perf_session *session; 77 + 78 + const char *file_name; 79 + const char *report_event; 80 + const char *sort_key; 81 + int trace_vcpu; 82 + 83 + struct exit_reasons_table *exit_reasons; 84 + const char *exit_reasons_isa; 85 + 86 + struct kvm_events_ops *events_ops; 87 + key_cmp_fun compare; 88 + struct list_head kvm_events_cache[EVENTS_CACHE_SIZE]; 89 + 90 + u64 total_time; 91 + u64 total_count; 92 + u64 lost_events; 93 + u64 duration; 94 + 95 + const char *pid_str; 96 + struct intlist *pid_list; 97 + 98 + struct rb_root result; 99 + 100 + int timerfd; 101 + unsigned int display_time; 102 + bool live; 103 + }; 104 + 105 + struct kvm_reg_events_ops { 106 + const char *name; 107 + struct kvm_events_ops *ops; 108 + }; 109 + 110 + void exit_event_get_key(struct perf_evsel *evsel, 111 + struct perf_sample *sample, 112 + struct event_key *key); 113 + bool exit_event_begin(struct perf_evsel *evsel, 114 + struct perf_sample *sample, 115 + struct event_key *key); 116 + bool exit_event_end(struct perf_evsel *evsel, 117 + struct perf_sample *sample, 118 + struct event_key *key); 119 + void exit_event_decode_key(struct perf_kvm_stat *kvm, 120 + struct event_key *key, 121 + char *decode); 122 + 123 + bool kvm_exit_event(struct perf_evsel *evsel); 124 + bool kvm_entry_event(struct perf_evsel *evsel); 125 + 126 + #define define_exit_reasons_table(name, symbols) \ 127 + static struct exit_reasons_table name[] = { \ 128 + symbols, { -1, NULL } \ 129 + } 130 + 131 + /* 132 + * arch specific callbacks and data structures 133 + */ 134 + int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid); 135 + 136 + extern const char * const kvm_events_tp[]; 137 + extern struct kvm_reg_events_ops kvm_reg_events_ops[]; 138 + extern const char * const kvm_skip_events[]; 139 + 140 + #endif /* __PERF_KVM_STAT_H */
+125 -14
tools/perf/util/machine.c
··· 8 8 #include "sort.h" 9 9 #include "strlist.h" 10 10 #include "thread.h" 11 + #include "vdso.h" 11 12 #include <stdbool.h> 12 13 #include <symbol/kallsyms.h> 13 14 #include "unwind.h" ··· 24 23 INIT_LIST_HEAD(&machine->dead_threads); 25 24 machine->last_match = NULL; 26 25 26 + machine->vdso_info = NULL; 27 + 27 28 machine->kmaps.machine = machine; 28 29 machine->pid = pid; 29 30 ··· 37 34 return -ENOMEM; 38 35 39 36 if (pid != HOST_KERNEL_ID) { 40 - struct thread *thread = machine__findnew_thread(machine, 0, 37 + struct thread *thread = machine__findnew_thread(machine, -1, 41 38 pid); 42 39 char comm[64]; 43 40 ··· 47 44 snprintf(comm, sizeof(comm), "[guest/%d]", pid); 48 45 thread__set_comm(thread, comm, 0); 49 46 } 47 + 48 + machine->current_tid = NULL; 50 49 51 50 return 0; 52 51 } ··· 108 103 map_groups__exit(&machine->kmaps); 109 104 dsos__delete(&machine->user_dsos); 110 105 dsos__delete(&machine->kernel_dsos); 106 + vdso__exit(machine); 111 107 zfree(&machine->root_dir); 108 + zfree(&machine->current_tid); 112 109 } 113 110 114 111 void machine__delete(struct machine *machine) ··· 279 272 return; 280 273 } 281 274 275 + static void machine__update_thread_pid(struct machine *machine, 276 + struct thread *th, pid_t pid) 277 + { 278 + struct thread *leader; 279 + 280 + if (pid == th->pid_ || pid == -1 || th->pid_ != -1) 281 + return; 282 + 283 + th->pid_ = pid; 284 + 285 + if (th->pid_ == th->tid) 286 + return; 287 + 288 + leader = machine__findnew_thread(machine, th->pid_, th->pid_); 289 + if (!leader) 290 + goto out_err; 291 + 292 + if (!leader->mg) 293 + leader->mg = map_groups__new(); 294 + 295 + if (!leader->mg) 296 + goto out_err; 297 + 298 + if (th->mg == leader->mg) 299 + return; 300 + 301 + if (th->mg) { 302 + /* 303 + * Maps are created from MMAP events which provide the pid and 304 + * tid. Consequently there never should be any maps on a thread 305 + * with an unknown pid. Just print an error if there are. 306 + */ 307 + if (!map_groups__empty(th->mg)) 308 + pr_err("Discarding thread maps for %d:%d\n", 309 + th->pid_, th->tid); 310 + map_groups__delete(th->mg); 311 + } 312 + 313 + th->mg = map_groups__get(leader->mg); 314 + 315 + return; 316 + 317 + out_err: 318 + pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid); 319 + } 320 + 282 321 static struct thread *__machine__findnew_thread(struct machine *machine, 283 322 pid_t pid, pid_t tid, 284 323 bool create) ··· 338 285 * so most of the time we dont have to look up 339 286 * the full rbtree: 340 287 */ 341 - if (machine->last_match && machine->last_match->tid == tid) { 342 - if (pid && pid != machine->last_match->pid_) 343 - machine->last_match->pid_ = pid; 344 - return machine->last_match; 288 + th = machine->last_match; 289 + if (th && th->tid == tid) { 290 + machine__update_thread_pid(machine, th, pid); 291 + return th; 345 292 } 346 293 347 294 while (*p != NULL) { ··· 350 297 351 298 if (th->tid == tid) { 352 299 machine->last_match = th; 353 - if (pid && pid != th->pid_) 354 - th->pid_ = pid; 300 + machine__update_thread_pid(machine, th, pid); 355 301 return th; 356 302 } 357 303 ··· 377 325 * within thread__init_map_groups to find the thread 378 326 * leader and that would screwed the rb tree. 379 327 */ 380 - if (thread__init_map_groups(th, machine)) 328 + if (thread__init_map_groups(th, machine)) { 329 + thread__delete(th); 381 330 return NULL; 331 + } 382 332 } 383 333 384 334 return th; ··· 1099 1045 else 1100 1046 type = MAP__FUNCTION; 1101 1047 1102 - map = map__new(&machine->user_dsos, event->mmap2.start, 1048 + map = map__new(machine, event->mmap2.start, 1103 1049 event->mmap2.len, event->mmap2.pgoff, 1104 1050 event->mmap2.pid, event->mmap2.maj, 1105 1051 event->mmap2.min, event->mmap2.ino, 1106 1052 event->mmap2.ino_generation, 1107 1053 event->mmap2.prot, 1108 1054 event->mmap2.flags, 1109 - event->mmap2.filename, type); 1055 + event->mmap2.filename, type, thread); 1110 1056 1111 1057 if (map == NULL) 1112 1058 goto out_problem; ··· 1149 1095 else 1150 1096 type = MAP__FUNCTION; 1151 1097 1152 - map = map__new(&machine->user_dsos, event->mmap.start, 1098 + map = map__new(machine, event->mmap.start, 1153 1099 event->mmap.len, event->mmap.pgoff, 1154 1100 event->mmap.pid, 0, 0, 0, 0, 0, 0, 1155 1101 event->mmap.filename, 1156 - type); 1102 + type, thread); 1157 1103 1158 1104 if (map == NULL) 1159 1105 goto out_problem; ··· 1335 1281 u8 cpumode = PERF_RECORD_MISC_USER; 1336 1282 int chain_nr = min(max_stack, (int)chain->nr); 1337 1283 int i; 1284 + int j; 1338 1285 int err; 1286 + int skip_idx __maybe_unused; 1339 1287 1340 1288 callchain_cursor_reset(&callchain_cursor); 1341 1289 ··· 1346 1290 return 0; 1347 1291 } 1348 1292 1293 + /* 1294 + * Based on DWARF debug information, some architectures skip 1295 + * a callchain entry saved by the kernel. 1296 + */ 1297 + skip_idx = arch_skip_callchain_idx(machine, thread, chain); 1298 + 1349 1299 for (i = 0; i < chain_nr; i++) { 1350 1300 u64 ip; 1351 1301 struct addr_location al; 1352 1302 1353 1303 if (callchain_param.order == ORDER_CALLEE) 1354 - ip = chain->ips[i]; 1304 + j = i; 1355 1305 else 1356 - ip = chain->ips[chain->nr - i - 1]; 1306 + j = chain->nr - i - 1; 1307 + 1308 + #ifdef HAVE_SKIP_CALLCHAIN_IDX 1309 + if (j == skip_idx) 1310 + continue; 1311 + #endif 1312 + ip = chain->ips[j]; 1357 1313 1358 1314 if (ip >= PERF_CONTEXT_MAX) { 1359 1315 switch (ip) { ··· 1486 1418 else if (target__has_cpu(target)) 1487 1419 return perf_event__synthesize_threads(tool, process, machine, data_mmap); 1488 1420 /* command specified */ 1421 + return 0; 1422 + } 1423 + 1424 + pid_t machine__get_current_tid(struct machine *machine, int cpu) 1425 + { 1426 + if (cpu < 0 || cpu >= MAX_NR_CPUS || !machine->current_tid) 1427 + return -1; 1428 + 1429 + return machine->current_tid[cpu]; 1430 + } 1431 + 1432 + int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, 1433 + pid_t tid) 1434 + { 1435 + struct thread *thread; 1436 + 1437 + if (cpu < 0) 1438 + return -EINVAL; 1439 + 1440 + if (!machine->current_tid) { 1441 + int i; 1442 + 1443 + machine->current_tid = calloc(MAX_NR_CPUS, sizeof(pid_t)); 1444 + if (!machine->current_tid) 1445 + return -ENOMEM; 1446 + for (i = 0; i < MAX_NR_CPUS; i++) 1447 + machine->current_tid[i] = -1; 1448 + } 1449 + 1450 + if (cpu >= MAX_NR_CPUS) { 1451 + pr_err("Requested CPU %d too large. ", cpu); 1452 + pr_err("Consider raising MAX_NR_CPUS\n"); 1453 + return -EINVAL; 1454 + } 1455 + 1456 + machine->current_tid[cpu] = tid; 1457 + 1458 + thread = machine__findnew_thread(machine, pid, tid); 1459 + if (!thread) 1460 + return -ENOMEM; 1461 + 1462 + thread->cpu = cpu; 1463 + 1489 1464 return 0; 1490 1465 }
+8
tools/perf/util/machine.h
··· 20 20 21 21 extern const char *ref_reloc_sym_names[]; 22 22 23 + struct vdso_info; 24 + 23 25 struct machine { 24 26 struct rb_node rb_node; 25 27 pid_t pid; ··· 30 28 struct rb_root threads; 31 29 struct list_head dead_threads; 32 30 struct thread *last_match; 31 + struct vdso_info *vdso_info; 33 32 struct list_head user_dsos; 34 33 struct list_head kernel_dsos; 35 34 struct map_groups kmaps; 36 35 struct map *vmlinux_maps[MAP__NR_TYPES]; 37 36 symbol_filter_t symbol_filter; 37 + pid_t *current_tid; 38 38 }; 39 39 40 40 static inline ··· 194 190 return __machine__synthesize_threads(machine, NULL, target, threads, 195 191 perf_event__process, data_mmap); 196 192 } 193 + 194 + pid_t machine__get_current_tid(struct machine *machine, int cpu); 195 + int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, 196 + pid_t tid); 197 197 198 198 #endif /* __PERF_MACHINE_H */
+31 -16
tools/perf/util/map.c
··· 12 12 #include "vdso.h" 13 13 #include "build-id.h" 14 14 #include "util.h" 15 + #include "debug.h" 16 + #include "machine.h" 15 17 #include <linux/string.h> 16 18 17 19 const char *map_type__name[MAP__NR_TYPES] = { ··· 138 136 map->erange_warned = false; 139 137 } 140 138 141 - struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 139 + struct map *map__new(struct machine *machine, u64 start, u64 len, 142 140 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 143 141 u64 ino_gen, u32 prot, u32 flags, char *filename, 144 - enum map_type type) 142 + enum map_type type, struct thread *thread) 145 143 { 146 144 struct map *map = malloc(sizeof(*map)); 147 145 ··· 174 172 175 173 if (vdso) { 176 174 pgoff = 0; 177 - dso = vdso__dso_findnew(dsos__list); 175 + dso = vdso__dso_findnew(machine, thread); 178 176 } else 179 - dso = __dsos__findnew(dsos__list, filename); 177 + dso = __dsos__findnew(&machine->user_dsos, filename); 180 178 181 179 if (dso == NULL) 182 180 goto out_delete; ··· 456 454 } 457 455 } 458 456 457 + bool map_groups__empty(struct map_groups *mg) 458 + { 459 + int i; 460 + 461 + for (i = 0; i < MAP__NR_TYPES; ++i) { 462 + if (maps__first(&mg->maps[i])) 463 + return false; 464 + if (!list_empty(&mg->removed_maps[i])) 465 + return false; 466 + } 467 + 468 + return true; 469 + } 470 + 459 471 struct map_groups *map_groups__new(void) 460 472 { 461 473 struct map_groups *mg = malloc(sizeof(*mg)); ··· 570 554 return ams->sym ? 0 : -1; 571 555 } 572 556 573 - size_t __map_groups__fprintf_maps(struct map_groups *mg, 574 - enum map_type type, int verbose, FILE *fp) 557 + size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type, 558 + FILE *fp) 575 559 { 576 560 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); 577 561 struct rb_node *nd; ··· 589 573 return printed; 590 574 } 591 575 592 - size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp) 576 + static size_t map_groups__fprintf_maps(struct map_groups *mg, FILE *fp) 593 577 { 594 578 size_t printed = 0, i; 595 579 for (i = 0; i < MAP__NR_TYPES; ++i) 596 - printed += __map_groups__fprintf_maps(mg, i, verbose, fp); 580 + printed += __map_groups__fprintf_maps(mg, i, fp); 597 581 return printed; 598 582 } 599 583 600 584 static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg, 601 - enum map_type type, 602 - int verbose, FILE *fp) 585 + enum map_type type, FILE *fp) 603 586 { 604 587 struct map *pos; 605 588 size_t printed = 0; ··· 615 600 } 616 601 617 602 static size_t map_groups__fprintf_removed_maps(struct map_groups *mg, 618 - int verbose, FILE *fp) 603 + FILE *fp) 619 604 { 620 605 size_t printed = 0, i; 621 606 for (i = 0; i < MAP__NR_TYPES; ++i) 622 - printed += __map_groups__fprintf_removed_maps(mg, i, verbose, fp); 607 + printed += __map_groups__fprintf_removed_maps(mg, i, fp); 623 608 return printed; 624 609 } 625 610 626 - size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp) 611 + size_t map_groups__fprintf(struct map_groups *mg, FILE *fp) 627 612 { 628 - size_t printed = map_groups__fprintf_maps(mg, verbose, fp); 613 + size_t printed = map_groups__fprintf_maps(mg, fp); 629 614 printed += fprintf(fp, "Removed maps:\n"); 630 - return printed + map_groups__fprintf_removed_maps(mg, verbose, fp); 615 + return printed + map_groups__fprintf_removed_maps(mg, fp); 631 616 } 632 617 633 618 int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, 634 - int verbose, FILE *fp) 619 + FILE *fp) 635 620 { 636 621 struct rb_root *root = &mg->maps[map->type]; 637 622 struct rb_node *next = rb_first(root);
+8 -7
tools/perf/util/map.h
··· 66 66 67 67 struct map_groups *map_groups__new(void); 68 68 void map_groups__delete(struct map_groups *mg); 69 + bool map_groups__empty(struct map_groups *mg); 69 70 70 71 static inline struct map_groups *map_groups__get(struct map_groups *mg) 71 72 { ··· 104 103 u64 map__objdump_2mem(struct map *map, u64 ip); 105 104 106 105 struct symbol; 106 + struct thread; 107 107 108 108 /* map__for_each_symbol - iterate over the symbols in the given map 109 109 * ··· 120 118 121 119 void map__init(struct map *map, enum map_type type, 122 120 u64 start, u64 end, u64 pgoff, struct dso *dso); 123 - struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 121 + struct map *map__new(struct machine *machine, u64 start, u64 len, 124 122 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 125 123 u64 ino_gen, u32 prot, u32 flags, 126 - char *filename, enum map_type type); 124 + char *filename, enum map_type type, struct thread *thread); 127 125 struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 128 126 void map__delete(struct map *map); 129 127 struct map *map__clone(struct map *map); ··· 143 141 144 142 void map__reloc_vmlinux(struct map *map); 145 143 146 - size_t __map_groups__fprintf_maps(struct map_groups *mg, 147 - enum map_type type, int verbose, FILE *fp); 144 + size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type, 145 + FILE *fp); 148 146 void maps__insert(struct rb_root *maps, struct map *map); 149 147 void maps__remove(struct rb_root *maps, struct map *map); 150 148 struct map *maps__find(struct rb_root *maps, u64 addr); ··· 154 152 void map_groups__exit(struct map_groups *mg); 155 153 int map_groups__clone(struct map_groups *mg, 156 154 struct map_groups *parent, enum map_type type); 157 - size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp); 158 - size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp); 155 + size_t map_groups__fprintf(struct map_groups *mg, FILE *fp); 159 156 160 157 int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name, 161 158 u64 addr); ··· 211 210 } 212 211 213 212 int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, 214 - int verbose, FILE *fp); 213 + FILE *fp); 215 214 216 215 struct map *map_groups__find_by_name(struct map_groups *mg, 217 216 enum map_type type, const char *name);
+5
tools/perf/util/parse-options.h
··· 98 98 parse_opt_cb *callback; 99 99 intptr_t defval; 100 100 bool *set; 101 + void *data; 101 102 }; 102 103 103 104 #define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v ) ··· 132 131 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\ 133 132 .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\ 134 133 .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG} 134 + #define OPT_CALLBACK_OPTARG(s, l, v, d, a, h, f) \ 135 + { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), \ 136 + .value = (v), (a), .help = (h), .callback = (f), \ 137 + .flags = PARSE_OPT_OPTARG, .data = (d) } 135 138 136 139 /* parse_options() will filter out the processed options and leave the 137 140 * non-option argments in argv[].
-1
tools/perf/util/probe-finder.c
··· 26 26 #include <errno.h> 27 27 #include <stdio.h> 28 28 #include <unistd.h> 29 - #include <getopt.h> 30 29 #include <stdlib.h> 31 30 #include <string.h> 32 31 #include <stdarg.h>
+1
tools/perf/util/pstack.c
··· 6 6 7 7 #include "util.h" 8 8 #include "pstack.h" 9 + #include "debug.h" 9 10 #include <linux/kernel.h> 10 11 #include <stdlib.h> 11 12
+2 -2
tools/perf/util/python.c
··· 14 14 */ 15 15 int verbose; 16 16 17 - int eprintf(int level, const char *fmt, ...) 17 + int eprintf(int level, int var, const char *fmt, ...) 18 18 { 19 19 va_list args; 20 20 int ret = 0; 21 21 22 - if (verbose >= level) { 22 + if (var >= level) { 23 23 va_start(args, fmt); 24 24 ret = vfprintf(stderr, fmt, args); 25 25 va_end(args);
+23 -4
tools/perf/util/record.c
··· 4 4 #include "parse-events.h" 5 5 #include <api/fs/fs.h> 6 6 #include "util.h" 7 + #include "cloexec.h" 7 8 8 9 typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel); 9 10 ··· 12 11 { 13 12 struct perf_evlist *evlist; 14 13 struct perf_evsel *evsel; 14 + unsigned long flags = perf_event_open_cloexec_flag(); 15 15 int err = -EAGAIN, fd; 16 16 17 17 evlist = perf_evlist__new(); ··· 24 22 25 23 evsel = perf_evlist__first(evlist); 26 24 27 - fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 25 + fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags); 28 26 if (fd < 0) 29 27 goto out_delete; 30 28 close(fd); 31 29 32 30 fn(evsel); 33 31 34 - fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 32 + fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags); 35 33 if (fd < 0) { 36 34 if (errno == EINVAL) 37 35 err = -EINVAL; ··· 71 69 evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER; 72 70 } 73 71 72 + static void perf_probe_comm_exec(struct perf_evsel *evsel) 73 + { 74 + evsel->attr.comm_exec = 1; 75 + } 76 + 74 77 bool perf_can_sample_identifier(void) 75 78 { 76 79 return perf_probe_api(perf_probe_sample_identifier); 80 + } 81 + 82 + static bool perf_can_comm_exec(void) 83 + { 84 + return perf_probe_api(perf_probe_comm_exec); 77 85 } 78 86 79 87 void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) 80 88 { 81 89 struct perf_evsel *evsel; 82 90 bool use_sample_identifier = false; 91 + bool use_comm_exec; 83 92 84 93 /* 85 94 * Set the evsel leader links before we configure attributes, ··· 102 89 if (evlist->cpus->map[0] < 0) 103 90 opts->no_inherit = true; 104 91 105 - evlist__for_each(evlist, evsel) 92 + use_comm_exec = perf_can_comm_exec(); 93 + 94 + evlist__for_each(evlist, evsel) { 106 95 perf_evsel__config(evsel, opts); 96 + if (!evsel->idx && use_comm_exec) 97 + evsel->attr.comm_exec = 1; 98 + } 107 99 108 100 if (evlist->nr_entries > 1) { 109 101 struct perf_evsel *first = perf_evlist__first(evlist); ··· 221 203 cpu = evlist->cpus->map[0]; 222 204 } 223 205 224 - fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 206 + fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 207 + perf_event_open_cloexec_flag()); 225 208 if (fd >= 0) { 226 209 close(fd); 227 210 ret = true;
+1
tools/perf/util/scripting-engines/trace-event-perl.c
··· 34 34 #include "../event.h" 35 35 #include "../trace-event.h" 36 36 #include "../evsel.h" 37 + #include "../debug.h" 37 38 38 39 void boot_Perf__Trace__Context(pTHX_ CV *cv); 39 40 void boot_DynaLoader(pTHX_ CV *cv);
+174 -23
tools/perf/util/scripting-engines/trace-event-python.c
··· 27 27 #include <errno.h> 28 28 29 29 #include "../../perf.h" 30 + #include "../debug.h" 30 31 #include "../evsel.h" 31 32 #include "../util.h" 32 33 #include "../event.h" 33 34 #include "../thread.h" 34 35 #include "../trace-event.h" 36 + #include "../machine.h" 35 37 36 38 PyMODINIT_FUNC initperf_trace_context(void); 37 39 ··· 52 50 53 51 static PyObject *main_module, *main_dict; 54 52 53 + static void handler_call_die(const char *handler_name) NORETURN; 55 54 static void handler_call_die(const char *handler_name) 56 55 { 57 56 PyErr_Print(); 58 57 Py_FatalError("problem in Python trace event handler"); 58 + // Py_FatalError does not return 59 + // but we have to make the compiler happy 60 + abort(); 59 61 } 60 62 61 63 /* ··· 103 97 retval = PyObject_CallObject(handler, t); 104 98 if (retval == NULL) 105 99 handler_call_die(handler_name); 100 + Py_DECREF(retval); 106 101 } 107 102 108 103 Py_DECREF(t); ··· 150 143 retval = PyObject_CallObject(handler, t); 151 144 if (retval == NULL) 152 145 handler_call_die(handler_name); 146 + Py_DECREF(retval); 153 147 } 154 148 155 149 Py_DECREF(t); ··· 239 231 return event; 240 232 } 241 233 234 + static PyObject *get_field_numeric_entry(struct event_format *event, 235 + struct format_field *field, void *data) 236 + { 237 + bool is_array = field->flags & FIELD_IS_ARRAY; 238 + PyObject *obj, *list = NULL; 239 + unsigned long long val; 240 + unsigned int item_size, n_items, i; 241 + 242 + if (is_array) { 243 + list = PyList_New(field->arraylen); 244 + item_size = field->size / field->arraylen; 245 + n_items = field->arraylen; 246 + } else { 247 + item_size = field->size; 248 + n_items = 1; 249 + } 250 + 251 + for (i = 0; i < n_items; i++) { 252 + 253 + val = read_size(event, data + field->offset + i * item_size, 254 + item_size); 255 + if (field->flags & FIELD_IS_SIGNED) { 256 + if ((long long)val >= LONG_MIN && 257 + (long long)val <= LONG_MAX) 258 + obj = PyInt_FromLong(val); 259 + else 260 + obj = PyLong_FromLongLong(val); 261 + } else { 262 + if (val <= LONG_MAX) 263 + obj = PyInt_FromLong(val); 264 + else 265 + obj = PyLong_FromUnsignedLongLong(val); 266 + } 267 + if (is_array) 268 + PyList_SET_ITEM(list, i, obj); 269 + } 270 + if (is_array) 271 + obj = list; 272 + return obj; 273 + } 274 + 275 + 276 + static PyObject *python_process_callchain(struct perf_sample *sample, 277 + struct perf_evsel *evsel, 278 + struct addr_location *al) 279 + { 280 + PyObject *pylist; 281 + 282 + pylist = PyList_New(0); 283 + if (!pylist) 284 + Py_FatalError("couldn't create Python list"); 285 + 286 + if (!symbol_conf.use_callchain || !sample->callchain) 287 + goto exit; 288 + 289 + if (machine__resolve_callchain(al->machine, evsel, al->thread, 290 + sample, NULL, NULL, 291 + PERF_MAX_STACK_DEPTH) != 0) { 292 + pr_err("Failed to resolve callchain. Skipping\n"); 293 + goto exit; 294 + } 295 + callchain_cursor_commit(&callchain_cursor); 296 + 297 + 298 + while (1) { 299 + PyObject *pyelem; 300 + struct callchain_cursor_node *node; 301 + node = callchain_cursor_current(&callchain_cursor); 302 + if (!node) 303 + break; 304 + 305 + pyelem = PyDict_New(); 306 + if (!pyelem) 307 + Py_FatalError("couldn't create Python dictionary"); 308 + 309 + 310 + pydict_set_item_string_decref(pyelem, "ip", 311 + PyLong_FromUnsignedLongLong(node->ip)); 312 + 313 + if (node->sym) { 314 + PyObject *pysym = PyDict_New(); 315 + if (!pysym) 316 + Py_FatalError("couldn't create Python dictionary"); 317 + pydict_set_item_string_decref(pysym, "start", 318 + PyLong_FromUnsignedLongLong(node->sym->start)); 319 + pydict_set_item_string_decref(pysym, "end", 320 + PyLong_FromUnsignedLongLong(node->sym->end)); 321 + pydict_set_item_string_decref(pysym, "binding", 322 + PyInt_FromLong(node->sym->binding)); 323 + pydict_set_item_string_decref(pysym, "name", 324 + PyString_FromStringAndSize(node->sym->name, 325 + node->sym->namelen)); 326 + pydict_set_item_string_decref(pyelem, "sym", pysym); 327 + } 328 + 329 + if (node->map) { 330 + struct map *map = node->map; 331 + const char *dsoname = "[unknown]"; 332 + if (map && map->dso && (map->dso->name || map->dso->long_name)) { 333 + if (symbol_conf.show_kernel_path && map->dso->long_name) 334 + dsoname = map->dso->long_name; 335 + else if (map->dso->name) 336 + dsoname = map->dso->name; 337 + } 338 + pydict_set_item_string_decref(pyelem, "dso", 339 + PyString_FromString(dsoname)); 340 + } 341 + 342 + callchain_cursor_advance(&callchain_cursor); 343 + PyList_Append(pylist, pyelem); 344 + Py_DECREF(pyelem); 345 + } 346 + 347 + exit: 348 + return pylist; 349 + } 350 + 351 + 242 352 static void python_process_tracepoint(struct perf_sample *sample, 243 353 struct perf_evsel *evsel, 244 354 struct thread *thread, 245 355 struct addr_location *al) 246 356 { 247 - PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; 357 + PyObject *handler, *retval, *context, *t, *obj, *callchain; 358 + PyObject *dict = NULL; 248 359 static char handler_name[256]; 249 360 struct format_field *field; 250 - unsigned long long val; 251 361 unsigned long s, ns; 252 362 struct event_format *event; 253 363 unsigned n = 0; ··· 406 280 PyTuple_SetItem(t, n++, PyString_FromString(handler_name)); 407 281 PyTuple_SetItem(t, n++, context); 408 282 283 + /* ip unwinding */ 284 + callchain = python_process_callchain(sample, evsel, al); 285 + 409 286 if (handler) { 410 287 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); 411 288 PyTuple_SetItem(t, n++, PyInt_FromLong(s)); 412 289 PyTuple_SetItem(t, n++, PyInt_FromLong(ns)); 413 290 PyTuple_SetItem(t, n++, PyInt_FromLong(pid)); 414 291 PyTuple_SetItem(t, n++, PyString_FromString(comm)); 292 + PyTuple_SetItem(t, n++, callchain); 415 293 } else { 416 294 pydict_set_item_string_decref(dict, "common_cpu", PyInt_FromLong(cpu)); 417 295 pydict_set_item_string_decref(dict, "common_s", PyInt_FromLong(s)); 418 296 pydict_set_item_string_decref(dict, "common_ns", PyInt_FromLong(ns)); 419 297 pydict_set_item_string_decref(dict, "common_pid", PyInt_FromLong(pid)); 420 298 pydict_set_item_string_decref(dict, "common_comm", PyString_FromString(comm)); 299 + pydict_set_item_string_decref(dict, "common_callchain", callchain); 421 300 } 422 301 for (field = event->format.fields; field; field = field->next) { 423 302 if (field->flags & FIELD_IS_STRING) { ··· 434 303 offset = field->offset; 435 304 obj = PyString_FromString((char *)data + offset); 436 305 } else { /* FIELD_IS_NUMERIC */ 437 - val = read_size(event, data + field->offset, 438 - field->size); 439 - if (field->flags & FIELD_IS_SIGNED) { 440 - if ((long long)val >= LONG_MIN && 441 - (long long)val <= LONG_MAX) 442 - obj = PyInt_FromLong(val); 443 - else 444 - obj = PyLong_FromLongLong(val); 445 - } else { 446 - if (val <= LONG_MAX) 447 - obj = PyInt_FromLong(val); 448 - else 449 - obj = PyLong_FromUnsignedLongLong(val); 450 - } 306 + obj = get_field_numeric_entry(event, field, data); 451 307 } 452 308 if (handler) 453 309 PyTuple_SetItem(t, n++, obj); ··· 442 324 pydict_set_item_string_decref(dict, field->name, obj); 443 325 444 326 } 327 + 445 328 if (!handler) 446 329 PyTuple_SetItem(t, n++, dict); 447 330 ··· 453 334 retval = PyObject_CallObject(handler, t); 454 335 if (retval == NULL) 455 336 handler_call_die(handler_name); 337 + Py_DECREF(retval); 456 338 } else { 457 339 handler = PyDict_GetItemString(main_dict, "trace_unhandled"); 458 340 if (handler && PyCallable_Check(handler)) { ··· 461 341 retval = PyObject_CallObject(handler, t); 462 342 if (retval == NULL) 463 343 handler_call_die("trace_unhandled"); 344 + Py_DECREF(retval); 464 345 } 465 346 Py_DECREF(dict); 466 347 } ··· 474 353 struct thread *thread, 475 354 struct addr_location *al) 476 355 { 477 - PyObject *handler, *retval, *t, *dict; 356 + PyObject *handler, *retval, *t, *dict, *callchain, *dict_sample; 478 357 static char handler_name[64]; 479 358 unsigned n = 0; 480 359 ··· 490 369 if (!dict) 491 370 Py_FatalError("couldn't create Python dictionary"); 492 371 372 + dict_sample = PyDict_New(); 373 + if (!dict_sample) 374 + Py_FatalError("couldn't create Python dictionary"); 375 + 493 376 snprintf(handler_name, sizeof(handler_name), "%s", "process_event"); 494 377 495 378 handler = PyDict_GetItemString(main_dict, handler_name); ··· 503 378 pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); 504 379 pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize( 505 380 (const char *)&evsel->attr, sizeof(evsel->attr))); 506 - pydict_set_item_string_decref(dict, "sample", PyString_FromStringAndSize( 507 - (const char *)sample, sizeof(*sample))); 381 + 382 + pydict_set_item_string_decref(dict_sample, "pid", 383 + PyInt_FromLong(sample->pid)); 384 + pydict_set_item_string_decref(dict_sample, "tid", 385 + PyInt_FromLong(sample->tid)); 386 + pydict_set_item_string_decref(dict_sample, "cpu", 387 + PyInt_FromLong(sample->cpu)); 388 + pydict_set_item_string_decref(dict_sample, "ip", 389 + PyLong_FromUnsignedLongLong(sample->ip)); 390 + pydict_set_item_string_decref(dict_sample, "time", 391 + PyLong_FromUnsignedLongLong(sample->time)); 392 + pydict_set_item_string_decref(dict_sample, "period", 393 + PyLong_FromUnsignedLongLong(sample->period)); 394 + pydict_set_item_string_decref(dict, "sample", dict_sample); 395 + 508 396 pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize( 509 397 (const char *)sample->raw_data, sample->raw_size)); 510 398 pydict_set_item_string_decref(dict, "comm", ··· 531 393 PyString_FromString(al->sym->name)); 532 394 } 533 395 396 + /* ip unwinding */ 397 + callchain = python_process_callchain(sample, evsel, al); 398 + pydict_set_item_string_decref(dict, "callchain", callchain); 399 + 534 400 PyTuple_SetItem(t, n++, dict); 535 401 if (_PyTuple_Resize(&t, n) == -1) 536 402 Py_FatalError("error resizing Python tuple"); ··· 542 400 retval = PyObject_CallObject(handler, t); 543 401 if (retval == NULL) 544 402 handler_call_die(handler_name); 403 + Py_DECREF(retval); 545 404 exit: 546 405 Py_DECREF(dict); 547 406 Py_DECREF(t); ··· 664 521 retval = PyObject_CallObject(handler, NULL); 665 522 if (retval == NULL) 666 523 handler_call_die("trace_end"); 667 - else 668 - Py_DECREF(retval); 524 + Py_DECREF(retval); 669 525 out: 670 526 Py_XDECREF(main_dict); 671 527 Py_XDECREF(main_module); ··· 731 589 fprintf(ofp, "common_nsecs, "); 732 590 fprintf(ofp, "common_pid, "); 733 591 fprintf(ofp, "common_comm,\n\t"); 592 + fprintf(ofp, "common_callchain, "); 734 593 735 594 not_first = 0; 736 595 count = 0; ··· 775 632 fprintf(ofp, "%%u"); 776 633 } 777 634 778 - fprintf(ofp, "\\n\" %% \\\n\t\t("); 635 + fprintf(ofp, "\" %% \\\n\t\t("); 779 636 780 637 not_first = 0; 781 638 count = 0; ··· 811 668 fprintf(ofp, "%s", f->name); 812 669 } 813 670 814 - fprintf(ofp, "),\n\n"); 671 + fprintf(ofp, ")\n\n"); 672 + 673 + fprintf(ofp, "\t\tfor node in common_callchain:"); 674 + fprintf(ofp, "\n\t\t\tif 'sym' in node:"); 675 + fprintf(ofp, "\n\t\t\t\tprint \"\\t[%%x] %%s\" %% (node['ip'], node['sym']['name'])"); 676 + fprintf(ofp, "\n\t\t\telse:"); 677 + fprintf(ofp, "\n\t\t\t\tprint \"\t[%%x]\" %% (node['ip'])\n\n"); 678 + fprintf(ofp, "\t\tprint \"\\n\"\n\n"); 679 + 815 680 } 816 681 817 682 fprintf(ofp, "def trace_unhandled(event_name, context, "
+25 -14
tools/perf/util/session.c
··· 14 14 #include "util.h" 15 15 #include "cpumap.h" 16 16 #include "perf_regs.h" 17 - #include "vdso.h" 18 17 19 18 static int perf_session__open(struct perf_session *session) 20 19 { ··· 155 156 if (session->file) 156 157 perf_data_file__close(session->file); 157 158 free(session); 158 - vdso__exit(); 159 159 } 160 160 161 161 static int process_event_synth_tracing_data_stub(struct perf_tool *tool ··· 509 511 os->last_flush = iter->timestamp; 510 512 list_del(&iter->list); 511 513 list_add(&iter->list, &os->sample_cache); 514 + os->nr_samples--; 512 515 513 516 if (show_progress) 514 517 ui_progress__update(&prog, 1); ··· 521 522 os->last_sample = 522 523 list_entry(head->prev, struct sample_queue, list); 523 524 } 524 - 525 - os->nr_samples = 0; 526 525 527 526 return 0; 528 527 } ··· 991 994 } 992 995 } 993 996 994 - static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, 995 - struct perf_tool *tool, u64 file_offset) 997 + static s64 perf_session__process_user_event(struct perf_session *session, 998 + union perf_event *event, 999 + struct perf_tool *tool, 1000 + u64 file_offset) 996 1001 { 997 1002 int fd = perf_data_file__fd(session->file); 998 1003 int err; ··· 1036 1037 swap(event, sample_id_all); 1037 1038 } 1038 1039 1039 - static int perf_session__process_event(struct perf_session *session, 1040 + static s64 perf_session__process_event(struct perf_session *session, 1040 1041 union perf_event *event, 1041 1042 struct perf_tool *tool, 1042 1043 u64 file_offset) ··· 1082 1083 1083 1084 struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) 1084 1085 { 1085 - return machine__findnew_thread(&session->machines.host, 0, pid); 1086 + return machine__findnew_thread(&session->machines.host, -1, pid); 1086 1087 } 1087 1088 1088 1089 static struct thread *perf_session__register_idle_thread(struct perf_session *session) 1089 1090 { 1090 - struct thread *thread = perf_session__findnew(session, 0); 1091 + struct thread *thread; 1091 1092 1093 + thread = machine__findnew_thread(&session->machines.host, 0, 0); 1092 1094 if (thread == NULL || thread__set_comm(thread, "swapper", 0)) { 1093 1095 pr_err("problem inserting idle task.\n"); 1094 1096 thread = NULL; ··· 1147 1147 union perf_event *event; 1148 1148 uint32_t size, cur_size = 0; 1149 1149 void *buf = NULL; 1150 - int skip = 0; 1150 + s64 skip = 0; 1151 1151 u64 head; 1152 1152 ssize_t err; 1153 1153 void *p; ··· 1276 1276 u64 file_size, struct perf_tool *tool) 1277 1277 { 1278 1278 int fd = perf_data_file__fd(session->file); 1279 - u64 head, page_offset, file_offset, file_pos; 1279 + u64 head, page_offset, file_offset, file_pos, size; 1280 1280 int err, mmap_prot, mmap_flags, map_idx = 0; 1281 1281 size_t mmap_size; 1282 1282 char *buf, *mmaps[NUM_MMAPS]; 1283 1283 union perf_event *event; 1284 - uint32_t size; 1285 1284 struct ui_progress prog; 1285 + s64 skip; 1286 1286 1287 1287 perf_tool__fill_defaults(tool); 1288 1288 ··· 1296 1296 ui_progress__init(&prog, file_size, "Processing events..."); 1297 1297 1298 1298 mmap_size = MMAP_SIZE; 1299 - if (mmap_size > file_size) 1299 + if (mmap_size > file_size) { 1300 1300 mmap_size = file_size; 1301 + session->one_mmap = true; 1302 + } 1301 1303 1302 1304 memset(mmaps, 0, sizeof(mmaps)); 1303 1305 ··· 1321 1319 mmaps[map_idx] = buf; 1322 1320 map_idx = (map_idx + 1) & (ARRAY_SIZE(mmaps) - 1); 1323 1321 file_pos = file_offset + head; 1322 + if (session->one_mmap) { 1323 + session->one_mmap_addr = buf; 1324 + session->one_mmap_offset = file_offset; 1325 + } 1324 1326 1325 1327 more: 1326 1328 event = fetch_mmaped_event(session, head, mmap_size, buf); ··· 1343 1337 size = event->header.size; 1344 1338 1345 1339 if (size < sizeof(struct perf_event_header) || 1346 - perf_session__process_event(session, event, tool, file_pos) < 0) { 1340 + (skip = perf_session__process_event(session, event, tool, file_pos)) 1341 + < 0) { 1347 1342 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", 1348 1343 file_offset + head, event->header.size, 1349 1344 event->header.type); 1350 1345 err = -EINVAL; 1351 1346 goto out_err; 1352 1347 } 1348 + 1349 + if (skip) 1350 + size += skip; 1353 1351 1354 1352 head += size; 1355 1353 file_pos += size; ··· 1374 1364 ui_progress__finish(); 1375 1365 perf_session__warn_about_errors(session, tool); 1376 1366 perf_session_free_sample_buffers(session); 1367 + session->one_mmap = false; 1377 1368 return err; 1378 1369 } 1379 1370
+3
tools/perf/util/session.h
··· 36 36 struct trace_event tevent; 37 37 struct events_stats stats; 38 38 bool repipe; 39 + bool one_mmap; 40 + void *one_mmap_addr; 41 + u64 one_mmap_offset; 39 42 struct ordered_samples ordered_samples; 40 43 struct perf_data_file *file; 41 44 };
+1 -1
tools/perf/util/sort.c
··· 1215 1215 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1216 1216 len = hists__col_len(&evsel->hists, hse->se->se_width_idx); 1217 1217 1218 - return scnprintf(hpp->buf, hpp->size, "%*s", len, hse->se->se_header); 1218 + return scnprintf(hpp->buf, hpp->size, "%-*s", len, hse->se->se_header); 1219 1219 } 1220 1220 1221 1221 static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
+130 -38
tools/perf/util/svghelper.c
··· 30 30 31 31 #define SLOT_MULT 30.0 32 32 #define SLOT_HEIGHT 25.0 33 + #define SLOT_HALF (SLOT_HEIGHT / 2) 33 34 34 35 int svg_page_width = 1000; 35 36 u64 svg_highlight; ··· 115 114 fprintf(svgfile, " rect { stroke-width: 1; }\n"); 116 115 fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n"); 117 116 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 117 + fprintf(svgfile, " rect.process3 { fill:rgb(180,180,180); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 118 118 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 119 119 fprintf(svgfile, " rect.sample_hi{ fill:rgb(255,128, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 120 + fprintf(svgfile, " rect.error { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 121 + fprintf(svgfile, " rect.net { fill:rgb( 0,128, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 122 + fprintf(svgfile, " rect.disk { fill:rgb( 0, 0,255); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 123 + fprintf(svgfile, " rect.sync { fill:rgb(128,128, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 124 + fprintf(svgfile, " rect.poll { fill:rgb( 0,128,128); fill-opacity:0.2; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 120 125 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 121 126 fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 122 127 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); ··· 139 132 fprintf(svgfile, " ]]>\n </style>\n</defs>\n"); 140 133 } 141 134 135 + static double normalize_height(double height) 136 + { 137 + if (height < 0.25) 138 + return 0.25; 139 + else if (height < 0.50) 140 + return 0.50; 141 + else if (height < 0.75) 142 + return 0.75; 143 + else 144 + return 0.100; 145 + } 146 + 147 + void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges) 148 + { 149 + double w = time2pixels(end) - time2pixels(start); 150 + height = normalize_height(height); 151 + 152 + if (!svgfile) 153 + return; 154 + 155 + fprintf(svgfile, "<g>\n"); 156 + fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges); 157 + fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n", 158 + time2pixels(start), 159 + w, 160 + Yslot * SLOT_MULT, 161 + SLOT_HALF * height, 162 + type); 163 + fprintf(svgfile, "</g>\n"); 164 + } 165 + 166 + void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges) 167 + { 168 + double w = time2pixels(end) - time2pixels(start); 169 + height = normalize_height(height); 170 + 171 + if (!svgfile) 172 + return; 173 + 174 + fprintf(svgfile, "<g>\n"); 175 + fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges); 176 + fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n", 177 + time2pixels(start), 178 + w, 179 + Yslot * SLOT_MULT + SLOT_HEIGHT - SLOT_HALF * height, 180 + SLOT_HALF * height, 181 + type); 182 + fprintf(svgfile, "</g>\n"); 183 + } 184 + 185 + void svg_fbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges) 186 + { 187 + double w = time2pixels(end) - time2pixels(start); 188 + height = normalize_height(height); 189 + 190 + if (!svgfile) 191 + return; 192 + 193 + fprintf(svgfile, "<g>\n"); 194 + fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges); 195 + fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n", 196 + time2pixels(start), 197 + w, 198 + Yslot * SLOT_MULT + SLOT_HEIGHT - SLOT_HEIGHT * height, 199 + SLOT_HEIGHT * height, 200 + type); 201 + fprintf(svgfile, "</g>\n"); 202 + } 203 + 142 204 void svg_box(int Yslot, u64 start, u64 end, const char *type) 143 205 { 144 206 if (!svgfile) 145 207 return; 146 208 147 - fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", 209 + fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n", 148 210 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type); 149 211 } 150 212 ··· 250 174 cpu, time_to_string(end - start)); 251 175 if (backtrace) 252 176 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace); 253 - fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", 177 + fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n", 254 178 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, 255 179 type); 256 180 ··· 262 186 text_size = round_text_size(text_size); 263 187 264 188 if (text_size > MIN_TEXT_SIZE) 265 - fprintf(svgfile, "<text x=\"%1.8f\" y=\"%1.8f\" font-size=\"%1.8fpt\">%i</text>\n", 189 + fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"%.8fpt\">%i</text>\n", 266 190 time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1); 267 191 268 192 fprintf(svgfile, "</g>\n"); ··· 278 202 return text; 279 203 280 204 if (duration < 1000 * 1000) { /* less than 1 msec */ 281 - sprintf(text, "%4.1f us", duration / 1000.0); 205 + sprintf(text, "%.1f us", duration / 1000.0); 282 206 return text; 283 207 } 284 - sprintf(text, "%4.1f ms", duration / 1000.0 / 1000); 208 + sprintf(text, "%.1f ms", duration / 1000.0 / 1000); 285 209 286 210 return text; 287 211 } ··· 309 233 310 234 font_size = round_text_size(font_size); 311 235 312 - fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT); 236 + fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT); 313 237 fprintf(svgfile, "<title>#%d waiting %s</title>\n", cpu, time_to_string(end - start)); 314 238 if (backtrace) 315 239 fprintf(svgfile, "<desc>Waiting on:\n%s</desc>\n", backtrace); 316 - fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 240 + fprintf(svgfile, "<rect x=\"0\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n", 317 241 time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style); 318 242 if (font_size > MIN_TEXT_SIZE) 319 - fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%1.8fpt\"> %s</text>\n", 243 + fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%.8fpt\"> %s</text>\n", 320 244 font_size, text); 321 245 fprintf(svgfile, "</g>\n"); 322 246 } ··· 365 289 366 290 fprintf(svgfile, "<g>\n"); 367 291 368 - fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"cpu\"/>\n", 292 + fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"cpu\"/>\n", 369 293 time2pixels(first_time), 370 294 time2pixels(last_time)-time2pixels(first_time), 371 295 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); 372 296 373 297 sprintf(cpu_string, "CPU %i", (int)cpu); 374 - fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n", 298 + fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\">%s</text>\n", 375 299 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string); 376 300 377 - fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"1.25pt\">%s</text>\n", 301 + fprintf(svgfile, "<text transform=\"translate(%.8f,%.8f)\" font-size=\"1.25pt\">%s</text>\n", 378 302 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model()); 379 303 380 304 fprintf(svgfile, "</g>\n"); ··· 395 319 else 396 320 type = "sample"; 397 321 398 - fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu)); 322 + fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\">\n", time2pixels(start), cpu2y(cpu)); 399 323 fprintf(svgfile, "<title>%d %s running %s</title>\n", pid, name, time_to_string(end - start)); 400 324 if (backtrace) 401 325 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace); 402 - fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 326 + fprintf(svgfile, "<rect x=\"0\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n", 403 327 time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type); 404 328 width = time2pixels(end)-time2pixels(start); 405 329 if (width > 6) ··· 408 332 width = round_text_size(width); 409 333 410 334 if (width > MIN_TEXT_SIZE) 411 - fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%3.8fpt\">%s</text>\n", 335 + fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%.8fpt\">%s</text>\n", 412 336 width, name); 413 337 414 338 fprintf(svgfile, "</g>\n"); ··· 429 353 type = 6; 430 354 sprintf(style, "c%i", type); 431 355 432 - fprintf(svgfile, "<rect class=\"%s\" x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\"/>\n", 356 + fprintf(svgfile, "<rect class=\"%s\" x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\"/>\n", 433 357 style, 434 358 time2pixels(start), time2pixels(end)-time2pixels(start), 435 359 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); ··· 441 365 width = round_text_size(width); 442 366 443 367 if (width > MIN_TEXT_SIZE) 444 - fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"%3.8fpt\">C%i</text>\n", 368 + fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"%.8fpt\">C%i</text>\n", 445 369 time2pixels(start), cpu2y(cpu)+width, width, type); 446 370 447 371 fprintf(svgfile, "</g>\n"); ··· 483 407 if (max_freq) 484 408 height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT); 485 409 height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height; 486 - fprintf(svgfile, "<line x1=\"%4.8f\" x2=\"%4.8f\" y1=\"%4.1f\" y2=\"%4.1f\" class=\"pstate\"/>\n", 410 + fprintf(svgfile, "<line x1=\"%.8f\" x2=\"%.8f\" y1=\"%.1f\" y2=\"%.1f\" class=\"pstate\"/>\n", 487 411 time2pixels(start), time2pixels(end), height, height); 488 - fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"0.25pt\">%s</text>\n", 412 + fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"0.25pt\">%s</text>\n", 489 413 time2pixels(start), height+0.9, HzToHuman(freq)); 490 414 491 415 fprintf(svgfile, "</g>\n"); ··· 511 435 512 436 if (row1 < row2) { 513 437 if (row1) { 514 - fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 438 + fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 515 439 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); 516 440 if (desc2) 517 - fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n", 441 + fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n", 518 442 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_HEIGHT/48, desc2); 519 443 } 520 444 if (row2) { 521 - fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 445 + fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 522 446 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row2 * SLOT_MULT); 523 447 if (desc1) 524 - fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n", 448 + fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n", 525 449 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, desc1); 526 450 } 527 451 } else { 528 452 if (row2) { 529 - fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 453 + fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 530 454 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); 531 455 if (desc1) 532 - fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n", 456 + fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n", 533 457 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/48, desc1); 534 458 } 535 459 if (row1) { 536 - fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 460 + fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 537 461 time2pixels(start), row1 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row1 * SLOT_MULT); 538 462 if (desc2) 539 - fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n", 463 + fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n", 540 464 time2pixels(start), row1 * SLOT_MULT - SLOT_HEIGHT/32, desc2); 541 465 } 542 466 } ··· 544 468 if (row2 > row1) 545 469 height += SLOT_HEIGHT; 546 470 if (row1) 547 - fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 471 + fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 548 472 time2pixels(start), height); 549 473 550 474 fprintf(svgfile, "</g>\n"); ··· 564 488 fprintf(svgfile, "<desc>%s</desc>\n", backtrace); 565 489 566 490 if (row1 < row2) 567 - fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 491 + fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 568 492 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT); 569 493 else 570 - fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 494 + fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 571 495 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT); 572 496 573 497 height = row1 * SLOT_MULT; 574 498 if (row2 > row1) 575 499 height += SLOT_HEIGHT; 576 - fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 500 + fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 577 501 time2pixels(start), height); 578 502 579 503 fprintf(svgfile, "</g>\n"); ··· 591 515 if (backtrace) 592 516 fprintf(svgfile, "<desc>%s</desc>\n", backtrace); 593 517 594 - fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 518 + fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 595 519 time2pixels(start), row * SLOT_MULT); 596 - fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 520 + fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 597 521 time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT); 598 522 599 523 fprintf(svgfile, "</g>\n"); ··· 604 528 if (!svgfile) 605 529 return; 606 530 607 - fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n", 531 + fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\">%s</text>\n", 608 532 time2pixels(start), Yslot * SLOT_MULT+SLOT_HEIGHT/2, text); 609 533 } 610 534 ··· 613 537 double boxsize; 614 538 boxsize = SLOT_HEIGHT / 2; 615 539 616 - fprintf(svgfile, "<rect x=\"%i\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 540 + fprintf(svgfile, "<rect x=\"%i\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n", 617 541 X, boxsize, boxsize, style); 618 - fprintf(svgfile, "<text transform=\"translate(%4.8f, %4.8f)\" font-size=\"%4.8fpt\">%s</text>\n", 542 + fprintf(svgfile, "<text transform=\"translate(%.8f, %.8f)\" font-size=\"%.8fpt\">%s</text>\n", 619 543 X + boxsize + 5, boxsize, 0.8 * boxsize, text); 544 + } 545 + 546 + void svg_io_legenda(void) 547 + { 548 + if (!svgfile) 549 + return; 550 + 551 + fprintf(svgfile, "<g>\n"); 552 + svg_legenda_box(0, "Disk", "disk"); 553 + svg_legenda_box(100, "Network", "net"); 554 + svg_legenda_box(200, "Sync", "sync"); 555 + svg_legenda_box(300, "Poll", "poll"); 556 + svg_legenda_box(400, "Error", "error"); 557 + fprintf(svgfile, "</g>\n"); 620 558 } 621 559 622 560 void svg_legenda(void) ··· 649 559 fprintf(svgfile, "</g>\n"); 650 560 } 651 561 652 - void svg_time_grid(void) 562 + void svg_time_grid(double min_thickness) 653 563 { 654 564 u64 i; 655 565 ··· 669 579 color = 128; 670 580 } 671 581 672 - fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%" PRIu64 "\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%1.3f\"/>\n", 673 - time2pixels(i), SLOT_MULT/2, time2pixels(i), total_height, color, color, color, thickness); 582 + if (thickness >= min_thickness) 583 + fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%" PRIu64 "\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%.3f\"/>\n", 584 + time2pixels(i), SLOT_MULT/2, time2pixels(i), 585 + total_height, color, color, color, thickness); 674 586 675 587 i += 10000000; 676 588 }
+5 -1
tools/perf/util/svghelper.h
··· 4 4 #include <linux/types.h> 5 5 6 6 extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end); 7 + extern void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges); 8 + extern void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges); 9 + extern void svg_fbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges); 7 10 extern void svg_box(int Yslot, u64 start, u64 end, const char *type); 8 11 extern void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); 9 12 extern void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); ··· 19 16 extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq); 20 17 21 18 22 - extern void svg_time_grid(void); 19 + extern void svg_time_grid(double min_thickness); 20 + extern void svg_io_legenda(void); 23 21 extern void svg_legenda(void); 24 22 extern void svg_wakeline(u64 start, int row1, int row2, const char *backtrace); 25 23 extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace);
+39 -2
tools/perf/util/symbol-elf.c
··· 49 49 50 50 static inline int elf_sym__is_function(const GElf_Sym *sym) 51 51 { 52 - return elf_sym__type(sym) == STT_FUNC && 52 + return (elf_sym__type(sym) == STT_FUNC || 53 + elf_sym__type(sym) == STT_GNU_IFUNC) && 53 54 sym->st_name != 0 && 54 55 sym->st_shndx != SHN_UNDEF; 55 56 } ··· 599 598 goto out_elf_end; 600 599 } 601 600 601 + ss->is_64_bit = (gelf_getclass(elf) == ELFCLASS64); 602 + 602 603 ss->symtab = elf_section_by_name(elf, &ehdr, &ss->symshdr, ".symtab", 603 604 NULL); 604 605 if (ss->symshdr.sh_type != SHT_SYMTAB) ··· 622 619 GElf_Shdr shdr; 623 620 ss->adjust_symbols = (ehdr.e_type == ET_EXEC || 624 621 ehdr.e_type == ET_REL || 625 - is_vdso_map(dso->short_name) || 622 + dso__is_vdso(dso) || 626 623 elf_section_by_name(elf, &ehdr, &shdr, 627 624 ".gnu.prelink_undo", 628 625 NULL) != NULL); ··· 701 698 bool remap_kernel = false, adjust_kernel_syms = false; 702 699 703 700 dso->symtab_type = syms_ss->type; 701 + dso->is_64_bit = syms_ss->is_64_bit; 704 702 dso->rel = syms_ss->ehdr.e_type == ET_REL; 705 703 706 704 /* ··· 1026 1022 1027 1023 elf_end(elf); 1028 1024 return err; 1025 + } 1026 + 1027 + enum dso_type dso__type_fd(int fd) 1028 + { 1029 + enum dso_type dso_type = DSO__TYPE_UNKNOWN; 1030 + GElf_Ehdr ehdr; 1031 + Elf_Kind ek; 1032 + Elf *elf; 1033 + 1034 + elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 1035 + if (elf == NULL) 1036 + goto out; 1037 + 1038 + ek = elf_kind(elf); 1039 + if (ek != ELF_K_ELF) 1040 + goto out_end; 1041 + 1042 + if (gelf_getclass(elf) == ELFCLASS64) { 1043 + dso_type = DSO__TYPE_64BIT; 1044 + goto out_end; 1045 + } 1046 + 1047 + if (gelf_getehdr(elf, &ehdr) == NULL) 1048 + goto out_end; 1049 + 1050 + if (ehdr.e_machine == EM_X86_64) 1051 + dso_type = DSO__TYPE_X32BIT; 1052 + else 1053 + dso_type = DSO__TYPE_32BIT; 1054 + out_end: 1055 + elf_end(elf); 1056 + out: 1057 + return dso_type; 1029 1058 } 1030 1059 1031 1060 static int copy_bytes(int from, off_t from_offs, int to, off_t to_offs, u64 len)
+43
tools/perf/util/symbol-minimal.c
··· 288 288 return 0; 289 289 } 290 290 291 + static int fd__is_64_bit(int fd) 292 + { 293 + u8 e_ident[EI_NIDENT]; 294 + 295 + if (lseek(fd, 0, SEEK_SET)) 296 + return -1; 297 + 298 + if (readn(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident)) 299 + return -1; 300 + 301 + if (memcmp(e_ident, ELFMAG, SELFMAG) || 302 + e_ident[EI_VERSION] != EV_CURRENT) 303 + return -1; 304 + 305 + return e_ident[EI_CLASS] == ELFCLASS64; 306 + } 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 + 291 329 int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, 292 330 struct symsrc *ss, 293 331 struct symsrc *runtime_ss __maybe_unused, ··· 333 295 int kmodule __maybe_unused) 334 296 { 335 297 unsigned char *build_id[BUILD_ID_SIZE]; 298 + int ret; 299 + 300 + ret = fd__is_64_bit(ss->fd); 301 + if (ret >= 0) 302 + dso->is_64_bit = ret; 336 303 337 304 if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) { 338 305 dso__set_build_id(dso, build_id);
+20 -1
tools/perf/util/symbol.c
··· 34 34 .annotate_src = true, 35 35 .demangle = true, 36 36 .cumulate_callchain = true, 37 + .show_hist_headers = true, 37 38 .symfs = "", 38 39 }; 39 40 ··· 342 341 return NULL; 343 342 } 344 343 344 + static struct symbol *symbols__next(struct symbol *sym) 345 + { 346 + struct rb_node *n = rb_next(&sym->rb_node); 347 + 348 + if (n) 349 + return rb_entry(n, struct symbol, rb_node); 350 + 351 + return NULL; 352 + } 353 + 345 354 struct symbol_name_rb_node { 346 355 struct rb_node rb_node; 347 356 struct symbol sym; ··· 422 411 return symbols__find(&dso->symbols[type], addr); 423 412 } 424 413 425 - static struct symbol *dso__first_symbol(struct dso *dso, enum map_type type) 414 + struct symbol *dso__first_symbol(struct dso *dso, enum map_type type) 426 415 { 427 416 return symbols__first(&dso->symbols[type]); 417 + } 418 + 419 + struct symbol *dso__next_symbol(struct symbol *sym) 420 + { 421 + return symbols__next(sym); 428 422 } 429 423 430 424 struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, ··· 1080 1064 &is_64_bit); 1081 1065 if (err) 1082 1066 goto out_err; 1067 + dso->is_64_bit = is_64_bit; 1083 1068 1084 1069 if (list_empty(&md.maps)) { 1085 1070 err = -EINVAL; ··· 1679 1662 free(kallsyms_allocated_filename); 1680 1663 1681 1664 if (err > 0 && !dso__is_kcore(dso)) { 1665 + dso->binary_type = DSO_BINARY_TYPE__KALLSYMS; 1682 1666 dso__set_long_name(dso, "[kernel.kallsyms]", false); 1683 1667 map__fixup_start(map); 1684 1668 map__fixup_end(map); ··· 1727 1709 if (err > 0) 1728 1710 pr_debug("Using %s for symbols\n", kallsyms_filename); 1729 1711 if (err > 0 && !dso__is_kcore(dso)) { 1712 + dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 1730 1713 machine__mmap_name(machine, path, sizeof(path)); 1731 1714 dso__set_long_name(dso, strdup(path), true); 1732 1715 map__fixup_start(map);
+8 -1
tools/perf/util/symbol.h
··· 118 118 annotate_src, 119 119 event_group, 120 120 demangle, 121 - filter_relative; 121 + filter_relative, 122 + show_hist_headers; 122 123 const char *vmlinux_name, 123 124 *kallsyms_name, 124 125 *source_prefix, ··· 216 215 GElf_Shdr dynshdr; 217 216 218 217 bool adjust_symbols; 218 + bool is_64_bit; 219 219 #endif 220 220 }; 221 221 ··· 239 237 u64 addr); 240 238 struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 241 239 const char *name); 240 + 241 + struct symbol *dso__first_symbol(struct dso *dso, enum map_type type); 242 + struct symbol *dso__next_symbol(struct symbol *sym); 243 + 244 + enum dso_type dso__type_fd(int fd); 242 245 243 246 int filename__read_build_id(const char *filename, void *bf, size_t size); 244 247 int sysfs__read_build_id(const char *filename, void *bf, size_t size);
+8 -5
tools/perf/util/thread.c
··· 13 13 struct thread *leader; 14 14 pid_t pid = thread->pid_; 15 15 16 - if (pid == thread->tid) { 16 + if (pid == thread->tid || pid == -1) { 17 17 thread->mg = map_groups__new(); 18 18 } else { 19 19 leader = machine__findnew_thread(machine, pid, pid); ··· 34 34 thread->pid_ = pid; 35 35 thread->tid = tid; 36 36 thread->ppid = -1; 37 + thread->cpu = -1; 37 38 INIT_LIST_HEAD(&thread->comm_list); 38 39 39 40 comm_str = malloc(32); ··· 61 60 { 62 61 struct comm *comm, *tmp; 63 62 64 - map_groups__put(thread->mg); 65 - thread->mg = NULL; 63 + if (thread->mg) { 64 + map_groups__put(thread->mg); 65 + thread->mg = NULL; 66 + } 66 67 list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) { 67 68 list_del(&comm->list); 68 69 comm__free(comm); ··· 130 127 size_t thread__fprintf(struct thread *thread, FILE *fp) 131 128 { 132 129 return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) + 133 - map_groups__fprintf(thread->mg, verbose, fp); 130 + map_groups__fprintf(thread->mg, fp); 134 131 } 135 132 136 133 void thread__insert_map(struct thread *thread, struct map *map) 137 134 { 138 - map_groups__fixup_overlappings(thread->mg, map, verbose, stderr); 135 + map_groups__fixup_overlappings(thread->mg, map, stderr); 139 136 map_groups__insert(thread->mg, map); 140 137 } 141 138
+1
tools/perf/util/thread.h
··· 17 17 pid_t pid_; /* Not all tools update this */ 18 18 pid_t tid; 19 19 pid_t ppid; 20 + int cpu; 20 21 char shortname[3]; 21 22 bool comm_set; 22 23 bool dead; /* if set thread has exited */
+4 -9
tools/perf/util/trace-event-info.c
··· 40 40 #include "trace-event.h" 41 41 #include <api/fs/debugfs.h> 42 42 #include "evsel.h" 43 + #include "debug.h" 43 44 44 45 #define VERSION "0.5" 45 46 ··· 192 191 strcmp(dent->d_name, "..") == 0 || 193 192 !name_in_tp_list(dent->d_name, tps)) 194 193 continue; 195 - format = malloc(strlen(sys) + strlen(dent->d_name) + 10); 196 - if (!format) { 194 + if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) { 197 195 err = -ENOMEM; 198 196 goto out; 199 197 } 200 - sprintf(format, "%s/%s/format", sys, dent->d_name); 201 198 ret = stat(format, &st); 202 199 free(format); 203 200 if (ret < 0) ··· 216 217 strcmp(dent->d_name, "..") == 0 || 217 218 !name_in_tp_list(dent->d_name, tps)) 218 219 continue; 219 - format = malloc(strlen(sys) + strlen(dent->d_name) + 10); 220 - if (!format) { 220 + if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) { 221 221 err = -ENOMEM; 222 222 goto out; 223 223 } 224 - sprintf(format, "%s/%s/format", sys, dent->d_name); 225 224 ret = stat(format, &st); 226 225 227 226 if (ret >= 0) { ··· 314 317 strcmp(dent->d_name, "ftrace") == 0 || 315 318 !system_in_tp_list(dent->d_name, tps)) 316 319 continue; 317 - sys = malloc(strlen(path) + strlen(dent->d_name) + 2); 318 - if (!sys) { 320 + if (asprintf(&sys, "%s/%s", path, dent->d_name) < 0) { 319 321 err = -ENOMEM; 320 322 goto out; 321 323 } 322 - sprintf(sys, "%s/%s", path, dent->d_name); 323 324 ret = stat(sys, &st); 324 325 if (ret >= 0) { 325 326 ssize_t size = strlen(dent->d_name) + 1;
+1 -1
tools/perf/util/trace-event-read.c
··· 22 22 #include <stdio.h> 23 23 #include <stdlib.h> 24 24 #include <string.h> 25 - #include <getopt.h> 26 25 #include <stdarg.h> 27 26 #include <sys/types.h> 28 27 #include <sys/stat.h> ··· 35 36 #include "../perf.h" 36 37 #include "util.h" 37 38 #include "trace-event.h" 39 + #include "debug.h" 38 40 39 41 static int input_fd; 40 42
+30
tools/perf/util/tsc.c
··· 1 + #include <linux/compiler.h> 2 + #include <linux/types.h> 3 + 4 + #include "tsc.h" 5 + 6 + u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc) 7 + { 8 + u64 t, quot, rem; 9 + 10 + t = ns - tc->time_zero; 11 + quot = t / tc->time_mult; 12 + rem = t % tc->time_mult; 13 + return (quot << tc->time_shift) + 14 + (rem << tc->time_shift) / tc->time_mult; 15 + } 16 + 17 + u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc) 18 + { 19 + u64 quot, rem; 20 + 21 + quot = cyc >> tc->time_shift; 22 + rem = cyc & ((1 << tc->time_shift) - 1); 23 + return tc->time_zero + quot * tc->time_mult + 24 + ((rem * tc->time_mult) >> tc->time_shift); 25 + } 26 + 27 + u64 __weak rdtsc(void) 28 + { 29 + return 0; 30 + }
+12
tools/perf/util/tsc.h
··· 1 + #ifndef __PERF_TSC_H 2 + #define __PERF_TSC_H 3 + 4 + #include <linux/types.h> 5 + 6 + #include "../arch/x86/util/tsc.h" 7 + 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); 10 + u64 rdtsc(void); 11 + 12 + #endif
+1
tools/perf/util/unwind-libdw.c
··· 3 3 #include <elfutils/libdwfl.h> 4 4 #include <inttypes.h> 5 5 #include <errno.h> 6 + #include "debug.h" 6 7 #include "unwind.h" 7 8 #include "unwind-libdw.h" 8 9 #include "machine.h"
+1
tools/perf/util/unwind-libunwind.c
··· 30 30 #include "unwind.h" 31 31 #include "symbol.h" 32 32 #include "util.h" 33 + #include "debug.h" 33 34 34 35 extern int 35 36 UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
+3 -7
tools/perf/util/util.c
··· 1 1 #include "../perf.h" 2 2 #include "util.h" 3 + #include "debug.h" 3 4 #include <api/fs/fs.h> 4 5 #include <sys/mman.h> 5 6 #ifdef HAVE_BACKTRACE_SUPPORT ··· 334 333 if (!debugfs) 335 334 return NULL; 336 335 337 - tracing = malloc(strlen(debugfs) + 9); 338 - if (!tracing) 336 + if (asprintf(&tracing, "%s/tracing", debugfs) < 0) 339 337 return NULL; 340 - 341 - sprintf(tracing, "%s/tracing", debugfs); 342 338 343 339 tracing_found = 1; 344 340 return tracing; ··· 350 352 if (!tracing) 351 353 return NULL; 352 354 353 - file = malloc(strlen(tracing) + strlen(name) + 2); 354 - if (!file) 355 + if (asprintf(&file, "%s/%s", tracing, name) < 0) 355 356 return NULL; 356 357 357 - sprintf(file, "%s/%s", tracing, name); 358 358 return file; 359 359 } 360 360
+83 -26
tools/perf/util/vdso.c
··· 11 11 #include "vdso.h" 12 12 #include "util.h" 13 13 #include "symbol.h" 14 + #include "machine.h" 14 15 #include "linux/string.h" 16 + #include "debug.h" 15 17 16 - static bool vdso_found; 17 - static char vdso_file[] = "/tmp/perf-vdso.so-XXXXXX"; 18 + #define VDSO__TEMP_FILE_NAME "/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 + } 18 42 19 43 static int find_vdso_map(void **start, void **end) 20 44 { ··· 71 47 return !found; 72 48 } 73 49 74 - static char *get_file(void) 50 + static char *get_file(struct vdso_file *vdso_file) 75 51 { 76 52 char *vdso = NULL; 77 53 char *buf = NULL; ··· 79 55 size_t size; 80 56 int fd; 81 57 82 - if (vdso_found) 83 - return vdso_file; 58 + if (vdso_file->found) 59 + return vdso_file->temp_file_name; 84 60 85 - if (find_vdso_map(&start, &end)) 61 + if (vdso_file->error || find_vdso_map(&start, &end)) 86 62 return NULL; 87 63 88 64 size = end - start; ··· 91 67 if (!buf) 92 68 return NULL; 93 69 94 - fd = mkstemp(vdso_file); 70 + fd = mkstemp(vdso_file->temp_file_name); 95 71 if (fd < 0) 96 72 goto out; 97 73 98 74 if (size == (size_t) write(fd, buf, size)) 99 - vdso = vdso_file; 75 + vdso = vdso_file->temp_file_name; 100 76 101 77 close(fd); 102 78 103 79 out: 104 80 free(buf); 105 81 106 - vdso_found = (vdso != NULL); 82 + vdso_file->found = (vdso != NULL); 83 + vdso_file->error = !vdso_file->found; 107 84 return vdso; 108 85 } 109 86 110 - void vdso__exit(void) 87 + void vdso__exit(struct machine *machine) 111 88 { 112 - if (vdso_found) 113 - unlink(vdso_file); 89 + struct vdso_info *vdso_info = machine->vdso_info; 90 + 91 + if (!vdso_info) 92 + return; 93 + 94 + if (vdso_info->vdso.found) 95 + unlink(vdso_info->vdso.temp_file_name); 96 + 97 + zfree(&machine->vdso_info); 114 98 } 115 99 116 - struct dso *vdso__dso_findnew(struct list_head *head) 100 + static struct dso *vdso__new(struct machine *machine, const char *short_name, 101 + const char *long_name) 117 102 { 118 - struct dso *dso = dsos__find(head, VDSO__MAP_NAME, true); 103 + struct dso *dso; 119 104 120 - if (!dso) { 121 - char *file; 122 - 123 - file = get_file(); 124 - if (!file) 125 - return NULL; 126 - 127 - dso = dso__new(VDSO__MAP_NAME); 128 - if (dso != NULL) { 129 - dsos__add(head, dso); 130 - dso__set_long_name(dso, file, false); 131 - } 105 + dso = dso__new(short_name); 106 + if (dso != NULL) { 107 + dsos__add(&machine->user_dsos, dso); 108 + dso__set_long_name(dso, long_name, false); 132 109 } 133 110 134 111 return dso; 112 + } 113 + 114 + struct dso *vdso__dso_findnew(struct machine *machine, 115 + struct thread *thread __maybe_unused) 116 + { 117 + struct vdso_info *vdso_info; 118 + struct dso *dso; 119 + 120 + if (!machine->vdso_info) 121 + machine->vdso_info = vdso_info__new(); 122 + 123 + vdso_info = machine->vdso_info; 124 + if (!vdso_info) 125 + return NULL; 126 + 127 + dso = dsos__find(&machine->user_dsos, DSO__NAME_VDSO, true); 128 + if (!dso) { 129 + char *file; 130 + 131 + file = get_file(&vdso_info->vdso); 132 + if (!file) 133 + return NULL; 134 + 135 + dso = vdso__new(machine, DSO__NAME_VDSO, file); 136 + } 137 + 138 + return dso; 139 + } 140 + 141 + bool dso__is_vdso(struct dso *dso) 142 + { 143 + return !strcmp(dso->short_name, DSO__NAME_VDSO); 135 144 }
+11 -2
tools/perf/util/vdso.h
··· 7 7 8 8 #define VDSO__MAP_NAME "[vdso]" 9 9 10 + #define DSO__NAME_VDSO "[vdso]" 11 + 10 12 static inline bool is_vdso_map(const char *filename) 11 13 { 12 14 return !strcmp(filename, VDSO__MAP_NAME); 13 15 } 14 16 15 - struct dso *vdso__dso_findnew(struct list_head *head); 16 - void vdso__exit(void); 17 + struct dso; 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 27 #endif /* __PERF_VDSO__ */