Pull perf updates from Ingo Molnar: "Kernel improvements: - watchdog driver improvements by Li Zefan - Power7 CPI stack events related improvements by Sukadev Bhattiprolu - event multiplexing via hrtimers and other improvements by Stephane Eranian - kernel stack use optimization by Andrew Hunter - AMD IOMMU uncore PMU support by Suravee Suthikulpanit - NMI handling rate-limits by Dave Hansen - various hw_breakpoint fixes by Oleg Nesterov - hw_breakpoint overflow period sampling and related signal handling fixes by Jiri Olsa - Intel Haswell PMU support by Andi Kleen Tooling improvements: - Reset SIGTERM handler in workload child process, fix from David Ahern. - Makefile reorganization, prep work for Kconfig patches, from Jiri Olsa. - Add automated make test suite, from Jiri Olsa. - Add --percent-limit option to 'top' and 'report', from Namhyung Kim. - Sorting improvements, from Namhyung Kim. - Expand definition of sysfs format attribute, from Michael Ellerman. Tooling fixes: - 'perf tests' fixes from Jiri Olsa. - Make Power7 CPI stack events available in sysfs, from Sukadev Bhattiprolu. - Handle death by SIGTERM in 'perf record', fix from David Ahern. - Fix printing of perf_event_paranoid message, from David Ahern. - Handle realloc failures in 'perf kvm', from David Ahern. - Fix divide by 0 in variance, from David Ahern. - Save parent pid in thread struct, from David Ahern. - Handle JITed code in shared memory, from Andi Kleen. - Fixes for 'perf diff', from Jiri Olsa. - Remove some unused struct members, from Jiri Olsa. - Add missing liblk.a dependency for python/perf.so, fix from Jiri Olsa. - Respect CROSS_COMPILE in liblk.a, from Rabin Vincent. - No need to do locking when adding hists in perf report, only 'top' needs that, from Namhyung Kim. - Fix alignment of symbol column in in the hists browser (top, report) when -v is given, from NAmhyung Kim. - Fix 'perf top' -E option behavior, from Namhyung Kim. - Fix bug in isupper() and islower(), from Sukadev Bhattiprolu. - Fix compile errors in bp_signal 'perf test', from Sukadev Bhattiprolu. ... and more things" * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (102 commits) perf/x86: Disable PEBS-LL in intel_pmu_pebs_disable() perf/x86: Fix shared register mutual exclusion enforcement perf/x86/intel: Support full width counting x86: Add NMI duration tracepoints perf: Drop sample rate when sampling is too slow x86: Warn when NMI handlers take large amounts of time hw_breakpoint: Introduce "struct bp_cpuinfo" hw_breakpoint: Simplify *register_wide_hw_breakpoint() hw_breakpoint: Introduce cpumask_of_bp() hw_breakpoint: Simplify the "weight" usage in toggle_bp_slot() paths hw_breakpoint: Simplify list/idx mess in toggle_bp_slot() paths perf/x86/intel: Add mem-loads/stores support for Haswell perf/x86/intel: Support Haswell/v4 LBR format perf/x86/intel: Move NMI clearing to end of PMI handler perf/x86/intel: Add Haswell PEBS support perf/x86/intel: Add simple Haswell PMU support perf/x86/intel: Add Haswell PEBS record support perf/x86/intel: Fix sparse warning perf/x86/amd: AMD IOMMU Performance Counter PERF uncore PMU implementation perf/x86/amd: Add IOMMU Performance Counter resource management ...
Unified · Split
| @@ -27,14 +27,36 @@ Description: Generic performance monitoring events · 26 unmodified lines | ||
| 27 | 27 | "basename". |
| 28 | 28 | |
| 29 | 29 | |
| 30 | −What: /sys/devices/cpu/events/PM_LD_MISS_L1 | |
| 31 | − /sys/devices/cpu/events/PM_LD_REF_L1 | |
| 32 | − /sys/devices/cpu/events/PM_CYC | |
| 30 | +What: /sys/devices/cpu/events/PM_1PLUS_PPC_CMPL | |
| 33 | 31 | /sys/devices/cpu/events/PM_BRU_FIN |
| 34 | − /sys/devices/cpu/events/PM_GCT_NOSLOT_CYC | |
| 35 | 32 | /sys/devices/cpu/events/PM_BRU_MPRED |
| 36 | − /sys/devices/cpu/events/PM_INST_CMPL | |
| 37 | 33 | /sys/devices/cpu/events/PM_CMPLU_STALL |
| 34 | + /sys/devices/cpu/events/PM_CMPLU_STALL_BRU | |
| 35 | + /sys/devices/cpu/events/PM_CMPLU_STALL_DCACHE_MISS | |
| 36 | + /sys/devices/cpu/events/PM_CMPLU_STALL_DFU | |
| 37 | + /sys/devices/cpu/events/PM_CMPLU_STALL_DIV | |
| 38 | + /sys/devices/cpu/events/PM_CMPLU_STALL_ERAT_MISS | |
| 39 | + /sys/devices/cpu/events/PM_CMPLU_STALL_FXU | |
| 40 | + /sys/devices/cpu/events/PM_CMPLU_STALL_IFU | |
| 41 | + /sys/devices/cpu/events/PM_CMPLU_STALL_LSU | |
| 42 | + /sys/devices/cpu/events/PM_CMPLU_STALL_REJECT | |
| 43 | + /sys/devices/cpu/events/PM_CMPLU_STALL_SCALAR | |
| 44 | + /sys/devices/cpu/events/PM_CMPLU_STALL_SCALAR_LONG | |
| 45 | + /sys/devices/cpu/events/PM_CMPLU_STALL_STORE | |
| 46 | + /sys/devices/cpu/events/PM_CMPLU_STALL_THRD | |
| 47 | + /sys/devices/cpu/events/PM_CMPLU_STALL_VECTOR | |
| 48 | + /sys/devices/cpu/events/PM_CMPLU_STALL_VECTOR_LONG | |
| 49 | + /sys/devices/cpu/events/PM_CYC | |
| 50 | + /sys/devices/cpu/events/PM_GCT_NOSLOT_BR_MPRED | |
| 51 | + /sys/devices/cpu/events/PM_GCT_NOSLOT_BR_MPRED_IC_MISS | |
| 52 | + /sys/devices/cpu/events/PM_GCT_NOSLOT_CYC | |
| 53 | + /sys/devices/cpu/events/PM_GCT_NOSLOT_IC_MISS | |
| 54 | + /sys/devices/cpu/events/PM_GRP_CMPL | |
| 55 | + /sys/devices/cpu/events/PM_INST_CMPL | |
| 56 | + /sys/devices/cpu/events/PM_LD_MISS_L1 | |
| 57 | + /sys/devices/cpu/events/PM_LD_REF_L1 | |
| 58 | + /sys/devices/cpu/events/PM_RUN_CYC | |
| 59 | + /sys/devices/cpu/events/PM_RUN_INST_CMPL | |
| 38 | 60 | |
| 39 | 61 | Date: 2013/01/08 |
| 40 | 62 | |
| @@ -9,6 +9,12 @@ Description: · 8 unmodified lines | ||
| 9 | 9 | we want to export, so that userspace can deal with sane |
| 10 | 10 | name/value pairs. |
| 11 | 11 | |
| 12 | + Userspace must be prepared for the possibility that attributes | |
| 13 | + define overlapping bit ranges. For example: | |
| 14 | + attr1 = 'config:0-23' | |
| 15 | + attr2 = 'config:0-7' | |
| 16 | + attr3 = 'config:12-35' | |
| 17 | + | |
| 12 | 18 | Example: 'config1:1,6-10,44' |
| 13 | 19 | Defines contents of attribute that occupies bits 1,6-10,44 of |
| 14 | 20 | perf_event_attr::config1. |
| @@ -70,12 +70,12 @@ show up in /proc/sys/kernel: · 69 unmodified lines | ||
| 70 | 70 | - shmall |
| 71 | 71 | - shmmax [ sysv ipc ] |
| 72 | 72 | - shmmni |
| 73 | −- softlockup_thresh | |
| 74 | 73 | - stop-a [ SPARC only ] |
| 75 | 74 | - sysrq ==> Documentation/sysrq.txt |
| 76 | 75 | - tainted |
| 77 | 76 | - threads-max |
| 78 | 77 | - unknown_nmi_panic |
| 78 | +- watchdog_thresh | |
| 79 | 79 | - version |
| 80 | 80 | |
| 81 | 81 | ============================================================== |
| @@ -427,6 +427,32 @@ This file shows up if CONFIG_DEBUG_STACKOVERFLOW is enabled. · 345 unmodified lines | ||
| 427 | 427 | |
| 428 | 428 | ============================================================== |
| 429 | 429 | |
| 430 | +perf_cpu_time_max_percent: | |
| 431 | + | |
| 432 | +Hints to the kernel how much CPU time it should be allowed to | |
| 433 | +use to handle perf sampling events. If the perf subsystem | |
| 434 | +is informed that its samples are exceeding this limit, it | |
| 435 | +will drop its sampling frequency to attempt to reduce its CPU | |
| 436 | +usage. | |
| 437 | + | |
| 438 | +Some perf sampling happens in NMIs. If these samples | |
| 439 | +unexpectedly take too long to execute, the NMIs can become | |
| 440 | +stacked up next to each other so much that nothing else is | |
| 441 | +allowed to execute. | |
| 442 | + | |
| 443 | +0: disable the mechanism. Do not monitor or correct perf's | |
| 444 | + sampling rate no matter how CPU time it takes. | |
| 445 | + | |
| 446 | +1-100: attempt to throttle perf's sample rate to this | |
| 447 | + percentage of CPU. Note: the kernel calculates an | |
| 448 | + "expected" length of each sample event. 100 here means | |
| 449 | + 100% of that expected length. Even if this is set to | |
| 450 | + 100, you may still see sample throttling if this | |
| 451 | + length is exceeded. Set to 0 if you truly do not care | |
| 452 | + how much CPU is consumed. | |
| 453 | + | |
| 454 | +============================================================== | |
| 455 | + | |
| 430 | 456 | |
| 431 | 457 | pid_max: |
| 432 | 458 | |
| @@ -604,15 +630,6 @@ without users and with a dead originative process will be destroyed. · 171 unmodified lines | ||
| 604 | 630 | |
| 605 | 631 | ============================================================== |
| 606 | 632 | |
| 607 | −softlockup_thresh: | |
| 608 | − | |
| 609 | −This value can be used to lower the softlockup tolerance threshold. The | |
| 610 | −default threshold is 60 seconds. If a cpu is locked up for 60 seconds, | |
| 611 | −the kernel complains. Valid values are 1-60 seconds. Setting this | |
| 612 | −tunable to zero will disable the softlockup detection altogether. | |
| 613 | − | |
| 614 | −============================================================== | |
| 615 | − | |
| 616 | 633 | tainted: |
| 617 | 634 | |
| 618 | 635 | Non-zero if the kernel has been tainted. Numeric values, which |
| @@ -648,3 +665,16 @@ that time, kernel debugging information is displayed on console. · 29 unmodified lines | ||
| 648 | 665 | |
| 649 | 666 | NMI switch that most IA32 servers have fires unknown NMI up, for |
| 650 | 667 | example. If a system hangs up, try pressing the NMI switch. |
| 668 | + | |
| 669 | +============================================================== | |
| 670 | + | |
| 671 | +watchdog_thresh: | |
| 672 | + | |
| 673 | +This value can be used to control the frequency of hrtimer and NMI | |
| 674 | +events and the soft and hard lockup thresholds. The default threshold | |
| 675 | +is 10 seconds. | |
| 676 | + | |
| 677 | +The softlockup threshold is (2 * watchdog_thresh). Setting this | |
| 678 | +tunable to zero will disable lockup detection altogether. | |
| 679 | + | |
| 680 | +============================================================== | |
| @@ -0,0 +1,43 @@ | ||
| 1 | +NMI Trace Events | |
| 2 | + | |
| 3 | +These events normally show up here: | |
| 4 | + | |
| 5 | + /sys/kernel/debug/tracing/events/nmi | |
| 6 | + | |
| 7 | +-- | |
| 8 | + | |
| 9 | +nmi_handler: | |
| 10 | + | |
| 11 | +You might want to use this tracepoint if you suspect that your | |
| 12 | +NMI handlers are hogging large amounts of CPU time. The kernel | |
| 13 | +will warn if it sees long-running handlers: | |
| 14 | + | |
| 15 | + INFO: NMI handler took too long to run: 9.207 msecs | |
| 16 | + | |
| 17 | +and this tracepoint will allow you to drill down and get some | |
| 18 | +more details. | |
| 19 | + | |
| 20 | +Let's say you suspect that perf_event_nmi_handler() is causing | |
| 21 | +you some problems and you only want to trace that handler | |
| 22 | +specifically. You need to find its address: | |
| 23 | + | |
| 24 | + $ grep perf_event_nmi_handler /proc/kallsyms | |
| 25 | + ffffffff81625600 t perf_event_nmi_handler | |
| 26 | + | |
| 27 | +Let's also say you are only interested in when that function is | |
| 28 | +really hogging a lot of CPU time, like a millisecond at a time. | |
| 29 | +Note that the kernel's output is in milliseconds, but the input | |
| 30 | +to the filter is in nanoseconds! You can filter on 'delta_ns': | |
| 31 | + | |
| 32 | +cd /sys/kernel/debug/tracing/events/nmi/nmi_handler | |
| 33 | +echo 'handler==0xffffffff81625600 && delta_ns>1000000' > filter | |
| 34 | +echo 1 > enable | |
| 35 | + | |
| 36 | +Your output would then look like: | |
| 37 | + | |
| 38 | +$ cat /sys/kernel/debug/tracing/trace_pipe | |
| 39 | +<idle>-0 [000] d.h3 505.397558: nmi_handler: perf_event_nmi_handler() delta_ns: 3236765 handled: 1 | |
| 40 | +<idle>-0 [000] d.h3 505.805893: nmi_handler: perf_event_nmi_handler() delta_ns: 3174234 handled: 1 | |
| 41 | +<idle>-0 [000] d.h3 506.158206: nmi_handler: perf_event_nmi_handler() delta_ns: 3084642 handled: 1 | |
| 42 | +<idle>-0 [000] d.h3 506.334346: nmi_handler: perf_event_nmi_handler() delta_ns: 3080351 handled: 1 | |
| 43 | + | |
| @@ -882,7 +882,7 @@ static int __init init_hw_perf_events(void) · 881 unmodified lines | ||
| 882 | 882 | } |
| 883 | 883 | |
| 884 | 884 | register_cpu_notifier(&metag_pmu_notifier); |
| 885 | − ret = perf_pmu_register(&pmu, (char *)metag_pmu->name, PERF_TYPE_RAW); | |
| 885 | + ret = perf_pmu_register(&pmu, metag_pmu->name, PERF_TYPE_RAW); | |
| 886 | 886 | out: |
| 887 | 887 | return ret; |
| 888 | 888 | } |
| @@ -62,6 +62,29 @@ · 61 unmodified lines | ||
| 62 | 62 | #define PME_PM_BRU_FIN 0x10068 |
| 63 | 63 | #define PME_PM_BRU_MPRED 0x400f6 |
| 64 | 64 | |
| 65 | +#define PME_PM_CMPLU_STALL_FXU 0x20014 | |
| 66 | +#define PME_PM_CMPLU_STALL_DIV 0x40014 | |
| 67 | +#define PME_PM_CMPLU_STALL_SCALAR 0x40012 | |
| 68 | +#define PME_PM_CMPLU_STALL_SCALAR_LONG 0x20018 | |
| 69 | +#define PME_PM_CMPLU_STALL_VECTOR 0x2001c | |
| 70 | +#define PME_PM_CMPLU_STALL_VECTOR_LONG 0x4004a | |
| 71 | +#define PME_PM_CMPLU_STALL_LSU 0x20012 | |
| 72 | +#define PME_PM_CMPLU_STALL_REJECT 0x40016 | |
| 73 | +#define PME_PM_CMPLU_STALL_ERAT_MISS 0x40018 | |
| 74 | +#define PME_PM_CMPLU_STALL_DCACHE_MISS 0x20016 | |
| 75 | +#define PME_PM_CMPLU_STALL_STORE 0x2004a | |
| 76 | +#define PME_PM_CMPLU_STALL_THRD 0x1001c | |
| 77 | +#define PME_PM_CMPLU_STALL_IFU 0x4004c | |
| 78 | +#define PME_PM_CMPLU_STALL_BRU 0x4004e | |
| 79 | +#define PME_PM_GCT_NOSLOT_IC_MISS 0x2001a | |
| 80 | +#define PME_PM_GCT_NOSLOT_BR_MPRED 0x4001a | |
| 81 | +#define PME_PM_GCT_NOSLOT_BR_MPRED_IC_MISS 0x4001c | |
| 82 | +#define PME_PM_GRP_CMPL 0x30004 | |
| 83 | +#define PME_PM_1PLUS_PPC_CMPL 0x100f2 | |
| 84 | +#define PME_PM_CMPLU_STALL_DFU 0x2003c | |
| 85 | +#define PME_PM_RUN_CYC 0x200f4 | |
| 86 | +#define PME_PM_RUN_INST_CMPL 0x400fa | |
| 87 | + | |
| 65 | 88 | /* |
| 66 | 89 | * Layout of constraint bits: |
| 67 | 90 | * 6666555555555544444444443333333333222222222211111111110000000000 |
| @@ -393,6 +416,31 @@ POWER_EVENT_ATTR(LD_MISS_L1, LD_MISS_L1); · 325 unmodified lines | ||
| 393 | 416 | POWER_EVENT_ATTR(BRU_FIN, BRU_FIN) |
| 394 | 417 | POWER_EVENT_ATTR(BRU_MPRED, BRU_MPRED); |
| 395 | 418 | |
| 419 | +POWER_EVENT_ATTR(CMPLU_STALL_FXU, CMPLU_STALL_FXU); | |
| 420 | +POWER_EVENT_ATTR(CMPLU_STALL_DIV, CMPLU_STALL_DIV); | |
| 421 | +POWER_EVENT_ATTR(CMPLU_STALL_SCALAR, CMPLU_STALL_SCALAR); | |
| 422 | +POWER_EVENT_ATTR(CMPLU_STALL_SCALAR_LONG, CMPLU_STALL_SCALAR_LONG); | |
| 423 | +POWER_EVENT_ATTR(CMPLU_STALL_VECTOR, CMPLU_STALL_VECTOR); | |
| 424 | +POWER_EVENT_ATTR(CMPLU_STALL_VECTOR_LONG, CMPLU_STALL_VECTOR_LONG); | |
| 425 | +POWER_EVENT_ATTR(CMPLU_STALL_LSU, CMPLU_STALL_LSU); | |
| 426 | +POWER_EVENT_ATTR(CMPLU_STALL_REJECT, CMPLU_STALL_REJECT); | |
| 427 | + | |
| 428 | +POWER_EVENT_ATTR(CMPLU_STALL_ERAT_MISS, CMPLU_STALL_ERAT_MISS); | |
| 429 | +POWER_EVENT_ATTR(CMPLU_STALL_DCACHE_MISS, CMPLU_STALL_DCACHE_MISS); | |
| 430 | +POWER_EVENT_ATTR(CMPLU_STALL_STORE, CMPLU_STALL_STORE); | |
| 431 | +POWER_EVENT_ATTR(CMPLU_STALL_THRD, CMPLU_STALL_THRD); | |
| 432 | +POWER_EVENT_ATTR(CMPLU_STALL_IFU, CMPLU_STALL_IFU); | |
| 433 | +POWER_EVENT_ATTR(CMPLU_STALL_BRU, CMPLU_STALL_BRU); | |
| 434 | +POWER_EVENT_ATTR(GCT_NOSLOT_IC_MISS, GCT_NOSLOT_IC_MISS); | |
| 435 | + | |
| 436 | +POWER_EVENT_ATTR(GCT_NOSLOT_BR_MPRED, GCT_NOSLOT_BR_MPRED); | |
| 437 | +POWER_EVENT_ATTR(GCT_NOSLOT_BR_MPRED_IC_MISS, GCT_NOSLOT_BR_MPRED_IC_MISS); | |
| 438 | +POWER_EVENT_ATTR(GRP_CMPL, GRP_CMPL); | |
| 439 | +POWER_EVENT_ATTR(1PLUS_PPC_CMPL, 1PLUS_PPC_CMPL); | |
| 440 | +POWER_EVENT_ATTR(CMPLU_STALL_DFU, CMPLU_STALL_DFU); | |
| 441 | +POWER_EVENT_ATTR(RUN_CYC, RUN_CYC); | |
| 442 | +POWER_EVENT_ATTR(RUN_INST_CMPL, RUN_INST_CMPL); | |
| 443 | + | |
| 396 | 444 | static struct attribute *power7_events_attr[] = { |
| 397 | 445 | GENERIC_EVENT_PTR(CYC), |
| 398 | 446 | GENERIC_EVENT_PTR(GCT_NOSLOT_CYC), |
| @@ -411,6 +459,31 @@ static struct attribute *power7_events_attr[] = { · 12 unmodified lines | ||
| 411 | 459 | POWER_EVENT_PTR(LD_MISS_L1), |
| 412 | 460 | POWER_EVENT_PTR(BRU_FIN), |
| 413 | 461 | POWER_EVENT_PTR(BRU_MPRED), |
| 462 | + | |
| 463 | + POWER_EVENT_PTR(CMPLU_STALL_FXU), | |
| 464 | + POWER_EVENT_PTR(CMPLU_STALL_DIV), | |
| 465 | + POWER_EVENT_PTR(CMPLU_STALL_SCALAR), | |
| 466 | + POWER_EVENT_PTR(CMPLU_STALL_SCALAR_LONG), | |
| 467 | + POWER_EVENT_PTR(CMPLU_STALL_VECTOR), | |
| 468 | + POWER_EVENT_PTR(CMPLU_STALL_VECTOR_LONG), | |
| 469 | + POWER_EVENT_PTR(CMPLU_STALL_LSU), | |
| 470 | + POWER_EVENT_PTR(CMPLU_STALL_REJECT), | |
| 471 | + | |
| 472 | + POWER_EVENT_PTR(CMPLU_STALL_ERAT_MISS), | |
| 473 | + POWER_EVENT_PTR(CMPLU_STALL_DCACHE_MISS), | |
| 474 | + POWER_EVENT_PTR(CMPLU_STALL_STORE), | |
| 475 | + POWER_EVENT_PTR(CMPLU_STALL_THRD), | |
| 476 | + POWER_EVENT_PTR(CMPLU_STALL_IFU), | |
| 477 | + POWER_EVENT_PTR(CMPLU_STALL_BRU), | |
| 478 | + POWER_EVENT_PTR(GCT_NOSLOT_IC_MISS), | |
| 479 | + POWER_EVENT_PTR(GCT_NOSLOT_BR_MPRED), | |
| 480 | + | |
| 481 | + POWER_EVENT_PTR(GCT_NOSLOT_BR_MPRED_IC_MISS), | |
| 482 | + POWER_EVENT_PTR(GRP_CMPL), | |
| 483 | + POWER_EVENT_PTR(1PLUS_PPC_CMPL), | |
| 484 | + POWER_EVENT_PTR(CMPLU_STALL_DFU), | |
| 485 | + POWER_EVENT_PTR(RUN_CYC), | |
| 486 | + POWER_EVENT_PTR(RUN_INST_CMPL), | |
| 414 | 487 | NULL |
| 415 | 488 | }; |
| 416 | 489 | |
| @@ -34,8 +34,6 @@ · 33 unmodified lines | ||
| 34 | 34 | #include <asm/sys_ia32.h> |
| 35 | 35 | #include <asm/smap.h> |
| 36 | 36 | |
| 37 | −#define FIX_EFLAGS __FIX_EFLAGS | |
| 38 | − | |
| 39 | 37 | int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) |
| 40 | 38 | { |
| 41 | 39 | int err = 0; |
| @@ -29,6 +29,9 @@ · 28 unmodified lines | ||
| 29 | 29 | #define ARCH_PERFMON_EVENTSEL_INV (1ULL << 23) |
| 30 | 30 | #define ARCH_PERFMON_EVENTSEL_CMASK 0xFF000000ULL |
| 31 | 31 | |
| 32 | +#define HSW_IN_TX (1ULL << 32) | |
| 33 | +#define HSW_IN_TX_CHECKPOINTED (1ULL << 33) | |
| 34 | + | |
| 32 | 35 | #define AMD64_EVENTSEL_INT_CORE_ENABLE (1ULL << 36) |
| 33 | 36 | #define AMD64_EVENTSEL_GUESTONLY (1ULL << 40) |
| 34 | 37 | #define AMD64_EVENTSEL_HOSTONLY (1ULL << 41) |
| @@ -7,10 +7,10 @@ · 6 unmodified lines | ||
| 7 | 7 | |
| 8 | 8 | #include <asm/processor-flags.h> |
| 9 | 9 | |
| 10 | −#define __FIX_EFLAGS (X86_EFLAGS_AC | X86_EFLAGS_OF | \ | |
| 10 | +#define FIX_EFLAGS (X86_EFLAGS_AC | X86_EFLAGS_OF | \ | |
| 11 | 11 | X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \ |
| 12 | 12 | X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \ |
| 13 | − X86_EFLAGS_CF) | |
| 13 | + X86_EFLAGS_CF | X86_EFLAGS_RF) | |
| 14 | 14 | |
| 15 | 15 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where); |
| 16 | 16 | |
| @@ -170,6 +170,9 @@ · 169 unmodified lines | ||
| 170 | 170 | #define MSR_KNC_EVNTSEL0 0x00000028 |
| 171 | 171 | #define MSR_KNC_EVNTSEL1 0x00000029 |
| 172 | 172 | |
| 173 | +/* Alternative perfctr range with full access. */ | |
| 174 | +#define MSR_IA32_PMC0 0x000004c1 | |
| 175 | + | |
| 173 | 176 | /* AMD64 MSRs. Not complete. See the architecture manual for a more |
| 174 | 177 | complete list. */ |
| 175 | 178 | |
| @@ -31,11 +31,15 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o · 30 unmodified lines | ||
| 31 | 31 | |
| 32 | 32 | ifdef CONFIG_PERF_EVENTS |
| 33 | 33 | obj-$(CONFIG_CPU_SUP_AMD) += perf_event_amd.o perf_event_amd_uncore.o |
| 34 | +ifdef CONFIG_AMD_IOMMU | |
| 35 | +obj-$(CONFIG_CPU_SUP_AMD) += perf_event_amd_iommu.o | |
| 36 | +endif | |
| 34 | 37 | obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_knc.o perf_event_p4.o |
| 35 | 38 | obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o |
| 36 | 39 | obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore.o |
| 37 | 40 | endif |
| 38 | 41 | |
| 42 | + | |
| 39 | 43 | obj-$(CONFIG_X86_MCE) += mcheck/ |
| 40 | 44 | obj-$(CONFIG_MTRR) += mtrr/ |
| 41 | 45 | |
| @@ -403,7 +403,8 @@ int x86_pmu_hw_config(struct perf_event *event) · 402 unmodified lines | ||
| 403 | 403 | * check that PEBS LBR correction does not conflict with |
| 404 | 404 | * whatever the user is asking with attr->branch_sample_type |
| 405 | 405 | */ |
| 406 | − if (event->attr.precise_ip > 1) { | |
| 406 | + if (event->attr.precise_ip > 1 && | |
| 407 | + x86_pmu.intel_cap.pebs_format < 2) { | |
| 407 | 408 | u64 *br_type = &event->attr.branch_sample_type; |
| 408 | 409 | |
| 409 | 410 | if (has_branch_stack(event)) { |
| @@ -568,7 +569,7 @@ struct sched_state { · 158 unmodified lines | ||
| 568 | 569 | struct perf_sched { |
| 569 | 570 | int max_weight; |
| 570 | 571 | int max_events; |
| 571 | − struct event_constraint **constraints; | |
| 572 | + struct perf_event **events; | |
| 572 | 573 | struct sched_state state; |
| 573 | 574 | int saved_states; |
| 574 | 575 | struct sched_state saved[SCHED_STATES_MAX]; |
| @@ -577,7 +578,7 @@ struct perf_sched { · 2 unmodified lines | ||
| 577 | 578 | /* |
| 578 | 579 | * Initialize interator that runs through all events and counters. |
| 579 | 580 | */ |
| 580 | −static void perf_sched_init(struct perf_sched *sched, struct event_constraint **c, | |
| 581 | +static void perf_sched_init(struct perf_sched *sched, struct perf_event **events, | |
| 581 | 582 | int num, int wmin, int wmax) |
| 582 | 583 | { |
| 583 | 584 | int idx; |
| @@ -585,10 +586,10 @@ static void perf_sched_init(struct perf_sched *sched, struct event_constraint ** · 1 unmodified line | ||
| 585 | 586 | memset(sched, 0, sizeof(*sched)); |
| 586 | 587 | sched->max_events = num; |
| 587 | 588 | sched->max_weight = wmax; |
| 588 | − sched->constraints = c; | |
| 589 | + sched->events = events; | |
| 589 | 590 | |
| 590 | 591 | for (idx = 0; idx < num; idx++) { |
| 591 | − if (c[idx]->weight == wmin) | |
| 592 | + if (events[idx]->hw.constraint->weight == wmin) | |
| 592 | 593 | break; |
| 593 | 594 | } |
| 594 | 595 | |
| @@ -635,8 +636,7 @@ static bool __perf_sched_find_counter(struct perf_sched *sched) · 40 unmodified lines | ||
| 635 | 636 | if (sched->state.event >= sched->max_events) |
| 636 | 637 | return false; |
| 637 | 638 | |
| 638 | − c = sched->constraints[sched->state.event]; | |
| 639 | − | |
| 639 | + c = sched->events[sched->state.event]->hw.constraint; | |
| 640 | 640 | /* Prefer fixed purpose counters */ |
| 641 | 641 | if (c->idxmsk64 & (~0ULL << INTEL_PMC_IDX_FIXED)) { |
| 642 | 642 | idx = INTEL_PMC_IDX_FIXED; |
| @@ -694,7 +694,7 @@ static bool perf_sched_next_event(struct perf_sched *sched) · 51 unmodified lines | ||
| 694 | 694 | if (sched->state.weight > sched->max_weight) |
| 695 | 695 | return false; |
| 696 | 696 | } |
| 697 | − c = sched->constraints[sched->state.event]; | |
| 697 | + c = sched->events[sched->state.event]->hw.constraint; | |
| 698 | 698 | } while (c->weight != sched->state.weight); |
| 699 | 699 | |
| 700 | 700 | sched->state.counter = 0; /* start with first counter */ |
| @@ -705,12 +705,12 @@ static bool perf_sched_next_event(struct perf_sched *sched) · 4 unmodified lines | ||
| 705 | 705 | /* |
| 706 | 706 | * Assign a counter for each event. |
| 707 | 707 | */ |
| 708 | −int perf_assign_events(struct event_constraint **constraints, int n, | |
| 708 | +int perf_assign_events(struct perf_event **events, int n, | |
| 709 | 709 | int wmin, int wmax, int *assign) |
| 710 | 710 | { |
| 711 | 711 | struct perf_sched sched; |
| 712 | 712 | |
| 713 | − perf_sched_init(&sched, constraints, n, wmin, wmax); | |
| 713 | + perf_sched_init(&sched, events, n, wmin, wmax); | |
| 714 | 714 | |
| 715 | 715 | do { |
| 716 | 716 | if (!perf_sched_find_counter(&sched)) |
| @@ -724,16 +724,19 @@ int perf_assign_events(struct event_constraint **constraints, int n, · 7 unmodified lines | ||
| 724 | 724 | |
| 725 | 725 | int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) |
| 726 | 726 | { |
| 727 | − struct event_constraint *c, *constraints[X86_PMC_IDX_MAX]; | |
| 727 | + struct event_constraint *c; | |
| 728 | 728 | unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; |
| 729 | + struct perf_event *e; | |
| 729 | 730 | int i, wmin, wmax, num = 0; |
| 730 | 731 | struct hw_perf_event *hwc; |
| 731 | 732 | |
| 732 | 733 | bitmap_zero(used_mask, X86_PMC_IDX_MAX); |
| 733 | 734 | |
| 734 | 735 | for (i = 0, wmin = X86_PMC_IDX_MAX, wmax = 0; i < n; i++) { |
| 736 | + hwc = &cpuc->event_list[i]->hw; | |
| 735 | 737 | c = x86_pmu.get_event_constraints(cpuc, cpuc->event_list[i]); |
| 736 | − constraints[i] = c; | |
| 738 | + hwc->constraint = c; | |
| 739 | + | |
| 737 | 740 | wmin = min(wmin, c->weight); |
| 738 | 741 | wmax = max(wmax, c->weight); |
| 739 | 742 | } |
| @@ -743,7 +746,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) · 3 unmodified lines | ||
| 743 | 746 | */ |
| 744 | 747 | for (i = 0; i < n; i++) { |
| 745 | 748 | hwc = &cpuc->event_list[i]->hw; |
| 746 | − c = constraints[i]; | |
| 749 | + c = hwc->constraint; | |
| 747 | 750 | |
| 748 | 751 | /* never assigned */ |
| 749 | 752 | if (hwc->idx == -1) |
| @@ -764,16 +767,35 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) · 14 unmodified lines | ||
| 764 | 767 | |
| 765 | 768 | /* slow path */ |
| 766 | 769 | if (i != n) |
| 767 | − num = perf_assign_events(constraints, n, wmin, wmax, assign); | |
| 770 | + num = perf_assign_events(cpuc->event_list, n, wmin, | |
| 771 | + wmax, assign); | |
| 768 | 772 | |
| 773 | + /* | |
| 774 | + * Mark the event as committed, so we do not put_constraint() | |
| 775 | + * in case new events are added and fail scheduling. | |
| 776 | + */ | |
| 777 | + if (!num && assign) { | |
| 778 | + for (i = 0; i < n; i++) { | |
| 779 | + e = cpuc->event_list[i]; | |
| 780 | + e->hw.flags |= PERF_X86_EVENT_COMMITTED; | |
| 781 | + } | |
| 782 | + } | |
| 769 | 783 | /* |
| 770 | 784 | * scheduling failed or is just a simulation, |
| 771 | 785 | * free resources if necessary |
| 772 | 786 | */ |
| 773 | 787 | if (!assign || num) { |
| 774 | 788 | for (i = 0; i < n; i++) { |
| 789 | + e = cpuc->event_list[i]; | |
| 790 | + /* | |
| 791 | + * do not put_constraint() on comitted events, | |
| 792 | + * because they are good to go | |
| 793 | + */ | |
| 794 | + if ((e->hw.flags & PERF_X86_EVENT_COMMITTED)) | |
| 795 | + continue; | |
| 796 | + | |
| 775 | 797 | if (x86_pmu.put_event_constraints) |
| 776 | − x86_pmu.put_event_constraints(cpuc, cpuc->event_list[i]); | |
| 798 | + x86_pmu.put_event_constraints(cpuc, e); | |
| 777 | 799 | } |
| 778 | 800 | } |
| 779 | 801 | return num ? -EINVAL : 0; |
| @@ -1152,6 +1174,11 @@ static void x86_pmu_del(struct perf_event *event, int flags) · 372 unmodified lines | ||
| 1152 | 1174 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); |
| 1153 | 1175 | int i; |
| 1154 | 1176 | |
| 1177 | + /* | |
| 1178 | + * event is descheduled | |
| 1179 | + */ | |
| 1180 | + event->hw.flags &= ~PERF_X86_EVENT_COMMITTED; | |
| 1181 | + | |
| 1155 | 1182 | /* |
| 1156 | 1183 | * If we're called during a txn, we don't need to do anything. |
| 1157 | 1184 | * The events never got scheduled and ->cancel_txn will truncate |
| @@ -1249,10 +1276,20 @@ void perf_events_lapic_init(void) · 91 unmodified lines | ||
| 1249 | 1276 | static int __kprobes |
| 1250 | 1277 | perf_event_nmi_handler(unsigned int cmd, struct pt_regs *regs) |
| 1251 | 1278 | { |
| 1279 | + int ret; | |
| 1280 | + u64 start_clock; | |
| 1281 | + u64 finish_clock; | |
| 1282 | + | |
| 1252 | 1283 | if (!atomic_read(&active_events)) |
| 1253 | 1284 | return NMI_DONE; |
| 1254 | 1285 | |
| 1255 | − return x86_pmu.handle_irq(regs); | |
| 1286 | + start_clock = local_clock(); | |
| 1287 | + ret = x86_pmu.handle_irq(regs); | |
| 1288 | + finish_clock = local_clock(); | |
| 1289 | + | |
| 1290 | + perf_sample_event_took(finish_clock - start_clock); | |
| 1291 | + | |
| 1292 | + return ret; | |
| 1256 | 1293 | } |
| 1257 | 1294 | |
| 1258 | 1295 | struct event_constraint emptyconstraint; |
| @@ -63,10 +63,12 @@ struct event_constraint { · 62 unmodified lines | ||
| 63 | 63 | int flags; |
| 64 | 64 | }; |
| 65 | 65 | /* |
| 66 | − * struct event_constraint flags | |
| 66 | + * struct hw_perf_event.flags flags | |
| 67 | 67 | */ |
| 68 | 68 | #define PERF_X86_EVENT_PEBS_LDLAT 0x1 /* ld+ldlat data address sampling */ |
| 69 | 69 | #define PERF_X86_EVENT_PEBS_ST 0x2 /* st data address sampling */ |
| 70 | +#define PERF_X86_EVENT_PEBS_ST_HSW 0x4 /* haswell style st data sampling */ | |
| 71 | +#define PERF_X86_EVENT_COMMITTED 0x8 /* event passed commit_txn */ | |
| 70 | 72 | |
| 71 | 73 | struct amd_nb { |
| 72 | 74 | int nb_id; /* NorthBridge id */ |
| @@ -227,11 +229,14 @@ struct cpu_hw_events { · 154 unmodified lines | ||
| 227 | 229 | * - inv |
| 228 | 230 | * - edge |
| 229 | 231 | * - cnt-mask |
| 232 | + * - in_tx | |
| 233 | + * - in_tx_checkpointed | |
| 230 | 234 | * The other filters are supported by fixed counters. |
| 231 | 235 | * The any-thread option is supported starting with v3. |
| 232 | 236 | */ |
| 237 | +#define FIXED_EVENT_FLAGS (X86_RAW_EVENT_MASK|HSW_IN_TX|HSW_IN_TX_CHECKPOINTED) | |
| 233 | 238 | #define FIXED_EVENT_CONSTRAINT(c, n) \ |
| 234 | − EVENT_CONSTRAINT(c, (1ULL << (32+n)), X86_RAW_EVENT_MASK) | |
| 239 | + EVENT_CONSTRAINT(c, (1ULL << (32+n)), FIXED_EVENT_FLAGS) | |
| 235 | 240 | |
| 236 | 241 | /* |
| 237 | 242 | * Constraint on the Event code + UMask |
| @@ -247,6 +252,11 @@ struct cpu_hw_events { · 9 unmodified lines | ||
| 247 | 252 | __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \ |
| 248 | 253 | HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST) |
| 249 | 254 | |
| 255 | +/* DataLA version of store sampling without extra enable bit. */ | |
| 256 | +#define INTEL_PST_HSW_CONSTRAINT(c, n) \ | |
| 257 | + __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \ | |
| 258 | + HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST_HSW) | |
| 259 | + | |
| 250 | 260 | #define EVENT_CONSTRAINT_END \ |
| 251 | 261 | EVENT_CONSTRAINT(0, 0, 0) |
| 252 | 262 | |
| @@ -301,6 +311,11 @@ union perf_capabilities { · 48 unmodified lines | ||
| 301 | 311 | u64 pebs_arch_reg:1; |
| 302 | 312 | u64 pebs_format:4; |
| 303 | 313 | u64 smm_freeze:1; |
| 314 | + /* | |
| 315 | + * PMU supports separate counter range for writing | |
| 316 | + * values > 32bit. | |
| 317 | + */ | |
| 318 | + u64 full_width_write:1; | |
| 304 | 319 | }; |
| 305 | 320 | u64 capabilities; |
| 306 | 321 | }; |
| @@ -375,6 +390,7 @@ struct x86_pmu { · 68 unmodified lines | ||
| 375 | 390 | struct event_constraint *event_constraints; |
| 376 | 391 | struct x86_pmu_quirk *quirks; |
| 377 | 392 | int perfctr_second_write; |
| 393 | + bool late_ack; | |
| 378 | 394 | |
| 379 | 395 | /* |
| 380 | 396 | * sysfs attrs |
| @@ -528,7 +544,7 @@ static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc, · 147 unmodified lines | ||
| 528 | 544 | |
| 529 | 545 | void x86_pmu_enable_all(int added); |
| 530 | 546 | |
| 531 | −int perf_assign_events(struct event_constraint **constraints, int n, | |
| 547 | +int perf_assign_events(struct perf_event **events, int n, | |
| 532 | 548 | int wmin, int wmax, int *assign); |
| 533 | 549 | int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign); |
| 534 | 550 | |
| @@ -633,6 +649,8 @@ extern struct event_constraint intel_snb_pebs_event_constraints[]; · 98 unmodified lines | ||
| 633 | 649 | |
| 634 | 650 | extern struct event_constraint intel_ivb_pebs_event_constraints[]; |
| 635 | 651 | |
| 652 | +extern struct event_constraint intel_hsw_pebs_event_constraints[]; | |
| 653 | + | |
| 636 | 654 | struct event_constraint *intel_pebs_constraints(struct perf_event *event); |
| 637 | 655 | |
| 638 | 656 | void intel_pmu_pebs_enable(struct perf_event *event); |
| @@ -648,48 +648,48 @@ static __initconst const struct x86_pmu amd_pmu = { · 647 unmodified lines | ||
| 648 | 648 | .cpu_dead = amd_pmu_cpu_dead, |
| 649 | 649 | }; |
| 650 | 650 | |
| 651 | −static int setup_event_constraints(void) | |
| 651 | +static int __init amd_core_pmu_init(void) | |
| 652 | 652 | { |
| 653 | − if (boot_cpu_data.x86 == 0x15) | |
| 653 | + if (!cpu_has_perfctr_core) | |
| 654 | + return 0; | |
| 655 | + | |
| 656 | + switch (boot_cpu_data.x86) { | |
| 657 | + case 0x15: | |
| 658 | + pr_cont("Fam15h "); | |
| 654 | 659 | x86_pmu.get_event_constraints = amd_get_event_constraints_f15h; |
| 655 | − return 0; | |
| 656 | −} | |
| 660 | + break; | |
| 657 | 661 | |
| 658 | −static int setup_perfctr_core(void) | |
| 659 | −{ | |
| 660 | − if (!cpu_has_perfctr_core) { | |
| 661 | − WARN(x86_pmu.get_event_constraints == amd_get_event_constraints_f15h, | |
| 662 | − KERN_ERR "Odd, counter constraints enabled but no core perfctrs detected!"); | |
| 662 | + default: | |
| 663 | + pr_err("core perfctr but no constraints; unknown hardware!\n"); | |
| 663 | 664 | return -ENODEV; |
| 664 | 665 | } |
| 665 | 666 | |
| 666 | − WARN(x86_pmu.get_event_constraints == amd_get_event_constraints, | |
| 667 | − KERN_ERR "hw perf events core counters need constraints handler!"); | |
| 668 | − | |
| 669 | 667 | /* |
| 670 | 668 | * If core performance counter extensions exists, we must use |
| 671 | 669 | * MSR_F15H_PERF_CTL/MSR_F15H_PERF_CTR msrs. See also |
| 672 | − * x86_pmu_addr_offset(). | |
| 670 | + * amd_pmu_addr_offset(). | |
| 673 | 671 | */ |
| 674 | 672 | x86_pmu.eventsel = MSR_F15H_PERF_CTL; |
| 675 | 673 | x86_pmu.perfctr = MSR_F15H_PERF_CTR; |
| 676 | 674 | x86_pmu.num_counters = AMD64_NUM_COUNTERS_CORE; |
| 677 | 675 | |
| 678 | − printk(KERN_INFO "perf: AMD core performance counters detected\n"); | |
| 679 | − | |
| 676 | + pr_cont("core perfctr, "); | |
| 680 | 677 | return 0; |
| 681 | 678 | } |
| 682 | 679 | |
| 683 | 680 | __init int amd_pmu_init(void) |
| 684 | 681 | { |
| 682 | + int ret; | |
| 683 | + | |
| 685 | 684 | /* Performance-monitoring supported from K7 and later: */ |
| 686 | 685 | if (boot_cpu_data.x86 < 6) |
| 687 | 686 | return -ENODEV; |
| 688 | 687 | |
| 689 | 688 | x86_pmu = amd_pmu; |
| 690 | 689 | |
| 691 | − setup_event_constraints(); | |
| 692 | − setup_perfctr_core(); | |
| 690 | + ret = amd_core_pmu_init(); | |
| 691 | + if (ret) | |
| 692 | + return ret; | |
| 693 | 693 | |
| 694 | 694 | /* Events are common for all AMDs */ |
| 695 | 695 | memcpy(hw_cache_event_ids, amd_hw_cache_event_ids, |
| @@ -0,0 +1,504 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (C) 2013 Advanced Micro Devices, Inc. | |
| 3 | + * | |
| 4 | + * Author: Steven Kinney <Steven.Kinney@amd.com> | |
| 5 | + * Author: Suravee Suthikulpanit <Suraveee.Suthikulpanit@amd.com> | |
| 6 | + * | |
| 7 | + * Perf: amd_iommu - AMD IOMMU Performance Counter PMU implementation | |
| 8 | + * | |
| 9 | + * This program is free software; you can redistribute it and/or modify | |
| 10 | + * it under the terms of the GNU General Public License version 2 as | |
| 11 | + * published by the Free Software Foundation. | |
| 12 | + */ | |
| 13 | + | |
| 14 | +#include <linux/perf_event.h> | |
| 15 | +#include <linux/module.h> | |
| 16 | +#include <linux/cpumask.h> | |
| 17 | +#include <linux/slab.h> | |
| 18 | + | |
| 19 | +#include "perf_event.h" | |
| 20 | +#include "perf_event_amd_iommu.h" | |
| 21 | + | |
| 22 | +#define COUNTER_SHIFT 16 | |
| 23 | + | |
| 24 | +#define _GET_BANK(ev) ((u8)(ev->hw.extra_reg.reg >> 8)) | |
| 25 | +#define _GET_CNTR(ev) ((u8)(ev->hw.extra_reg.reg)) | |
| 26 | + | |
| 27 | +/* iommu pmu config masks */ | |
| 28 | +#define _GET_CSOURCE(ev) ((ev->hw.config & 0xFFULL)) | |
| 29 | +#define _GET_DEVID(ev) ((ev->hw.config >> 8) & 0xFFFFULL) | |
| 30 | +#define _GET_PASID(ev) ((ev->hw.config >> 24) & 0xFFFFULL) | |
| 31 | +#define _GET_DOMID(ev) ((ev->hw.config >> 40) & 0xFFFFULL) | |
| 32 | +#define _GET_DEVID_MASK(ev) ((ev->hw.extra_reg.config) & 0xFFFFULL) | |
| 33 | +#define _GET_PASID_MASK(ev) ((ev->hw.extra_reg.config >> 16) & 0xFFFFULL) | |
| 34 | +#define _GET_DOMID_MASK(ev) ((ev->hw.extra_reg.config >> 32) & 0xFFFFULL) | |
| 35 | + | |
| 36 | +static struct perf_amd_iommu __perf_iommu; | |
| 37 | + | |
| 38 | +struct perf_amd_iommu { | |
| 39 | + struct pmu pmu; | |
| 40 | + u8 max_banks; | |
| 41 | + u8 max_counters; | |
| 42 | + u64 cntr_assign_mask; | |
| 43 | + raw_spinlock_t lock; | |
| 44 | + const struct attribute_group *attr_groups[4]; | |
| 45 | +}; | |
| 46 | + | |
| 47 | +#define format_group attr_groups[0] | |
| 48 | +#define cpumask_group attr_groups[1] | |
| 49 | +#define events_group attr_groups[2] | |
| 50 | +#define null_group attr_groups[3] | |
| 51 | + | |
| 52 | +/*--------------------------------------------- | |
| 53 | + * sysfs format attributes | |
| 54 | + *---------------------------------------------*/ | |
| 55 | +PMU_FORMAT_ATTR(csource, "config:0-7"); | |
| 56 | +PMU_FORMAT_ATTR(devid, "config:8-23"); | |
| 57 | +PMU_FORMAT_ATTR(pasid, "config:24-39"); | |
| 58 | +PMU_FORMAT_ATTR(domid, "config:40-55"); | |
| 59 | +PMU_FORMAT_ATTR(devid_mask, "config1:0-15"); | |
| 60 | +PMU_FORMAT_ATTR(pasid_mask, "config1:16-31"); | |
| 61 | +PMU_FORMAT_ATTR(domid_mask, "config1:32-47"); | |
| 62 | + | |
| 63 | +static struct attribute *iommu_format_attrs[] = { | |
| 64 | + &format_attr_csource.attr, | |
| 65 | + &format_attr_devid.attr, | |
| 66 | + &format_attr_pasid.attr, | |
| 67 | + &format_attr_domid.attr, | |
| 68 | + &format_attr_devid_mask.attr, | |
| 69 | + &format_attr_pasid_mask.attr, | |
| 70 | + &format_attr_domid_mask.attr, | |
| 71 | + NULL, | |
| 72 | +}; | |
| 73 | + | |
| 74 | +static struct attribute_group amd_iommu_format_group = { | |
| 75 | + .name = "format", | |
| 76 | + .attrs = iommu_format_attrs, | |
| 77 | +}; | |
| 78 | + | |
| 79 | +/*--------------------------------------------- | |
| 80 | + * sysfs events attributes | |
| 81 | + *---------------------------------------------*/ | |
| 82 | +struct amd_iommu_event_desc { | |
| 83 | + struct kobj_attribute attr; | |
| 84 | + const char *event; | |
| 85 | +}; | |
| 86 | + | |
| 87 | +static ssize_t _iommu_event_show(struct kobject *kobj, | |
| 88 | + struct kobj_attribute *attr, char *buf) | |
| 89 | +{ | |
| 90 | + struct amd_iommu_event_desc *event = | |
| 91 | + container_of(attr, struct amd_iommu_event_desc, attr); | |
| 92 | + return sprintf(buf, "%s\n", event->event); | |
| 93 | +} | |
| 94 | + | |
| 95 | +#define AMD_IOMMU_EVENT_DESC(_name, _event) \ | |
| 96 | +{ \ | |
| 97 | + .attr = __ATTR(_name, 0444, _iommu_event_show, NULL), \ | |
| 98 | + .event = _event, \ | |
| 99 | +} | |
| 100 | + | |
| 101 | +static struct amd_iommu_event_desc amd_iommu_v2_event_descs[] = { | |
| 102 | + AMD_IOMMU_EVENT_DESC(mem_pass_untrans, "csource=0x01"), | |
| 103 | + AMD_IOMMU_EVENT_DESC(mem_pass_pretrans, "csource=0x02"), | |
| 104 | + AMD_IOMMU_EVENT_DESC(mem_pass_excl, "csource=0x03"), | |
| 105 | + AMD_IOMMU_EVENT_DESC(mem_target_abort, "csource=0x04"), | |
| 106 | + AMD_IOMMU_EVENT_DESC(mem_trans_total, "csource=0x05"), | |
| 107 | + AMD_IOMMU_EVENT_DESC(mem_iommu_tlb_pte_hit, "csource=0x06"), | |
| 108 | + AMD_IOMMU_EVENT_DESC(mem_iommu_tlb_pte_mis, "csource=0x07"), | |
| 109 | + AMD_IOMMU_EVENT_DESC(mem_iommu_tlb_pde_hit, "csource=0x08"), | |
| 110 | + AMD_IOMMU_EVENT_DESC(mem_iommu_tlb_pde_mis, "csource=0x09"), | |
| 111 | + AMD_IOMMU_EVENT_DESC(mem_dte_hit, "csource=0x0a"), | |
| 112 | + AMD_IOMMU_EVENT_DESC(mem_dte_mis, "csource=0x0b"), | |
| 113 | + AMD_IOMMU_EVENT_DESC(page_tbl_read_tot, "csource=0x0c"), | |
| 114 | + AMD_IOMMU_EVENT_DESC(page_tbl_read_nst, "csource=0x0d"), | |
| 115 | + AMD_IOMMU_EVENT_DESC(page_tbl_read_gst, "csource=0x0e"), | |
| 116 | + AMD_IOMMU_EVENT_DESC(int_dte_hit, "csource=0x0f"), | |
| 117 | + AMD_IOMMU_EVENT_DESC(int_dte_mis, "csource=0x10"), | |
| 118 | + AMD_IOMMU_EVENT_DESC(cmd_processed, "csource=0x11"), | |
| 119 | + AMD_IOMMU_EVENT_DESC(cmd_processed_inv, "csource=0x12"), | |
| 120 | + AMD_IOMMU_EVENT_DESC(tlb_inv, "csource=0x13"), | |
| 121 | + { /* end: all zeroes */ }, | |
| 122 | +}; | |
| 123 | + | |
| 124 | +/*--------------------------------------------- | |
| 125 | + * sysfs cpumask attributes | |
| 126 | + *---------------------------------------------*/ | |
| 127 | +static cpumask_t iommu_cpumask; | |
| 128 | + | |
| 129 | +static ssize_t _iommu_cpumask_show(struct device *dev, | |
| 130 | + struct device_attribute *attr, | |
| 131 | + char *buf) | |
| 132 | +{ | |
| 133 | + int n = cpulist_scnprintf(buf, PAGE_SIZE - 2, &iommu_cpumask); | |
| 134 | + buf[n++] = '\n'; | |
| 135 | + buf[n] = '\0'; | |
| 136 | + return n; | |
| 137 | +} | |
| 138 | +static DEVICE_ATTR(cpumask, S_IRUGO, _iommu_cpumask_show, NULL); | |
| 139 | + | |
| 140 | +static struct attribute *iommu_cpumask_attrs[] = { | |
| 141 | + &dev_attr_cpumask.attr, | |
| 142 | + NULL, | |
| 143 | +}; | |
| 144 | + | |
| 145 | +static struct attribute_group amd_iommu_cpumask_group = { | |
| 146 | + .attrs = iommu_cpumask_attrs, | |
| 147 | +}; | |
| 148 | + | |
| 149 | +/*---------------------------------------------*/ | |
| 150 | + | |
| 151 | +static int get_next_avail_iommu_bnk_cntr(struct perf_amd_iommu *perf_iommu) | |
| 152 | +{ | |
| 153 | + unsigned long flags; | |
| 154 | + int shift, bank, cntr, retval; | |
| 155 | + int max_banks = perf_iommu->max_banks; | |
| 156 | + int max_cntrs = perf_iommu->max_counters; | |
| 157 | + | |
| 158 | + raw_spin_lock_irqsave(&perf_iommu->lock, flags); | |
| 159 | + | |
| 160 | + for (bank = 0, shift = 0; bank < max_banks; bank++) { | |
| 161 | + for (cntr = 0; cntr < max_cntrs; cntr++) { | |
| 162 | + shift = bank + (bank*3) + cntr; | |
| 163 | + if (perf_iommu->cntr_assign_mask & (1ULL<<shift)) { | |
| 164 | + continue; | |
| 165 | + } else { | |
| 166 | + perf_iommu->cntr_assign_mask |= (1ULL<<shift); | |
| 167 | + retval = ((u16)((u16)bank<<8) | (u8)(cntr)); | |
| 168 | + goto out; | |
| 169 | + } | |
| 170 | + } | |
| 171 | + } | |
| 172 | + retval = -ENOSPC; | |
| 173 | +out: | |
| 174 | + raw_spin_unlock_irqrestore(&perf_iommu->lock, flags); | |
| 175 | + return retval; | |
| 176 | +} | |
| 177 | + | |
| 178 | +static int clear_avail_iommu_bnk_cntr(struct perf_amd_iommu *perf_iommu, | |
| 179 | + u8 bank, u8 cntr) | |
| 180 | +{ | |
| 181 | + unsigned long flags; | |
| 182 | + int max_banks, max_cntrs; | |
| 183 | + int shift = 0; | |
| 184 | + | |
| 185 | + max_banks = perf_iommu->max_banks; | |
| 186 | + max_cntrs = perf_iommu->max_counters; | |
| 187 | + | |
| 188 | + if ((bank > max_banks) || (cntr > max_cntrs)) | |
| 189 | + return -EINVAL; | |
| 190 | + | |
| 191 | + shift = bank + cntr + (bank*3); | |
| 192 | + | |
| 193 | + raw_spin_lock_irqsave(&perf_iommu->lock, flags); | |
| 194 | + perf_iommu->cntr_assign_mask &= ~(1ULL<<shift); | |
| 195 | + raw_spin_unlock_irqrestore(&perf_iommu->lock, flags); | |
| 196 | + | |
| 197 | + return 0; | |
| 198 | +} | |
| 199 | + | |
| 200 | +static int perf_iommu_event_init(struct perf_event *event) | |
| 201 | +{ | |
| 202 | + struct hw_perf_event *hwc = &event->hw; | |
| 203 | + struct perf_amd_iommu *perf_iommu; | |
| 204 | + u64 config, config1; | |
| 205 | + | |
| 206 | + /* test the event attr type check for PMU enumeration */ | |
| 207 | + if (event->attr.type != event->pmu->type) | |
| 208 | + return -ENOENT; | |
| 209 | + | |
| 210 | + /* | |
| 211 | + * IOMMU counters are shared across all cores. | |
| 212 | + * Therefore, it does not support per-process mode. | |
| 213 | + * Also, it does not support event sampling mode. | |
| 214 | + */ | |
| 215 | + if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) | |
| 216 | + return -EINVAL; | |
| 217 | + | |
| 218 | + /* IOMMU counters do not have usr/os/guest/host bits */ | |
| 219 | + if (event->attr.exclude_user || event->attr.exclude_kernel || | |
| 220 | + event->attr.exclude_host || event->attr.exclude_guest) | |
| 221 | + return -EINVAL; | |
| 222 | + | |
| 223 | + if (event->cpu < 0) | |
| 224 | + return -EINVAL; | |
| 225 | + | |
| 226 | + perf_iommu = &__perf_iommu; | |
| 227 | + | |
| 228 | + if (event->pmu != &perf_iommu->pmu) | |
| 229 | + return -ENOENT; | |
| 230 | + | |
| 231 | + if (perf_iommu) { | |
| 232 | + config = event->attr.config; | |
| 233 | + config1 = event->attr.config1; | |
| 234 | + } else { | |
| 235 | + return -EINVAL; | |
| 236 | + } | |
| 237 | + | |
| 238 | + /* integrate with iommu base devid (0000), assume one iommu */ | |
| 239 | + perf_iommu->max_banks = | |
| 240 | + amd_iommu_pc_get_max_banks(IOMMU_BASE_DEVID); | |
| 241 | + perf_iommu->max_counters = | |
| 242 | + amd_iommu_pc_get_max_counters(IOMMU_BASE_DEVID); | |
| 243 | + if ((perf_iommu->max_banks == 0) || (perf_iommu->max_counters == 0)) | |
| 244 | + return -EINVAL; | |
| 245 | + | |
| 246 | + /* update the hw_perf_event struct with the iommu config data */ | |
| 247 | + hwc->config = config; | |
| 248 | + hwc->extra_reg.config = config1; | |
| 249 | + | |
| 250 | + return 0; | |
| 251 | +} | |
| 252 | + | |
| 253 | +static void perf_iommu_enable_event(struct perf_event *ev) | |
| 254 | +{ | |
| 255 | + u8 csource = _GET_CSOURCE(ev); | |
| 256 | + u16 devid = _GET_DEVID(ev); | |
| 257 | + u64 reg = 0ULL; | |
| 258 | + | |
| 259 | + reg = csource; | |
| 260 | + amd_iommu_pc_get_set_reg_val(devid, | |
| 261 | + _GET_BANK(ev), _GET_CNTR(ev) , | |
| 262 | + IOMMU_PC_COUNTER_SRC_REG, ®, true); | |
| 263 | + | |
| 264 | + reg = 0ULL | devid | (_GET_DEVID_MASK(ev) << 32); | |
| 265 | + if (reg) | |
| 266 | + reg |= (1UL << 31); | |
| 267 | + amd_iommu_pc_get_set_reg_val(devid, | |
| 268 | + _GET_BANK(ev), _GET_CNTR(ev) , | |
| 269 | + IOMMU_PC_DEVID_MATCH_REG, ®, true); | |
| 270 | + | |
| 271 | + reg = 0ULL | _GET_PASID(ev) | (_GET_PASID_MASK(ev) << 32); | |
| 272 | + if (reg) | |
| 273 | + reg |= (1UL << 31); | |
| 274 | + amd_iommu_pc_get_set_reg_val(devid, | |
| 275 | + _GET_BANK(ev), _GET_CNTR(ev) , | |
| 276 | + IOMMU_PC_PASID_MATCH_REG, ®, true); | |
| 277 | + | |
| 278 | + reg = 0ULL | _GET_DOMID(ev) | (_GET_DOMID_MASK(ev) << 32); | |
| 279 | + if (reg) | |
| 280 | + reg |= (1UL << 31); | |
| 281 | + amd_iommu_pc_get_set_reg_val(devid, | |
| 282 | + _GET_BANK(ev), _GET_CNTR(ev) , | |
| 283 | + IOMMU_PC_DOMID_MATCH_REG, ®, true); | |
| 284 | +} | |
| 285 | + | |
| 286 | +static void perf_iommu_disable_event(struct perf_event *event) | |
| 287 | +{ | |
| 288 | + u64 reg = 0ULL; | |
| 289 | + | |
| 290 | + amd_iommu_pc_get_set_reg_val(_GET_DEVID(event), | |
| 291 | + _GET_BANK(event), _GET_CNTR(event), | |
| 292 | + IOMMU_PC_COUNTER_SRC_REG, ®, true); | |
| 293 | +} | |
| 294 | + | |
| 295 | +static void perf_iommu_start(struct perf_event *event, int flags) | |
| 296 | +{ | |
| 297 | + struct hw_perf_event *hwc = &event->hw; | |
| 298 | + | |
| 299 | + pr_debug("perf: amd_iommu:perf_iommu_start\n"); | |
| 300 | + if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED))) | |
| 301 | + return; | |
| 302 | + | |
| 303 | + WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE)); | |
| 304 | + hwc->state = 0; | |
| 305 | + | |
| 306 | + if (flags & PERF_EF_RELOAD) { | |
| 307 | + u64 prev_raw_count = local64_read(&hwc->prev_count); | |
| 308 | + amd_iommu_pc_get_set_reg_val(_GET_DEVID(event), | |
| 309 | + _GET_BANK(event), _GET_CNTR(event), | |
| 310 | + IOMMU_PC_COUNTER_REG, &prev_raw_count, true); | |
| 311 | + } | |
| 312 | + | |
| 313 | + perf_iommu_enable_event(event); | |
| 314 | + perf_event_update_userpage(event); | |
| 315 | + | |
| 316 | +} | |
| 317 | + | |
| 318 | +static void perf_iommu_read(struct perf_event *event) | |
| 319 | +{ | |
| 320 | + u64 count = 0ULL; | |
| 321 | + u64 prev_raw_count = 0ULL; | |
| 322 | + u64 delta = 0ULL; | |
| 323 | + struct hw_perf_event *hwc = &event->hw; | |
| 324 | + pr_debug("perf: amd_iommu:perf_iommu_read\n"); | |
| 325 | + | |
| 326 | + amd_iommu_pc_get_set_reg_val(_GET_DEVID(event), | |
| 327 | + _GET_BANK(event), _GET_CNTR(event), | |
| 328 | + IOMMU_PC_COUNTER_REG, &count, false); | |
| 329 | + | |
| 330 | + /* IOMMU pc counter register is only 48 bits */ | |
| 331 | + count &= 0xFFFFFFFFFFFFULL; | |
| 332 | + | |
| 333 | + prev_raw_count = local64_read(&hwc->prev_count); | |
| 334 | + if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, | |
| 335 | + count) != prev_raw_count) | |
| 336 | + return; | |
| 337 | + | |
| 338 | + /* Handling 48-bit counter overflowing */ | |
| 339 | + delta = (count << COUNTER_SHIFT) - (prev_raw_count << COUNTER_SHIFT); | |
| 340 | + delta >>= COUNTER_SHIFT; | |
| 341 | + local64_add(delta, &event->count); | |
| 342 | + | |
| 343 | +} | |
| 344 | + | |
| 345 | +static void perf_iommu_stop(struct perf_event *event, int flags) | |
| 346 | +{ | |
| 347 | + struct hw_perf_event *hwc = &event->hw; | |
| 348 | + u64 config; | |
| 349 | + | |
| 350 | + pr_debug("perf: amd_iommu:perf_iommu_stop\n"); | |
| 351 | + | |
| 352 | + if (hwc->state & PERF_HES_UPTODATE) | |
| 353 | + return; | |
| 354 | + | |
| 355 | + perf_iommu_disable_event(event); | |
| 356 | + WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); | |
| 357 | + hwc->state |= PERF_HES_STOPPED; | |
| 358 | + | |
| 359 | + if (hwc->state & PERF_HES_UPTODATE) | |
| 360 | + return; | |
| 361 | + | |
| 362 | + config = hwc->config; | |
| 363 | + perf_iommu_read(event); | |
| 364 | + hwc->state |= PERF_HES_UPTODATE; | |
| 365 | +} | |
| 366 | + | |
| 367 | +static int perf_iommu_add(struct perf_event *event, int flags) | |
| 368 | +{ | |
| 369 | + int retval; | |
| 370 | + struct perf_amd_iommu *perf_iommu = | |
| 371 | + container_of(event->pmu, struct perf_amd_iommu, pmu); | |
| 372 | + | |
| 373 | + pr_debug("perf: amd_iommu:perf_iommu_add\n"); | |
| 374 | + event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED; | |
| 375 | + | |
| 376 | + /* request an iommu bank/counter */ | |
| 377 | + retval = get_next_avail_iommu_bnk_cntr(perf_iommu); | |
| 378 | + if (retval != -ENOSPC) | |
| 379 | + event->hw.extra_reg.reg = (u16)retval; | |
| 380 | + else | |
| 381 | + return retval; | |
| 382 | + | |
| 383 | + if (flags & PERF_EF_START) | |
| 384 | + perf_iommu_start(event, PERF_EF_RELOAD); | |
| 385 | + | |
| 386 | + return 0; | |
| 387 | +} | |
| 388 | + | |
| 389 | +static void perf_iommu_del(struct perf_event *event, int flags) | |
| 390 | +{ | |
| 391 | + struct perf_amd_iommu *perf_iommu = | |
| 392 | + container_of(event->pmu, struct perf_amd_iommu, pmu); | |
| 393 | + | |
| 394 | + pr_debug("perf: amd_iommu:perf_iommu_del\n"); | |
| 395 | + perf_iommu_stop(event, PERF_EF_UPDATE); | |
| 396 | + | |
| 397 | + /* clear the assigned iommu bank/counter */ | |
| 398 | + clear_avail_iommu_bnk_cntr(perf_iommu, | |
| 399 | + _GET_BANK(event), | |
| 400 | + _GET_CNTR(event)); | |
| 401 | + | |
| 402 | + perf_event_update_userpage(event); | |
| 403 | +} | |
| 404 | + | |
| 405 | +static __init int _init_events_attrs(struct perf_amd_iommu *perf_iommu) | |
| 406 | +{ | |
| 407 | + struct attribute **attrs; | |
| 408 | + struct attribute_group *attr_group; | |
| 409 | + int i = 0, j; | |
| 410 | + | |
| 411 | + while (amd_iommu_v2_event_descs[i].attr.attr.name) | |
| 412 | + i++; | |
| 413 | + | |
| 414 | + attr_group = kzalloc(sizeof(struct attribute *) | |
| 415 | + * (i + 1) + sizeof(*attr_group), GFP_KERNEL); | |
| 416 | + if (!attr_group) | |
| 417 | + return -ENOMEM; | |
| 418 | + | |
| 419 | + attrs = (struct attribute **)(attr_group + 1); | |
| 420 | + for (j = 0; j < i; j++) | |
| 421 | + attrs[j] = &amd_iommu_v2_event_descs[j].attr.attr; | |
| 422 | + | |
| 423 | + attr_group->name = "events"; | |
| 424 | + attr_group->attrs = attrs; | |
| 425 | + perf_iommu->events_group = attr_group; | |
| 426 | + | |
| 427 | + return 0; | |
| 428 | +} | |
| 429 | + | |
| 430 | +static __init void amd_iommu_pc_exit(void) | |
| 431 | +{ | |
| 432 | + if (__perf_iommu.events_group != NULL) { | |
| 433 | + kfree(__perf_iommu.events_group); | |
| 434 | + __perf_iommu.events_group = NULL; | |
| 435 | + } | |
| 436 | +} | |
| 437 | + | |
| 438 | +static __init int _init_perf_amd_iommu( | |
| 439 | + struct perf_amd_iommu *perf_iommu, char *name) | |
| 440 | +{ | |
| 441 | + int ret; | |
| 442 | + | |
| 443 | + raw_spin_lock_init(&perf_iommu->lock); | |
| 444 | + | |
| 445 | + /* Init format attributes */ | |
| 446 | + perf_iommu->format_group = &amd_iommu_format_group; | |
| 447 | + | |
| 448 | + /* Init cpumask attributes to only core 0 */ | |
| 449 | + cpumask_set_cpu(0, &iommu_cpumask); | |
| 450 | + perf_iommu->cpumask_group = &amd_iommu_cpumask_group; | |
| 451 | + | |
| 452 | + /* Init events attributes */ | |
| 453 | + if (_init_events_attrs(perf_iommu) != 0) | |
| 454 | + pr_err("perf: amd_iommu: Only support raw events.\n"); | |
| 455 | + | |
| 456 | + /* Init null attributes */ | |
| 457 | + perf_iommu->null_group = NULL; | |
| 458 | + perf_iommu->pmu.attr_groups = perf_iommu->attr_groups; | |
| 459 | + | |
| 460 | + ret = perf_pmu_register(&perf_iommu->pmu, name, -1); | |
| 461 | + if (ret) { | |
| 462 | + pr_err("perf: amd_iommu: Failed to initialized.\n"); | |
| 463 | + amd_iommu_pc_exit(); | |
| 464 | + } else { | |
| 465 | + pr_info("perf: amd_iommu: Detected. (%d banks, %d counters/bank)\n", | |
| 466 | + amd_iommu_pc_get_max_banks(IOMMU_BASE_DEVID), | |
| 467 | + amd_iommu_pc_get_max_counters(IOMMU_BASE_DEVID)); | |
| 468 | + } | |
| 469 | + | |
| 470 | + return ret; | |
| 471 | +} | |
| 472 | + | |
| 473 | +static struct perf_amd_iommu __perf_iommu = { | |
| 474 | + .pmu = { | |
| 475 | + .event_init = perf_iommu_event_init, | |
| 476 | + .add = perf_iommu_add, | |
| 477 | + .del = perf_iommu_del, | |
| 478 | + .start = perf_iommu_start, | |
| 479 | + .stop = perf_iommu_stop, | |
| 480 | + .read = perf_iommu_read, | |
| 481 | + }, | |
| 482 | + .max_banks = 0x00, | |
| 483 | + .max_counters = 0x00, | |
| 484 | + .cntr_assign_mask = 0ULL, | |
| 485 | + .format_group = NULL, | |
| 486 | + .cpumask_group = NULL, | |
| 487 | + .events_group = NULL, | |
| 488 | + .null_group = NULL, | |
| 489 | +}; | |
| 490 | + | |
| 491 | +static __init int amd_iommu_pc_init(void) | |
| 492 | +{ | |
| 493 | + /* Make sure the IOMMU PC resource is available */ | |
| 494 | + if (!amd_iommu_pc_supported()) { | |
| 495 | + pr_err("perf: amd_iommu PMU not installed. No support!\n"); | |
| 496 | + return -ENODEV; | |
| 497 | + } | |
| 498 | + | |
| 499 | + _init_perf_amd_iommu(&__perf_iommu, "amd_iommu"); | |
| 500 | + | |
| 501 | + return 0; | |
| 502 | +} | |
| 503 | + | |
| 504 | +device_initcall(amd_iommu_pc_init); | |
| @@ -0,0 +1,40 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (C) 2013 Advanced Micro Devices, Inc. | |
| 3 | + * | |
| 4 | + * Author: Steven Kinney <Steven.Kinney@amd.com> | |
| 5 | + * Author: Suravee Suthikulpanit <Suraveee.Suthikulpanit@amd.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 as | |
| 9 | + * published by the Free Software Foundation. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#ifndef _PERF_EVENT_AMD_IOMMU_H_ | |
| 13 | +#define _PERF_EVENT_AMD_IOMMU_H_ | |
| 14 | + | |
| 15 | +/* iommu pc mmio region register indexes */ | |
| 16 | +#define IOMMU_PC_COUNTER_REG 0x00 | |
| 17 | +#define IOMMU_PC_COUNTER_SRC_REG 0x08 | |
| 18 | +#define IOMMU_PC_PASID_MATCH_REG 0x10 | |
| 19 | +#define IOMMU_PC_DOMID_MATCH_REG 0x18 | |
| 20 | +#define IOMMU_PC_DEVID_MATCH_REG 0x20 | |
| 21 | +#define IOMMU_PC_COUNTER_REPORT_REG 0x28 | |
| 22 | + | |
| 23 | +/* maximun specified bank/counters */ | |
| 24 | +#define PC_MAX_SPEC_BNKS 64 | |
| 25 | +#define PC_MAX_SPEC_CNTRS 16 | |
| 26 | + | |
| 27 | +/* iommu pc reg masks*/ | |
| 28 | +#define IOMMU_BASE_DEVID 0x0000 | |
| 29 | + | |
| 30 | +/* amd_iommu_init.c external support functions */ | |
| 31 | +extern bool amd_iommu_pc_supported(void); | |
| 32 | + | |
| 33 | +extern u8 amd_iommu_pc_get_max_banks(u16 devid); | |
| 34 | + | |
| 35 | +extern u8 amd_iommu_pc_get_max_counters(u16 devid); | |
| 36 | + | |
| 37 | +extern int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, | |
| 38 | + u8 fxn, u64 *value, bool is_write); | |
| 39 | + | |
| 40 | +#endif /*_PERF_EVENT_AMD_IOMMU_H_*/ | |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <linux/slab.h> |
| 14 | 14 | #include <linux/export.h> |
| 15 | 15 | |
| 16 | +#include <asm/cpufeature.h> | |
| 16 | 17 | #include <asm/hardirq.h> |
| 17 | 18 | #include <asm/apic.h> |
| 18 | 19 | |
| @@ -190,6 +191,22 @@ struct attribute *snb_events_attrs[] = { · 171 unmodified lines | ||
| 190 | 191 | NULL, |
| 191 | 192 | }; |
| 192 | 193 | |
| 194 | +static struct event_constraint intel_hsw_event_constraints[] = { | |
| 195 | + FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ | |
| 196 | + FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ | |
| 197 | + FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */ | |
| 198 | + INTEL_EVENT_CONSTRAINT(0x48, 0x4), /* L1D_PEND_MISS.* */ | |
| 199 | + INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */ | |
| 200 | + INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */ | |
| 201 | + /* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */ | |
| 202 | + INTEL_EVENT_CONSTRAINT(0x08a3, 0x4), | |
| 203 | + /* CYCLE_ACTIVITY.STALLS_L1D_PENDING */ | |
| 204 | + INTEL_EVENT_CONSTRAINT(0x0ca3, 0x4), | |
| 205 | + /* CYCLE_ACTIVITY.CYCLES_NO_EXECUTE */ | |
| 206 | + INTEL_EVENT_CONSTRAINT(0x04a3, 0xf), | |
| 207 | + EVENT_CONSTRAINT_END | |
| 208 | +}; | |
| 209 | + | |
| 193 | 210 | static u64 intel_pmu_event_map(int hw_event) |
| 194 | 211 | { |
| 195 | 212 | return intel_perfmon_event_map[hw_event]; |
| @@ -872,7 +889,8 @@ static inline bool intel_pmu_needs_lbr_smpl(struct perf_event *event) · 676 unmodified lines | ||
| 872 | 889 | return true; |
| 873 | 890 | |
| 874 | 891 | /* implicit branch sampling to correct PEBS skid */ |
| 875 | − if (x86_pmu.intel_cap.pebs_trap && event->attr.precise_ip > 1) | |
| 892 | + if (x86_pmu.intel_cap.pebs_trap && event->attr.precise_ip > 1 && | |
| 893 | + x86_pmu.intel_cap.pebs_format < 2) | |
| 876 | 894 | return true; |
| 877 | 895 | |
| 878 | 896 | return false; |
| @@ -1167,15 +1185,11 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) · 288 unmodified lines | ||
| 1167 | 1185 | cpuc = &__get_cpu_var(cpu_hw_events); |
| 1168 | 1186 | |
| 1169 | 1187 | /* |
| 1170 | − * Some chipsets need to unmask the LVTPC in a particular spot | |
| 1171 | − * inside the nmi handler. As a result, the unmasking was pushed | |
| 1172 | − * into all the nmi handlers. | |
| 1173 | − * | |
| 1174 | − * This handler doesn't seem to have any issues with the unmasking | |
| 1175 | − * so it was left at the top. | |
| 1188 | + * No known reason to not always do late ACK, | |
| 1189 | + * but just in case do it opt-in. | |
| 1176 | 1190 | */ |
| 1177 | − apic_write(APIC_LVTPC, APIC_DM_NMI); | |
| 1178 | − | |
| 1191 | + if (!x86_pmu.late_ack) | |
| 1192 | + apic_write(APIC_LVTPC, APIC_DM_NMI); | |
| 1179 | 1193 | intel_pmu_disable_all(); |
| 1180 | 1194 | handled = intel_pmu_drain_bts_buffer(); |
| 1181 | 1195 | status = intel_pmu_get_status(); |
| @@ -1188,8 +1202,12 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) · 6 unmodified lines | ||
| 1188 | 1202 | again: |
| 1189 | 1203 | intel_pmu_ack_status(status); |
| 1190 | 1204 | if (++loops > 100) { |
| 1191 | − WARN_ONCE(1, "perfevents: irq loop stuck!\n"); | |
| 1192 | − perf_event_print_debug(); | |
| 1205 | + static bool warned = false; | |
| 1206 | + if (!warned) { | |
| 1207 | + WARN(1, "perfevents: irq loop stuck!\n"); | |
| 1208 | + perf_event_print_debug(); | |
| 1209 | + warned = true; | |
| 1210 | + } | |
| 1193 | 1211 | intel_pmu_reset(); |
| 1194 | 1212 | goto done; |
| 1195 | 1213 | } |
| @@ -1235,6 +1253,13 @@ again: · 39 unmodified lines | ||
| 1235 | 1253 | |
| 1236 | 1254 | done: |
| 1237 | 1255 | intel_pmu_enable_all(0); |
| 1256 | + /* | |
| 1257 | + * Only unmask the NMI after the overflow counters | |
| 1258 | + * have been reset. This avoids spurious NMIs on | |
| 1259 | + * Haswell CPUs. | |
| 1260 | + */ | |
| 1261 | + if (x86_pmu.late_ack) | |
| 1262 | + apic_write(APIC_LVTPC, APIC_DM_NMI); | |
| 1238 | 1263 | return handled; |
| 1239 | 1264 | } |
| 1240 | 1265 | |
| @@ -1425,7 +1450,6 @@ x86_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event) · 184 unmodified lines | ||
| 1425 | 1450 | if (x86_pmu.event_constraints) { |
| 1426 | 1451 | for_each_event_constraint(c, x86_pmu.event_constraints) { |
| 1427 | 1452 | if ((event->hw.config & c->cmask) == c->code) { |
| 1428 | − /* hw.flags zeroed at initialization */ | |
| 1429 | 1453 | event->hw.flags |= c->flags; |
| 1430 | 1454 | return c; |
| 1431 | 1455 | } |
| @@ -1473,7 +1497,6 @@ intel_put_shared_regs_event_constraints(struct cpu_hw_events *cpuc, · 41 unmodified lines | ||
| 1473 | 1497 | static void intel_put_event_constraints(struct cpu_hw_events *cpuc, |
| 1474 | 1498 | struct perf_event *event) |
| 1475 | 1499 | { |
| 1476 | − event->hw.flags = 0; | |
| 1477 | 1500 | intel_put_shared_regs_event_constraints(cpuc, event); |
| 1478 | 1501 | } |
| 1479 | 1502 | |
| @@ -1646,6 +1669,47 @@ static void core_pmu_enable_all(int added) · 166 unmodified lines | ||
| 1646 | 1669 | } |
| 1647 | 1670 | } |
| 1648 | 1671 | |
| 1672 | +static int hsw_hw_config(struct perf_event *event) | |
| 1673 | +{ | |
| 1674 | + int ret = intel_pmu_hw_config(event); | |
| 1675 | + | |
| 1676 | + if (ret) | |
| 1677 | + return ret; | |
| 1678 | + if (!boot_cpu_has(X86_FEATURE_RTM) && !boot_cpu_has(X86_FEATURE_HLE)) | |
| 1679 | + return 0; | |
| 1680 | + event->hw.config |= event->attr.config & (HSW_IN_TX|HSW_IN_TX_CHECKPOINTED); | |
| 1681 | + | |
| 1682 | + /* | |
| 1683 | + * IN_TX/IN_TX-CP filters are not supported by the Haswell PMU with | |
| 1684 | + * PEBS or in ANY thread mode. Since the results are non-sensical forbid | |
| 1685 | + * this combination. | |
| 1686 | + */ | |
| 1687 | + if ((event->hw.config & (HSW_IN_TX|HSW_IN_TX_CHECKPOINTED)) && | |
| 1688 | + ((event->hw.config & ARCH_PERFMON_EVENTSEL_ANY) || | |
| 1689 | + event->attr.precise_ip > 0)) | |
| 1690 | + return -EOPNOTSUPP; | |
| 1691 | + | |
| 1692 | + return 0; | |
| 1693 | +} | |
| 1694 | + | |
| 1695 | +static struct event_constraint counter2_constraint = | |
| 1696 | + EVENT_CONSTRAINT(0, 0x4, 0); | |
| 1697 | + | |
| 1698 | +static struct event_constraint * | |
| 1699 | +hsw_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event) | |
| 1700 | +{ | |
| 1701 | + struct event_constraint *c = intel_get_event_constraints(cpuc, event); | |
| 1702 | + | |
| 1703 | + /* Handle special quirk on in_tx_checkpointed only in counter 2 */ | |
| 1704 | + if (event->hw.config & HSW_IN_TX_CHECKPOINTED) { | |
| 1705 | + if (c->idxmsk64 & (1U << 2)) | |
| 1706 | + return &counter2_constraint; | |
| 1707 | + return &emptyconstraint; | |
| 1708 | + } | |
| 1709 | + | |
| 1710 | + return c; | |
| 1711 | +} | |
| 1712 | + | |
| 1649 | 1713 | PMU_FORMAT_ATTR(event, "config:0-7" ); |
| 1650 | 1714 | PMU_FORMAT_ATTR(umask, "config:8-15" ); |
| 1651 | 1715 | PMU_FORMAT_ATTR(edge, "config:18" ); |
| @@ -1653,6 +1717,8 @@ PMU_FORMAT_ATTR(pc, "config:19" ); · 1 unmodified line | ||
| 1653 | 1717 | PMU_FORMAT_ATTR(any, "config:21" ); /* v3 + */ |
| 1654 | 1718 | PMU_FORMAT_ATTR(inv, "config:23" ); |
| 1655 | 1719 | PMU_FORMAT_ATTR(cmask, "config:24-31" ); |
| 1720 | +PMU_FORMAT_ATTR(in_tx, "config:32"); | |
| 1721 | +PMU_FORMAT_ATTR(in_tx_cp, "config:33"); | |
| 1656 | 1722 | |
| 1657 | 1723 | static struct attribute *intel_arch_formats_attr[] = { |
| 1658 | 1724 | &format_attr_event.attr, |
| @@ -1807,6 +1873,8 @@ static struct attribute *intel_arch3_formats_attr[] = { · 148 unmodified lines | ||
| 1807 | 1873 | &format_attr_any.attr, |
| 1808 | 1874 | &format_attr_inv.attr, |
| 1809 | 1875 | &format_attr_cmask.attr, |
| 1876 | + &format_attr_in_tx.attr, | |
| 1877 | + &format_attr_in_tx_cp.attr, | |
| 1810 | 1878 | |
| 1811 | 1879 | &format_attr_offcore_rsp.attr, /* XXX do NHM/WSM + SNB breakout */ |
| 1812 | 1880 | &format_attr_ldlat.attr, /* PEBS load latency */ |
| @@ -1966,6 +2034,15 @@ static __init void intel_nehalem_quirk(void) · 153 unmodified lines | ||
| 1966 | 2034 | } |
| 1967 | 2035 | } |
| 1968 | 2036 | |
| 2037 | +EVENT_ATTR_STR(mem-loads, mem_ld_hsw, "event=0xcd,umask=0x1,ldlat=3"); | |
| 2038 | +EVENT_ATTR_STR(mem-stores, mem_st_hsw, "event=0xd0,umask=0x82") | |
| 2039 | + | |
| 2040 | +static struct attribute *hsw_events_attrs[] = { | |
| 2041 | + EVENT_PTR(mem_ld_hsw), | |
| 2042 | + EVENT_PTR(mem_st_hsw), | |
| 2043 | + NULL | |
| 2044 | +}; | |
| 2045 | + | |
| 1969 | 2046 | __init int intel_pmu_init(void) |
| 1970 | 2047 | { |
| 1971 | 2048 | union cpuid10_edx edx; |
| @@ -2189,6 +2266,30 @@ __init int intel_pmu_init(void) · 217 unmodified lines | ||
| 2189 | 2266 | break; |
| 2190 | 2267 | |
| 2191 | 2268 | |
| 2269 | + case 60: /* Haswell Client */ | |
| 2270 | + case 70: | |
| 2271 | + case 71: | |
| 2272 | + case 63: | |
| 2273 | + x86_pmu.late_ack = true; | |
| 2274 | + memcpy(hw_cache_event_ids, snb_hw_cache_event_ids, sizeof(hw_cache_event_ids)); | |
| 2275 | + memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs, sizeof(hw_cache_extra_regs)); | |
| 2276 | + | |
| 2277 | + intel_pmu_lbr_init_snb(); | |
| 2278 | + | |
| 2279 | + x86_pmu.event_constraints = intel_hsw_event_constraints; | |
| 2280 | + x86_pmu.pebs_constraints = intel_hsw_pebs_event_constraints; | |
| 2281 | + x86_pmu.extra_regs = intel_snb_extra_regs; | |
| 2282 | + x86_pmu.pebs_aliases = intel_pebs_aliases_snb; | |
| 2283 | + /* all extra regs are per-cpu when HT is on */ | |
| 2284 | + x86_pmu.er_flags |= ERF_HAS_RSP_1; | |
| 2285 | + x86_pmu.er_flags |= ERF_NO_HT_SHARING; | |
| 2286 | + | |
| 2287 | + x86_pmu.hw_config = hsw_hw_config; | |
| 2288 | + x86_pmu.get_event_constraints = hsw_get_event_constraints; | |
| 2289 | + x86_pmu.cpu_events = hsw_events_attrs; | |
| 2290 | + pr_cont("Haswell events, "); | |
| 2291 | + break; | |
| 2292 | + | |
| 2192 | 2293 | default: |
| 2193 | 2294 | switch (x86_pmu.version) { |
| 2194 | 2295 | case 1: |
| @@ -2227,7 +2328,7 @@ __init int intel_pmu_init(void) · 32 unmodified lines | ||
| 2227 | 2328 | * counter, so do not extend mask to generic counters |
| 2228 | 2329 | */ |
| 2229 | 2330 | for_each_event_constraint(c, x86_pmu.event_constraints) { |
| 2230 | − if (c->cmask != X86_RAW_EVENT_MASK | |
| 2331 | + if (c->cmask != FIXED_EVENT_FLAGS | |
| 2231 | 2332 | || c->idxmsk64 == INTEL_PMC_MSK_FIXED_REF_CYCLES) { |
| 2232 | 2333 | continue; |
| 2233 | 2334 | } |
| @@ -2237,5 +2338,12 @@ __init int intel_pmu_init(void) · 3 unmodified lines | ||
| 2237 | 2338 | } |
| 2238 | 2339 | } |
| 2239 | 2340 | |
| 2341 | + /* Support full width counters using alternative MSR range */ | |
| 2342 | + if (x86_pmu.intel_cap.full_width_write) { | |
| 2343 | + x86_pmu.max_period = x86_pmu.cntval_mask; | |
| 2344 | + x86_pmu.perfctr = MSR_IA32_PMC0; | |
| 2345 | + pr_cont("full-width counters, "); | |
| 2346 | + } | |
| 2347 | + | |
| 2240 | 2348 | return 0; |
| 2241 | 2349 | } |
| @@ -107,6 +107,19 @@ static u64 precise_store_data(u64 status) · 106 unmodified lines | ||
| 107 | 107 | return val; |
| 108 | 108 | } |
| 109 | 109 | |
| 110 | +static u64 precise_store_data_hsw(u64 status) | |
| 111 | +{ | |
| 112 | + union perf_mem_data_src dse; | |
| 113 | + | |
| 114 | + dse.val = 0; | |
| 115 | + dse.mem_op = PERF_MEM_OP_STORE; | |
| 116 | + dse.mem_lvl = PERF_MEM_LVL_NA; | |
| 117 | + if (status & 1) | |
| 118 | + dse.mem_lvl = PERF_MEM_LVL_L1; | |
| 119 | + /* Nothing else supported. Sorry. */ | |
| 120 | + return dse.val; | |
| 121 | +} | |
| 122 | + | |
| 110 | 123 | static u64 load_latency_data(u64 status) |
| 111 | 124 | { |
| 112 | 125 | union intel_x86_pebs_dse dse; |
| @@ -165,6 +178,22 @@ struct pebs_record_nhm { · 52 unmodified lines | ||
| 165 | 178 | u64 status, dla, dse, lat; |
| 166 | 179 | }; |
| 167 | 180 | |
| 181 | +/* | |
| 182 | + * Same as pebs_record_nhm, with two additional fields. | |
| 183 | + */ | |
| 184 | +struct pebs_record_hsw { | |
| 185 | + struct pebs_record_nhm nhm; | |
| 186 | + /* | |
| 187 | + * Real IP of the event. In the Intel documentation this | |
| 188 | + * is called eventingrip. | |
| 189 | + */ | |
| 190 | + u64 real_ip; | |
| 191 | + /* | |
| 192 | + * TSX tuning information field: abort cycles and abort flags. | |
| 193 | + */ | |
| 194 | + u64 tsx_tuning; | |
| 195 | +}; | |
| 196 | + | |
| 168 | 197 | void init_debug_store_on_cpu(int cpu) |
| 169 | 198 | { |
| 170 | 199 | struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; |
| @@ -548,6 +577,42 @@ struct event_constraint intel_ivb_pebs_event_constraints[] = { · 377 unmodified lines | ||
| 548 | 577 | EVENT_CONSTRAINT_END |
| 549 | 578 | }; |
| 550 | 579 | |
| 580 | +struct event_constraint intel_hsw_pebs_event_constraints[] = { | |
| 581 | + INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */ | |
| 582 | + INTEL_PST_HSW_CONSTRAINT(0x01c2, 0xf), /* UOPS_RETIRED.ALL */ | |
| 583 | + INTEL_UEVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */ | |
| 584 | + INTEL_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */ | |
| 585 | + INTEL_UEVENT_CONSTRAINT(0x01c5, 0xf), /* BR_MISP_RETIRED.CONDITIONAL */ | |
| 586 | + INTEL_UEVENT_CONSTRAINT(0x04c5, 0xf), /* BR_MISP_RETIRED.ALL_BRANCHES */ | |
| 587 | + INTEL_UEVENT_CONSTRAINT(0x20c5, 0xf), /* BR_MISP_RETIRED.NEAR_TAKEN */ | |
| 588 | + INTEL_PLD_CONSTRAINT(0x01cd, 0x8), /* MEM_TRANS_RETIRED.* */ | |
| 589 | + /* MEM_UOPS_RETIRED.STLB_MISS_LOADS */ | |
| 590 | + INTEL_UEVENT_CONSTRAINT(0x11d0, 0xf), | |
| 591 | + /* MEM_UOPS_RETIRED.STLB_MISS_STORES */ | |
| 592 | + INTEL_UEVENT_CONSTRAINT(0x12d0, 0xf), | |
| 593 | + INTEL_UEVENT_CONSTRAINT(0x21d0, 0xf), /* MEM_UOPS_RETIRED.LOCK_LOADS */ | |
| 594 | + INTEL_UEVENT_CONSTRAINT(0x41d0, 0xf), /* MEM_UOPS_RETIRED.SPLIT_LOADS */ | |
| 595 | + /* MEM_UOPS_RETIRED.SPLIT_STORES */ | |
| 596 | + INTEL_UEVENT_CONSTRAINT(0x42d0, 0xf), | |
| 597 | + INTEL_UEVENT_CONSTRAINT(0x81d0, 0xf), /* MEM_UOPS_RETIRED.ALL_LOADS */ | |
| 598 | + INTEL_PST_HSW_CONSTRAINT(0x82d0, 0xf), /* MEM_UOPS_RETIRED.ALL_STORES */ | |
| 599 | + INTEL_UEVENT_CONSTRAINT(0x01d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L1_HIT */ | |
| 600 | + INTEL_UEVENT_CONSTRAINT(0x02d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L2_HIT */ | |
| 601 | + INTEL_UEVENT_CONSTRAINT(0x04d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L3_HIT */ | |
| 602 | + /* MEM_LOAD_UOPS_RETIRED.HIT_LFB */ | |
| 603 | + INTEL_UEVENT_CONSTRAINT(0x40d1, 0xf), | |
| 604 | + /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_MISS */ | |
| 605 | + INTEL_UEVENT_CONSTRAINT(0x01d2, 0xf), | |
| 606 | + /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT */ | |
| 607 | + INTEL_UEVENT_CONSTRAINT(0x02d2, 0xf), | |
| 608 | + /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM */ | |
| 609 | + INTEL_UEVENT_CONSTRAINT(0x01d3, 0xf), | |
| 610 | + INTEL_UEVENT_CONSTRAINT(0x04c8, 0xf), /* HLE_RETIRED.Abort */ | |
| 611 | + INTEL_UEVENT_CONSTRAINT(0x04c9, 0xf), /* RTM_RETIRED.Abort */ | |
| 612 | + | |
| 613 | + EVENT_CONSTRAINT_END | |
| 614 | +}; | |
| 615 | + | |
| 551 | 616 | struct event_constraint *intel_pebs_constraints(struct perf_event *event) |
| 552 | 617 | { |
| 553 | 618 | struct event_constraint *c; |
| @@ -588,6 +653,12 @@ void intel_pmu_pebs_disable(struct perf_event *event) · 34 unmodified lines | ||
| 588 | 653 | struct hw_perf_event *hwc = &event->hw; |
| 589 | 654 | |
| 590 | 655 | cpuc->pebs_enabled &= ~(1ULL << hwc->idx); |
| 656 | + | |
| 657 | + if (event->hw.constraint->flags & PERF_X86_EVENT_PEBS_LDLAT) | |
| 658 | + cpuc->pebs_enabled &= ~(1ULL << (hwc->idx + 32)); | |
| 659 | + else if (event->hw.constraint->flags & PERF_X86_EVENT_PEBS_ST) | |
| 660 | + cpuc->pebs_enabled &= ~(1ULL << 63); | |
| 661 | + | |
| 591 | 662 | if (cpuc->enabled) |
| 592 | 663 | wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled); |
| 593 | 664 | |
| @@ -697,6 +768,7 @@ static void __intel_pmu_pebs_event(struct perf_event *event, · 103 unmodified lines | ||
| 697 | 768 | */ |
| 698 | 769 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); |
| 699 | 770 | struct pebs_record_nhm *pebs = __pebs; |
| 771 | + struct pebs_record_hsw *pebs_hsw = __pebs; | |
| 700 | 772 | struct perf_sample_data data; |
| 701 | 773 | struct pt_regs regs; |
| 702 | 774 | u64 sample_type; |
| @@ -706,7 +778,8 @@ static void __intel_pmu_pebs_event(struct perf_event *event, · 3 unmodified lines | ||
| 706 | 778 | return; |
| 707 | 779 | |
| 708 | 780 | fll = event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT; |
| 709 | − fst = event->hw.flags & PERF_X86_EVENT_PEBS_ST; | |
| 781 | + fst = event->hw.flags & (PERF_X86_EVENT_PEBS_ST | | |
| 782 | + PERF_X86_EVENT_PEBS_ST_HSW); | |
| 710 | 783 | |
| 711 | 784 | perf_sample_data_init(&data, 0, event->hw.last_period); |
| 712 | 785 | |
| @@ -717,9 +790,6 @@ static void __intel_pmu_pebs_event(struct perf_event *event, · 4 unmodified lines | ||
| 717 | 790 | * if PEBS-LL or PreciseStore |
| 718 | 791 | */ |
| 719 | 792 | if (fll || fst) { |
| 720 | − if (sample_type & PERF_SAMPLE_ADDR) | |
| 721 | − data.addr = pebs->dla; | |
| 722 | − | |
| 723 | 793 | /* |
| 724 | 794 | * Use latency for weight (only avail with PEBS-LL) |
| 725 | 795 | */ |
| @@ -732,6 +802,9 @@ static void __intel_pmu_pebs_event(struct perf_event *event, · 6 unmodified lines | ||
| 732 | 802 | if (sample_type & PERF_SAMPLE_DATA_SRC) { |
| 733 | 803 | if (fll) |
| 734 | 804 | data.data_src.val = load_latency_data(pebs->dse); |
| 805 | + else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW) | |
| 806 | + data.data_src.val = | |
| 807 | + precise_store_data_hsw(pebs->dse); | |
| 735 | 808 | else |
| 736 | 809 | data.data_src.val = precise_store_data(pebs->dse); |
| 737 | 810 | } |
| @@ -753,11 +826,18 @@ static void __intel_pmu_pebs_event(struct perf_event *event, · 15 unmodified lines | ||
| 753 | 826 | regs.bp = pebs->bp; |
| 754 | 827 | regs.sp = pebs->sp; |
| 755 | 828 | |
| 756 | − if (event->attr.precise_ip > 1 && intel_pmu_pebs_fixup_ip(®s)) | |
| 829 | + if (event->attr.precise_ip > 1 && x86_pmu.intel_cap.pebs_format >= 2) { | |
| 830 | + regs.ip = pebs_hsw->real_ip; | |
| 831 | + regs.flags |= PERF_EFLAGS_EXACT; | |
| 832 | + } else if (event->attr.precise_ip > 1 && intel_pmu_pebs_fixup_ip(®s)) | |
| 757 | 833 | regs.flags |= PERF_EFLAGS_EXACT; |
| 758 | 834 | else |
| 759 | 835 | regs.flags &= ~PERF_EFLAGS_EXACT; |
| 760 | 836 | |
| 837 | + if ((event->attr.sample_type & PERF_SAMPLE_ADDR) && | |
| 838 | + x86_pmu.intel_cap.pebs_format >= 1) | |
| 839 | + data.addr = pebs->dla; | |
| 840 | + | |
| 761 | 841 | if (has_branch_stack(event)) |
| 762 | 842 | data.br_stack = &cpuc->lbr_stack; |
| 763 | 843 | |
| @@ -806,35 +886,22 @@ static void intel_pmu_drain_pebs_core(struct pt_regs *iregs) · 42 unmodified lines | ||
| 806 | 886 | __intel_pmu_pebs_event(event, iregs, at); |
| 807 | 887 | } |
| 808 | 888 | |
| 809 | −static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs) | |
| 889 | +static void __intel_pmu_drain_pebs_nhm(struct pt_regs *iregs, void *at, | |
| 890 | + void *top) | |
| 810 | 891 | { |
| 811 | 892 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); |
| 812 | 893 | struct debug_store *ds = cpuc->ds; |
| 813 | − struct pebs_record_nhm *at, *top; | |
| 814 | 894 | struct perf_event *event = NULL; |
| 815 | 895 | u64 status = 0; |
| 816 | − int bit, n; | |
| 817 | − | |
| 818 | − if (!x86_pmu.pebs_active) | |
| 819 | − return; | |
| 820 | − | |
| 821 | − at = (struct pebs_record_nhm *)(unsigned long)ds->pebs_buffer_base; | |
| 822 | − top = (struct pebs_record_nhm *)(unsigned long)ds->pebs_index; | |
| 896 | + int bit; | |
| 823 | 897 | |
| 824 | 898 | ds->pebs_index = ds->pebs_buffer_base; |
| 825 | 899 | |
| 826 | − n = top - at; | |
| 827 | − if (n <= 0) | |
| 828 | − return; | |
| 829 | − | |
| 830 | − /* | |
| 831 | − * Should not happen, we program the threshold at 1 and do not | |
| 832 | − * set a reset value. | |
| 833 | − */ | |
| 834 | − WARN_ONCE(n > x86_pmu.max_pebs_events, "Unexpected number of pebs records %d\n", n); | |
| 900 | + for (; at < top; at += x86_pmu.pebs_record_size) { | |
| 901 | + struct pebs_record_nhm *p = at; | |
| 835 | 902 | |
| 836 | − for ( ; at < top; at++) { | |
| 837 | − for_each_set_bit(bit, (unsigned long *)&at->status, x86_pmu.max_pebs_events) { | |
| 903 | + for_each_set_bit(bit, (unsigned long *)&p->status, | |
| 904 | + x86_pmu.max_pebs_events) { | |
| 838 | 905 | event = cpuc->events[bit]; |
| 839 | 906 | if (!test_bit(bit, cpuc->active_mask)) |
| 840 | 907 | continue; |
| @@ -857,6 +924,61 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs) · 16 unmodified lines | ||
| 857 | 924 | } |
| 858 | 925 | } |
| 859 | 926 | |
| 927 | +static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs) | |
| 928 | +{ | |
| 929 | + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | |
| 930 | + struct debug_store *ds = cpuc->ds; | |
| 931 | + struct pebs_record_nhm *at, *top; | |
| 932 | + int n; | |
| 933 | + | |
| 934 | + if (!x86_pmu.pebs_active) | |
| 935 | + return; | |
| 936 | + | |
| 937 | + at = (struct pebs_record_nhm *)(unsigned long)ds->pebs_buffer_base; | |
| 938 | + top = (struct pebs_record_nhm *)(unsigned long)ds->pebs_index; | |
| 939 | + | |
| 940 | + ds->pebs_index = ds->pebs_buffer_base; | |
| 941 | + | |
| 942 | + n = top - at; | |
| 943 | + if (n <= 0) | |
| 944 | + return; | |
| 945 | + | |
| 946 | + /* | |
| 947 | + * Should not happen, we program the threshold at 1 and do not | |
| 948 | + * set a reset value. | |
| 949 | + */ | |
| 950 | + WARN_ONCE(n > x86_pmu.max_pebs_events, | |
| 951 | + "Unexpected number of pebs records %d\n", n); | |
| 952 | + | |
| 953 | + return __intel_pmu_drain_pebs_nhm(iregs, at, top); | |
| 954 | +} | |
| 955 | + | |
| 956 | +static void intel_pmu_drain_pebs_hsw(struct pt_regs *iregs) | |
| 957 | +{ | |
| 958 | + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | |
| 959 | + struct debug_store *ds = cpuc->ds; | |
| 960 | + struct pebs_record_hsw *at, *top; | |
| 961 | + int n; | |
| 962 | + | |
| 963 | + if (!x86_pmu.pebs_active) | |
| 964 | + return; | |
| 965 | + | |
| 966 | + at = (struct pebs_record_hsw *)(unsigned long)ds->pebs_buffer_base; | |
| 967 | + top = (struct pebs_record_hsw *)(unsigned long)ds->pebs_index; | |
| 968 | + | |
| 969 | + n = top - at; | |
| 970 | + if (n <= 0) | |
| 971 | + return; | |
| 972 | + /* | |
| 973 | + * Should not happen, we program the threshold at 1 and do not | |
| 974 | + * set a reset value. | |
| 975 | + */ | |
| 976 | + WARN_ONCE(n > x86_pmu.max_pebs_events, | |
| 977 | + "Unexpected number of pebs records %d\n", n); | |
| 978 | + | |
| 979 | + return __intel_pmu_drain_pebs_nhm(iregs, at, top); | |
| 980 | +} | |
| 981 | + | |
| 860 | 982 | /* |
| 861 | 983 | * BTS, PEBS probe and setup |
| 862 | 984 | */ |
| @@ -888,6 +1010,12 @@ void intel_ds_init(void) · 25 unmodified lines | ||
| 888 | 1010 | x86_pmu.drain_pebs = intel_pmu_drain_pebs_nhm; |
| 889 | 1011 | break; |
| 890 | 1012 | |
| 1013 | + case 2: | |
| 1014 | + pr_cont("PEBS fmt2%c, ", pebs_type); | |
| 1015 | + x86_pmu.pebs_record_size = sizeof(struct pebs_record_hsw); | |
| 1016 | + x86_pmu.drain_pebs = intel_pmu_drain_pebs_hsw; | |
| 1017 | + break; | |
| 1018 | + | |
| 891 | 1019 | default: |
| 892 | 1020 | printk(KERN_CONT "no PEBS fmt%d%c, ", format, pebs_type); |
| 893 | 1021 | x86_pmu.pebs = 0; |
| @@ -12,6 +12,16 @@ enum { · 11 unmodified lines | ||
| 12 | 12 | LBR_FORMAT_LIP = 0x01, |
| 13 | 13 | LBR_FORMAT_EIP = 0x02, |
| 14 | 14 | LBR_FORMAT_EIP_FLAGS = 0x03, |
| 15 | + LBR_FORMAT_EIP_FLAGS2 = 0x04, | |
| 16 | + LBR_FORMAT_MAX_KNOWN = LBR_FORMAT_EIP_FLAGS2, | |
| 17 | +}; | |
| 18 | + | |
| 19 | +static enum { | |
| 20 | + LBR_EIP_FLAGS = 1, | |
| 21 | + LBR_TSX = 2, | |
| 22 | +} lbr_desc[LBR_FORMAT_MAX_KNOWN + 1] = { | |
| 23 | + [LBR_FORMAT_EIP_FLAGS] = LBR_EIP_FLAGS, | |
| 24 | + [LBR_FORMAT_EIP_FLAGS2] = LBR_EIP_FLAGS | LBR_TSX, | |
| 15 | 25 | }; |
| 16 | 26 | |
| 17 | 27 | /* |
| @@ -56,6 +66,8 @@ enum { · 38 unmodified lines | ||
| 56 | 66 | LBR_FAR) |
| 57 | 67 | |
| 58 | 68 | #define LBR_FROM_FLAG_MISPRED (1ULL << 63) |
| 69 | +#define LBR_FROM_FLAG_IN_TX (1ULL << 62) | |
| 70 | +#define LBR_FROM_FLAG_ABORT (1ULL << 61) | |
| 59 | 71 | |
| 60 | 72 | #define for_each_branch_sample_type(x) \ |
| 61 | 73 | for ((x) = PERF_SAMPLE_BRANCH_USER; \ |
| @@ -81,9 +93,13 @@ enum { · 19 unmodified lines | ||
| 81 | 93 | X86_BR_JMP = 1 << 9, /* jump */ |
| 82 | 94 | X86_BR_IRQ = 1 << 10,/* hw interrupt or trap or fault */ |
| 83 | 95 | X86_BR_IND_CALL = 1 << 11,/* indirect calls */ |
| 96 | + X86_BR_ABORT = 1 << 12,/* transaction abort */ | |
| 97 | + X86_BR_IN_TX = 1 << 13,/* in transaction */ | |
| 98 | + X86_BR_NO_TX = 1 << 14,/* not in transaction */ | |
| 84 | 99 | }; |
| 85 | 100 | |
| 86 | 101 | #define X86_BR_PLM (X86_BR_USER | X86_BR_KERNEL) |
| 102 | +#define X86_BR_ANYTX (X86_BR_NO_TX | X86_BR_IN_TX) | |
| 87 | 103 | |
| 88 | 104 | #define X86_BR_ANY \ |
| 89 | 105 | (X86_BR_CALL |\ |
| @@ -95,6 +111,7 @@ enum { · 5 unmodified lines | ||
| 95 | 111 | X86_BR_JCC |\ |
| 96 | 112 | X86_BR_JMP |\ |
| 97 | 113 | X86_BR_IRQ |\ |
| 114 | + X86_BR_ABORT |\ | |
| 98 | 115 | X86_BR_IND_CALL) |
| 99 | 116 | |
| 100 | 117 | #define X86_BR_ALL (X86_BR_PLM | X86_BR_ANY) |
| @@ -270,21 +287,31 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc) · 169 unmodified lines | ||
| 270 | 287 | |
| 271 | 288 | for (i = 0; i < x86_pmu.lbr_nr; i++) { |
| 272 | 289 | unsigned long lbr_idx = (tos - i) & mask; |
| 273 | − u64 from, to, mis = 0, pred = 0; | |
| 290 | + u64 from, to, mis = 0, pred = 0, in_tx = 0, abort = 0; | |
| 291 | + int skip = 0; | |
| 292 | + int lbr_flags = lbr_desc[lbr_format]; | |
| 274 | 293 | |
| 275 | 294 | rdmsrl(x86_pmu.lbr_from + lbr_idx, from); |
| 276 | 295 | rdmsrl(x86_pmu.lbr_to + lbr_idx, to); |
| 277 | 296 | |
| 278 | − if (lbr_format == LBR_FORMAT_EIP_FLAGS) { | |
| 297 | + if (lbr_flags & LBR_EIP_FLAGS) { | |
| 279 | 298 | mis = !!(from & LBR_FROM_FLAG_MISPRED); |
| 280 | 299 | pred = !mis; |
| 281 | − from = (u64)((((s64)from) << 1) >> 1); | |
| 300 | + skip = 1; | |
| 301 | + } | |
| 302 | + if (lbr_flags & LBR_TSX) { | |
| 303 | + in_tx = !!(from & LBR_FROM_FLAG_IN_TX); | |
| 304 | + abort = !!(from & LBR_FROM_FLAG_ABORT); | |
| 305 | + skip = 3; | |
| 282 | 306 | } |
| 307 | + from = (u64)((((s64)from) << skip) >> skip); | |
| 283 | 308 | |
| 284 | 309 | cpuc->lbr_entries[i].from = from; |
| 285 | 310 | cpuc->lbr_entries[i].to = to; |
| 286 | 311 | cpuc->lbr_entries[i].mispred = mis; |
| 287 | 312 | cpuc->lbr_entries[i].predicted = pred; |
| 313 | + cpuc->lbr_entries[i].in_tx = in_tx; | |
| 314 | + cpuc->lbr_entries[i].abort = abort; | |
| 288 | 315 | cpuc->lbr_entries[i].reserved = 0; |
| 289 | 316 | } |
| 290 | 317 | cpuc->lbr_stack.nr = i; |
| @@ -310,7 +337,7 @@ void intel_pmu_lbr_read(void) · 19 unmodified lines | ||
| 310 | 337 | * - in case there is no HW filter |
| 311 | 338 | * - in case the HW filter has errata or limitations |
| 312 | 339 | */ |
| 313 | −static int intel_pmu_setup_sw_lbr_filter(struct perf_event *event) | |
| 340 | +static void intel_pmu_setup_sw_lbr_filter(struct perf_event *event) | |
| 314 | 341 | { |
| 315 | 342 | u64 br_type = event->attr.branch_sample_type; |
| 316 | 343 | int mask = 0; |
| @@ -318,11 +345,8 @@ static int intel_pmu_setup_sw_lbr_filter(struct perf_event *event) · 1 unmodified line | ||
| 318 | 345 | if (br_type & PERF_SAMPLE_BRANCH_USER) |
| 319 | 346 | mask |= X86_BR_USER; |
| 320 | 347 | |
| 321 | − if (br_type & PERF_SAMPLE_BRANCH_KERNEL) { | |
| 322 | − if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) | |
| 323 | − return -EACCES; | |
| 348 | + if (br_type & PERF_SAMPLE_BRANCH_KERNEL) | |
| 324 | 349 | mask |= X86_BR_KERNEL; |
| 325 | − } | |
| 326 | 350 | |
| 327 | 351 | /* we ignore BRANCH_HV here */ |
| 328 | 352 | |
| @@ -337,13 +361,21 @@ static int intel_pmu_setup_sw_lbr_filter(struct perf_event *event) · 8 unmodified lines | ||
| 337 | 361 | |
| 338 | 362 | if (br_type & PERF_SAMPLE_BRANCH_IND_CALL) |
| 339 | 363 | mask |= X86_BR_IND_CALL; |
| 364 | + | |
| 365 | + if (br_type & PERF_SAMPLE_BRANCH_ABORT_TX) | |
| 366 | + mask |= X86_BR_ABORT; | |
| 367 | + | |
| 368 | + if (br_type & PERF_SAMPLE_BRANCH_IN_TX) | |
| 369 | + mask |= X86_BR_IN_TX; | |
| 370 | + | |
| 371 | + if (br_type & PERF_SAMPLE_BRANCH_NO_TX) | |
| 372 | + mask |= X86_BR_NO_TX; | |
| 373 | + | |
| 340 | 374 | /* |
| 341 | 375 | * stash actual user request into reg, it may |
| 342 | 376 | * be used by fixup code for some CPU |
| 343 | 377 | */ |
| 344 | 378 | event->hw.branch_reg.reg = mask; |
| 345 | − | |
| 346 | − return 0; | |
| 347 | 379 | } |
| 348 | 380 | |
| 349 | 381 | /* |
| @@ -391,9 +423,7 @@ int intel_pmu_setup_lbr_filter(struct perf_event *event) · 41 unmodified lines | ||
| 391 | 423 | /* |
| 392 | 424 | * setup SW LBR filter |
| 393 | 425 | */ |
| 394 | − ret = intel_pmu_setup_sw_lbr_filter(event); | |
| 395 | − if (ret) | |
| 396 | − return ret; | |
| 426 | + intel_pmu_setup_sw_lbr_filter(event); | |
| 397 | 427 | |
| 398 | 428 | /* |
| 399 | 429 | * setup HW LBR filter, if any |
| @@ -415,7 +445,7 @@ int intel_pmu_setup_lbr_filter(struct perf_event *event) · 15 unmodified lines | ||
| 415 | 445 | * decoded (e.g., text page not present), then X86_BR_NONE is |
| 416 | 446 | * returned. |
| 417 | 447 | */ |
| 418 | −static int branch_type(unsigned long from, unsigned long to) | |
| 448 | +static int branch_type(unsigned long from, unsigned long to, int abort) | |
| 419 | 449 | { |
| 420 | 450 | struct insn insn; |
| 421 | 451 | void *addr; |
| @@ -435,6 +465,9 @@ static int branch_type(unsigned long from, unsigned long to) · 13 unmodified lines | ||
| 435 | 465 | if (from == 0 || to == 0) |
| 436 | 466 | return X86_BR_NONE; |
| 437 | 467 | |
| 468 | + if (abort) | |
| 469 | + return X86_BR_ABORT | to_plm; | |
| 470 | + | |
| 438 | 471 | if (from_plm == X86_BR_USER) { |
| 439 | 472 | /* |
| 440 | 473 | * can happen if measuring at the user level only |
| @@ -581,7 +614,13 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc) · 140 unmodified lines | ||
| 581 | 614 | from = cpuc->lbr_entries[i].from; |
| 582 | 615 | to = cpuc->lbr_entries[i].to; |
| 583 | 616 | |
| 584 | − type = branch_type(from, to); | |
| 617 | + type = branch_type(from, to, cpuc->lbr_entries[i].abort); | |
| 618 | + if (type != X86_BR_NONE && (br_sel & X86_BR_ANYTX)) { | |
| 619 | + if (cpuc->lbr_entries[i].in_tx) | |
| 620 | + type |= X86_BR_IN_TX; | |
| 621 | + else | |
| 622 | + type |= X86_BR_NO_TX; | |
| 623 | + } | |
| 585 | 624 | |
| 586 | 625 | /* if type does not correspond, then discard */ |
| 587 | 626 | if (type == X86_BR_NONE || (br_sel & type) != type) { |
| @@ -536,7 +536,7 @@ __snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *eve · 535 unmodified lines | ||
| 536 | 536 | if (!uncore_box_is_fake(box)) |
| 537 | 537 | reg1->alloc |= alloc; |
| 538 | 538 | |
| 539 | − return 0; | |
| 539 | + return NULL; | |
| 540 | 540 | fail: |
| 541 | 541 | for (; i >= 0; i--) { |
| 542 | 542 | if (alloc & (0x1 << i)) |
| @@ -644,7 +644,7 @@ snbep_pcu_get_constraint(struct intel_uncore_box *box, struct perf_event *event) · 101 unmodified lines | ||
| 644 | 644 | (!uncore_box_is_fake(box) && reg1->alloc)) |
| 645 | 645 | return NULL; |
| 646 | 646 | again: |
| 647 | − mask = 0xff << (idx * 8); | |
| 647 | + mask = 0xffULL << (idx * 8); | |
| 648 | 648 | raw_spin_lock_irqsave(&er->lock, flags); |
| 649 | 649 | if (!__BITS_VALUE(atomic_read(&er->ref), idx, 8) || |
| 650 | 650 | !((config1 ^ er->config) & mask)) { |
| @@ -1923,7 +1923,7 @@ static u64 nhmex_mbox_alter_er(struct perf_event *event, int new_idx, bool modif · 1272 unmodified lines | ||
| 1923 | 1923 | { |
| 1924 | 1924 | struct hw_perf_event *hwc = &event->hw; |
| 1925 | 1925 | struct hw_perf_event_extra *reg1 = &hwc->extra_reg; |
| 1926 | − int idx, orig_idx = __BITS_VALUE(reg1->idx, 0, 8); | |
| 1926 | + u64 idx, orig_idx = __BITS_VALUE(reg1->idx, 0, 8); | |
| 1927 | 1927 | u64 config = reg1->config; |
| 1928 | 1928 | |
| 1929 | 1929 | /* get the non-shared control bits and shift them */ |
| @@ -2723,15 +2723,16 @@ static void uncore_put_event_constraint(struct intel_uncore_box *box, struct per · 793 unmodified lines | ||
| 2723 | 2723 | static int uncore_assign_events(struct intel_uncore_box *box, int assign[], int n) |
| 2724 | 2724 | { |
| 2725 | 2725 | unsigned long used_mask[BITS_TO_LONGS(UNCORE_PMC_IDX_MAX)]; |
| 2726 | − struct event_constraint *c, *constraints[UNCORE_PMC_IDX_MAX]; | |
| 2726 | + struct event_constraint *c; | |
| 2727 | 2727 | int i, wmin, wmax, ret = 0; |
| 2728 | 2728 | struct hw_perf_event *hwc; |
| 2729 | 2729 | |
| 2730 | 2730 | bitmap_zero(used_mask, UNCORE_PMC_IDX_MAX); |
| 2731 | 2731 | |
| 2732 | 2732 | for (i = 0, wmin = UNCORE_PMC_IDX_MAX, wmax = 0; i < n; i++) { |
| 2733 | + hwc = &box->event_list[i]->hw; | |
| 2733 | 2734 | c = uncore_get_event_constraint(box, box->event_list[i]); |
| 2734 | − constraints[i] = c; | |
| 2735 | + hwc->constraint = c; | |
| 2735 | 2736 | wmin = min(wmin, c->weight); |
| 2736 | 2737 | wmax = max(wmax, c->weight); |
| 2737 | 2738 | } |
| @@ -2739,7 +2740,7 @@ static int uncore_assign_events(struct intel_uncore_box *box, int assign[], int · 1 unmodified line | ||
| 2739 | 2740 | /* fastpath, try to reuse previous register */ |
| 2740 | 2741 | for (i = 0; i < n; i++) { |
| 2741 | 2742 | hwc = &box->event_list[i]->hw; |
| 2742 | − c = constraints[i]; | |
| 2743 | + c = hwc->constraint; | |
| 2743 | 2744 | |
| 2744 | 2745 | /* never assigned */ |
| 2745 | 2746 | if (hwc->idx == -1) |
| @@ -2759,7 +2760,8 @@ static int uncore_assign_events(struct intel_uncore_box *box, int assign[], int · 13 unmodified lines | ||
| 2759 | 2760 | } |
| 2760 | 2761 | /* slow path */ |
| 2761 | 2762 | if (i != n) |
| 2762 | − ret = perf_assign_events(constraints, n, wmin, wmax, assign); | |
| 2763 | + ret = perf_assign_events(box->event_list, n, | |
| 2764 | + wmin, wmax, assign); | |
| 2763 | 2765 | |
| 2764 | 2766 | if (!assign || ret) { |
| 2765 | 2767 | for (i = 0; i < n; i++) |
| @@ -337,10 +337,10 @@ · 336 unmodified lines | ||
| 337 | 337 | NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK) |
| 338 | 338 | |
| 339 | 339 | #define NHMEX_M_PMON_ZDP_CTL_FVC_MASK (((1 << 11) - 1) | (1 << 23)) |
| 340 | −#define NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7 << (11 + 3 * (n))) | |
| 340 | +#define NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7ULL << (11 + 3 * (n))) | |
| 341 | 341 | |
| 342 | 342 | #define WSMEX_M_PMON_ZDP_CTL_FVC_MASK (((1 << 12) - 1) | (1 << 24)) |
| 343 | −#define WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7 << (12 + 3 * (n))) | |
| 343 | +#define WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7ULL << (12 + 3 * (n))) | |
| 344 | 344 | |
| 345 | 345 | /* |
| 346 | 346 | * use the 9~13 bits to select event If the 7th bit is not set, |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <linux/kprobes.h> |
| 15 | 15 | #include <linux/kdebug.h> |
| 16 | 16 | #include <linux/nmi.h> |
| 17 | +#include <linux/debugfs.h> | |
| 17 | 18 | #include <linux/delay.h> |
| 18 | 19 | #include <linux/hardirq.h> |
| 19 | 20 | #include <linux/slab.h> |
| @@ -29,6 +30,9 @@ · 9 unmodified lines | ||
| 29 | 30 | #include <asm/nmi.h> |
| 30 | 31 | #include <asm/x86_init.h> |
| 31 | 32 | |
| 33 | +#define CREATE_TRACE_POINTS | |
| 34 | +#include <trace/events/nmi.h> | |
| 35 | + | |
| 32 | 36 | struct nmi_desc { |
| 33 | 37 | spinlock_t lock; |
| 34 | 38 | struct list_head head; |
| @@ -82,6 +86,15 @@ __setup("unknown_nmi_panic", setup_unknown_nmi_panic); · 47 unmodified lines | ||
| 82 | 86 | |
| 83 | 87 | #define nmi_to_desc(type) (&nmi_desc[type]) |
| 84 | 88 | |
| 89 | +static u64 nmi_longest_ns = 1 * NSEC_PER_MSEC; | |
| 90 | +static int __init nmi_warning_debugfs(void) | |
| 91 | +{ | |
| 92 | + debugfs_create_u64("nmi_longest_ns", 0644, | |
| 93 | + arch_debugfs_dir, &nmi_longest_ns); | |
| 94 | + return 0; | |
| 95 | +} | |
| 96 | +fs_initcall(nmi_warning_debugfs); | |
| 97 | + | |
| 85 | 98 | static int __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2b) |
| 86 | 99 | { |
| 87 | 100 | struct nmi_desc *desc = nmi_to_desc(type); |
| @@ -96,8 +109,27 @@ static int __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2 · 8 unmodified lines | ||
| 96 | 109 | * can be latched at any given time. Walk the whole list |
| 97 | 110 | * to handle those situations. |
| 98 | 111 | */ |
| 99 | − list_for_each_entry_rcu(a, &desc->head, list) | |
| 100 | − handled += a->handler(type, regs); | |
| 112 | + list_for_each_entry_rcu(a, &desc->head, list) { | |
| 113 | + u64 before, delta, whole_msecs; | |
| 114 | + int decimal_msecs, thishandled; | |
| 115 | + | |
| 116 | + before = local_clock(); | |
| 117 | + thishandled = a->handler(type, regs); | |
| 118 | + handled += thishandled; | |
| 119 | + delta = local_clock() - before; | |
| 120 | + trace_nmi_handler(a->handler, (int)delta, thishandled); | |
| 121 | + | |
| 122 | + if (delta < nmi_longest_ns) | |
| 123 | + continue; | |
| 124 | + | |
| 125 | + nmi_longest_ns = delta; | |
| 126 | + whole_msecs = do_div(delta, (1000 * 1000)); | |
| 127 | + decimal_msecs = do_div(delta, 1000) % 1000; | |
| 128 | + printk_ratelimited(KERN_INFO | |
| 129 | + "INFO: NMI handler (%ps) took too long to run: " | |
| 130 | + "%lld.%03d msecs\n", a->handler, whole_msecs, | |
| 131 | + decimal_msecs); | |
| 132 | + } | |
| 101 | 133 | |
| 102 | 134 | rcu_read_unlock(); |
| 103 | 135 | |
| @@ -43,12 +43,6 @@ · 42 unmodified lines | ||
| 43 | 43 | |
| 44 | 44 | #include <asm/sigframe.h> |
| 45 | 45 | |
| 46 | −#ifdef CONFIG_X86_32 | |
| 47 | −# define FIX_EFLAGS (__FIX_EFLAGS | X86_EFLAGS_RF) | |
| 48 | −#else | |
| 49 | −# define FIX_EFLAGS __FIX_EFLAGS | |
| 50 | −#endif | |
| 51 | − | |
| 52 | 46 | #define COPY(x) do { \ |
| 53 | 47 | get_user_ex(regs->x, &sc->x); \ |
| 54 | 48 | } while (0) |
| @@ -668,15 +662,17 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs) · 613 unmodified lines | ||
| 668 | 662 | if (!failed) { |
| 669 | 663 | /* |
| 670 | 664 | * Clear the direction flag as per the ABI for function entry. |
| 671 | − */ | |
| 672 | − regs->flags &= ~X86_EFLAGS_DF; | |
| 673 | − /* | |
| 665 | + * | |
| 666 | + * Clear RF when entering the signal handler, because | |
| 667 | + * it might disable possible debug exception from the | |
| 668 | + * signal handler. | |
| 669 | + * | |
| 674 | 670 | * Clear TF when entering the signal handler, but |
| 675 | 671 | * notify any tracer that was single-stepping it. |
| 676 | 672 | * The tracer may want to single-step inside the |
| 677 | 673 | * handler too. |
| 678 | 674 | */ |
| 679 | − regs->flags &= ~X86_EFLAGS_TF; | |
| 675 | + regs->flags &= ~(X86_EFLAGS_DF|X86_EFLAGS_RF|X86_EFLAGS_TF); | |
| 680 | 676 | } |
| 681 | 677 | signal_setup_done(failed, ksig, test_thread_flag(TIF_SINGLESTEP)); |
| 682 | 678 | } |
| @@ -99,7 +99,7 @@ struct ivhd_header { · 98 unmodified lines | ||
| 99 | 99 | u64 mmio_phys; |
| 100 | 100 | u16 pci_seg; |
| 101 | 101 | u16 info; |
| 102 | − u32 reserved; | |
| 102 | + u32 efr; | |
| 103 | 103 | } __attribute__((packed)); |
| 104 | 104 | |
| 105 | 105 | /* |
| @@ -154,6 +154,7 @@ bool amd_iommu_iotlb_sup __read_mostly = true; · 48 unmodified lines | ||
| 154 | 154 | u32 amd_iommu_max_pasids __read_mostly = ~0; |
| 155 | 155 | |
| 156 | 156 | bool amd_iommu_v2_present __read_mostly; |
| 157 | +bool amd_iommu_pc_present __read_mostly; | |
| 157 | 158 | |
| 158 | 159 | bool amd_iommu_force_isolation __read_mostly; |
| 159 | 160 | |
| @@ -369,23 +370,23 @@ static void iommu_disable(struct amd_iommu *iommu) · 209 unmodified lines | ||
| 369 | 370 | * mapping and unmapping functions for the IOMMU MMIO space. Each AMD IOMMU in |
| 370 | 371 | * the system has one. |
| 371 | 372 | */ |
| 372 | −static u8 __iomem * __init iommu_map_mmio_space(u64 address) | |
| 373 | +static u8 __iomem * __init iommu_map_mmio_space(u64 address, u64 end) | |
| 373 | 374 | { |
| 374 | − if (!request_mem_region(address, MMIO_REGION_LENGTH, "amd_iommu")) { | |
| 375 | − pr_err("AMD-Vi: Can not reserve memory region %llx for mmio\n", | |
| 376 | − address); | |
| 375 | + if (!request_mem_region(address, end, "amd_iommu")) { | |
| 376 | + pr_err("AMD-Vi: Can not reserve memory region %llx-%llx for mmio\n", | |
| 377 | + address, end); | |
| 377 | 378 | pr_err("AMD-Vi: This is a BIOS bug. Please contact your hardware vendor\n"); |
| 378 | 379 | return NULL; |
| 379 | 380 | } |
| 380 | 381 | |
| 381 | − return (u8 __iomem *)ioremap_nocache(address, MMIO_REGION_LENGTH); | |
| 382 | + return (u8 __iomem *)ioremap_nocache(address, end); | |
| 382 | 383 | } |
| 383 | 384 | |
| 384 | 385 | static void __init iommu_unmap_mmio_space(struct amd_iommu *iommu) |
| 385 | 386 | { |
| 386 | 387 | if (iommu->mmio_base) |
| 387 | 388 | iounmap(iommu->mmio_base); |
| 388 | − release_mem_region(iommu->mmio_phys, MMIO_REGION_LENGTH); | |
| 389 | + release_mem_region(iommu->mmio_phys, iommu->mmio_phys_end); | |
| 389 | 390 | } |
| 390 | 391 | |
| 391 | 392 | /**************************************************************************** |
| @@ -1085,7 +1086,18 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) · 693 unmodified lines | ||
| 1085 | 1086 | iommu->cap_ptr = h->cap_ptr; |
| 1086 | 1087 | iommu->pci_seg = h->pci_seg; |
| 1087 | 1088 | iommu->mmio_phys = h->mmio_phys; |
| 1088 | − iommu->mmio_base = iommu_map_mmio_space(h->mmio_phys); | |
| 1089 | + | |
| 1090 | + /* Check if IVHD EFR contains proper max banks/counters */ | |
| 1091 | + if ((h->efr != 0) && | |
| 1092 | + ((h->efr & (0xF << 13)) != 0) && | |
| 1093 | + ((h->efr & (0x3F << 17)) != 0)) { | |
| 1094 | + iommu->mmio_phys_end = MMIO_REG_END_OFFSET; | |
| 1095 | + } else { | |
| 1096 | + iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET; | |
| 1097 | + } | |
| 1098 | + | |
| 1099 | + iommu->mmio_base = iommu_map_mmio_space(iommu->mmio_phys, | |
| 1100 | + iommu->mmio_phys_end); | |
| 1089 | 1101 | if (!iommu->mmio_base) |
| 1090 | 1102 | return -ENOMEM; |
| 1091 | 1103 | |
| @@ -1160,6 +1172,33 @@ static int __init init_iommu_all(struct acpi_table_header *table) · 68 unmodified lines | ||
| 1160 | 1172 | return 0; |
| 1161 | 1173 | } |
| 1162 | 1174 | |
| 1175 | + | |
| 1176 | +static void init_iommu_perf_ctr(struct amd_iommu *iommu) | |
| 1177 | +{ | |
| 1178 | + u64 val = 0xabcd, val2 = 0; | |
| 1179 | + | |
| 1180 | + if (!iommu_feature(iommu, FEATURE_PC)) | |
| 1181 | + return; | |
| 1182 | + | |
| 1183 | + amd_iommu_pc_present = true; | |
| 1184 | + | |
| 1185 | + /* Check if the performance counters can be written to */ | |
| 1186 | + if ((0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val, true)) || | |
| 1187 | + (0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val2, false)) || | |
| 1188 | + (val != val2)) { | |
| 1189 | + pr_err("AMD-Vi: Unable to write to IOMMU perf counter.\n"); | |
| 1190 | + amd_iommu_pc_present = false; | |
| 1191 | + return; | |
| 1192 | + } | |
| 1193 | + | |
| 1194 | + pr_info("AMD-Vi: IOMMU performance counters supported\n"); | |
| 1195 | + | |
| 1196 | + val = readl(iommu->mmio_base + MMIO_CNTR_CONF_OFFSET); | |
| 1197 | + iommu->max_banks = (u8) ((val >> 12) & 0x3f); | |
| 1198 | + iommu->max_counters = (u8) ((val >> 7) & 0xf); | |
| 1199 | +} | |
| 1200 | + | |
| 1201 | + | |
| 1163 | 1202 | static int iommu_init_pci(struct amd_iommu *iommu) |
| 1164 | 1203 | { |
| 1165 | 1204 | int cap_ptr = iommu->cap_ptr; |
| @@ -1226,6 +1265,8 @@ static int iommu_init_pci(struct amd_iommu *iommu) · 60 unmodified lines | ||
| 1226 | 1265 | if (iommu->cap & (1UL << IOMMU_CAP_NPCACHE)) |
| 1227 | 1266 | amd_iommu_np_cache = true; |
| 1228 | 1267 | |
| 1268 | + init_iommu_perf_ctr(iommu); | |
| 1269 | + | |
| 1229 | 1270 | if (is_rd890_iommu(iommu->dev)) { |
| 1230 | 1271 | int i, j; |
| 1231 | 1272 | |
| @@ -1278,7 +1319,7 @@ static void print_iommu_info(void) · 46 unmodified lines | ||
| 1278 | 1319 | if (iommu_feature(iommu, (1ULL << i))) |
| 1279 | 1320 | pr_cont(" %s", feat_str[i]); |
| 1280 | 1321 | } |
| 1281 | − pr_cont("\n"); | |
| 1322 | + pr_cont("\n"); | |
| 1282 | 1323 | } |
| 1283 | 1324 | } |
| 1284 | 1325 | if (irq_remapping_enabled) |
| @@ -2232,3 +2273,84 @@ bool amd_iommu_v2_supported(void) · 947 unmodified lines | ||
| 2232 | 2273 | return amd_iommu_v2_present; |
| 2233 | 2274 | } |
| 2234 | 2275 | EXPORT_SYMBOL(amd_iommu_v2_supported); |
| 2276 | + | |
| 2277 | +/**************************************************************************** | |
| 2278 | + * | |
| 2279 | + * IOMMU EFR Performance Counter support functionality. This code allows | |
| 2280 | + * access to the IOMMU PC functionality. | |
| 2281 | + * | |
| 2282 | + ****************************************************************************/ | |
| 2283 | + | |
| 2284 | +u8 amd_iommu_pc_get_max_banks(u16 devid) | |
| 2285 | +{ | |
| 2286 | + struct amd_iommu *iommu; | |
| 2287 | + u8 ret = 0; | |
| 2288 | + | |
| 2289 | + /* locate the iommu governing the devid */ | |
| 2290 | + iommu = amd_iommu_rlookup_table[devid]; | |
| 2291 | + if (iommu) | |
| 2292 | + ret = iommu->max_banks; | |
| 2293 | + | |
| 2294 | + return ret; | |
| 2295 | +} | |
| 2296 | +EXPORT_SYMBOL(amd_iommu_pc_get_max_banks); | |
| 2297 | + | |
| 2298 | +bool amd_iommu_pc_supported(void) | |
| 2299 | +{ | |
| 2300 | + return amd_iommu_pc_present; | |
| 2301 | +} | |
| 2302 | +EXPORT_SYMBOL(amd_iommu_pc_supported); | |
| 2303 | + | |
| 2304 | +u8 amd_iommu_pc_get_max_counters(u16 devid) | |
| 2305 | +{ | |
| 2306 | + struct amd_iommu *iommu; | |
| 2307 | + u8 ret = 0; | |
| 2308 | + | |
| 2309 | + /* locate the iommu governing the devid */ | |
| 2310 | + iommu = amd_iommu_rlookup_table[devid]; | |
| 2311 | + if (iommu) | |
| 2312 | + ret = iommu->max_counters; | |
| 2313 | + | |
| 2314 | + return ret; | |
| 2315 | +} | |
| 2316 | +EXPORT_SYMBOL(amd_iommu_pc_get_max_counters); | |
| 2317 | + | |
| 2318 | +int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn, | |
| 2319 | + u64 *value, bool is_write) | |
| 2320 | +{ | |
| 2321 | + struct amd_iommu *iommu; | |
| 2322 | + u32 offset; | |
| 2323 | + u32 max_offset_lim; | |
| 2324 | + | |
| 2325 | + /* Make sure the IOMMU PC resource is available */ | |
| 2326 | + if (!amd_iommu_pc_present) | |
| 2327 | + return -ENODEV; | |
| 2328 | + | |
| 2329 | + /* Locate the iommu associated with the device ID */ | |
| 2330 | + iommu = amd_iommu_rlookup_table[devid]; | |
| 2331 | + | |
| 2332 | + /* Check for valid iommu and pc register indexing */ | |
| 2333 | + if (WARN_ON((iommu == NULL) || (fxn > 0x28) || (fxn & 7))) | |
| 2334 | + return -ENODEV; | |
| 2335 | + | |
| 2336 | + offset = (u32)(((0x40|bank) << 12) | (cntr << 8) | fxn); | |
| 2337 | + | |
| 2338 | + /* Limit the offset to the hw defined mmio region aperture */ | |
| 2339 | + max_offset_lim = (u32)(((0x40|iommu->max_banks) << 12) | | |
| 2340 | + (iommu->max_counters << 8) | 0x28); | |
| 2341 | + if ((offset < MMIO_CNTR_REG_OFFSET) || | |
| 2342 | + (offset > max_offset_lim)) | |
| 2343 | + return -EINVAL; | |
| 2344 | + | |
| 2345 | + if (is_write) { | |
| 2346 | + writel((u32)*value, iommu->mmio_base + offset); | |
| 2347 | + writel((*value >> 32), iommu->mmio_base + offset + 4); | |
| 2348 | + } else { | |
| 2349 | + *value = readl(iommu->mmio_base + offset + 4); | |
| 2350 | + *value <<= 32; | |
| 2351 | + *value = readl(iommu->mmio_base + offset); | |
| 2352 | + } | |
| 2353 | + | |
| 2354 | + return 0; | |
| 2355 | +} | |
| 2356 | +EXPORT_SYMBOL(amd_iommu_pc_get_set_reg_val); | |
| @@ -56,6 +56,13 @@ extern int amd_iommu_domain_set_gcr3(struct iommu_domain *dom, int pasid, · 55 unmodified lines | ||
| 56 | 56 | extern int amd_iommu_domain_clear_gcr3(struct iommu_domain *dom, int pasid); |
| 57 | 57 | extern struct iommu_domain *amd_iommu_get_v2_domain(struct pci_dev *pdev); |
| 58 | 58 | |
| 59 | +/* IOMMU Performance Counter functions */ | |
| 60 | +extern bool amd_iommu_pc_supported(void); | |
| 61 | +extern u8 amd_iommu_pc_get_max_banks(u16 devid); | |
| 62 | +extern u8 amd_iommu_pc_get_max_counters(u16 devid); | |
| 63 | +extern int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn, | |
| 64 | + u64 *value, bool is_write); | |
| 65 | + | |
| 59 | 66 | #define PPR_SUCCESS 0x0 |
| 60 | 67 | #define PPR_INVALID 0x1 |
| 61 | 68 | #define PPR_FAILURE 0xf |
| @@ -38,9 +38,6 @@ · 37 unmodified lines | ||
| 38 | 38 | #define ALIAS_TABLE_ENTRY_SIZE 2 |
| 39 | 39 | #define RLOOKUP_TABLE_ENTRY_SIZE (sizeof(void *)) |
| 40 | 40 | |
| 41 | −/* Length of the MMIO region for the AMD IOMMU */ | |
| 42 | −#define MMIO_REGION_LENGTH 0x4000 | |
| 43 | − | |
| 44 | 41 | /* Capability offsets used by the driver */ |
| 45 | 42 | #define MMIO_CAP_HDR_OFFSET 0x00 |
| 46 | 43 | #define MMIO_RANGE_OFFSET 0x0c |
| @@ -78,6 +75,10 @@ · 31 unmodified lines | ||
| 78 | 75 | #define MMIO_STATUS_OFFSET 0x2020 |
| 79 | 76 | #define MMIO_PPR_HEAD_OFFSET 0x2030 |
| 80 | 77 | #define MMIO_PPR_TAIL_OFFSET 0x2038 |
| 78 | +#define MMIO_CNTR_CONF_OFFSET 0x4000 | |
| 79 | +#define MMIO_CNTR_REG_OFFSET 0x40000 | |
| 80 | +#define MMIO_REG_END_OFFSET 0x80000 | |
| 81 | + | |
| 81 | 82 | |
| 82 | 83 | |
| 83 | 84 | /* Extended Feature Bits */ |
| @@ -507,6 +508,10 @@ struct amd_iommu { · 423 unmodified lines | ||
| 507 | 508 | |
| 508 | 509 | /* physical address of MMIO space */ |
| 509 | 510 | u64 mmio_phys; |
| 511 | + | |
| 512 | + /* physical end address of MMIO space */ | |
| 513 | + u64 mmio_phys_end; | |
| 514 | + | |
| 510 | 515 | /* virtual address of MMIO space */ |
| 511 | 516 | u8 __iomem *mmio_base; |
| 512 | 517 | |
| @@ -584,6 +589,10 @@ struct amd_iommu { · 71 unmodified lines | ||
| 584 | 589 | |
| 585 | 590 | /* The l2 indirect registers */ |
| 586 | 591 | u32 stored_l2[0x83]; |
| 592 | + | |
| 593 | + /* The maximum PC banks and counters/bank (PCSup=1) */ | |
| 594 | + u8 max_banks; | |
| 595 | + u8 max_counters; | |
| 587 | 596 | }; |
| 588 | 597 | |
| 589 | 598 | struct devid_map { |
| @@ -73,13 +73,18 @@ struct perf_raw_record { · 72 unmodified lines | ||
| 73 | 73 | * |
| 74 | 74 | * support for mispred, predicted is optional. In case it |
| 75 | 75 | * is not supported mispred = predicted = 0. |
| 76 | + * | |
| 77 | + * in_tx: running in a hardware transaction | |
| 78 | + * abort: aborting a hardware transaction | |
| 76 | 79 | */ |
| 77 | 80 | struct perf_branch_entry { |
| 78 | 81 | __u64 from; |
| 79 | 82 | __u64 to; |
| 80 | 83 | __u64 mispred:1, /* target mispredicted */ |
| 81 | 84 | predicted:1,/* target predicted */ |
| 82 | − reserved:62; | |
| 85 | + in_tx:1, /* in transaction */ | |
| 86 | + abort:1, /* transaction abort */ | |
| 87 | + reserved:60; | |
| 83 | 88 | }; |
| 84 | 89 | |
| 85 | 90 | /* |
| @@ -113,6 +118,8 @@ struct hw_perf_event_extra { · 27 unmodified lines | ||
| 113 | 118 | int idx; /* index in shared_regs->regs[] */ |
| 114 | 119 | }; |
| 115 | 120 | |
| 121 | +struct event_constraint; | |
| 122 | + | |
| 116 | 123 | /** |
| 117 | 124 | * struct hw_perf_event - performance event hardware details: |
| 118 | 125 | */ |
| @@ -131,6 +138,8 @@ struct hw_perf_event { · 12 unmodified lines | ||
| 131 | 138 | |
| 132 | 139 | struct hw_perf_event_extra extra_reg; |
| 133 | 140 | struct hw_perf_event_extra branch_reg; |
| 141 | + | |
| 142 | + struct event_constraint *constraint; | |
| 134 | 143 | }; |
| 135 | 144 | struct { /* software */ |
| 136 | 145 | struct hrtimer hrtimer; |
| @@ -188,12 +197,13 @@ struct pmu { · 51 unmodified lines | ||
| 188 | 197 | |
| 189 | 198 | struct device *dev; |
| 190 | 199 | const struct attribute_group **attr_groups; |
| 191 | − char *name; | |
| 200 | + const char *name; | |
| 192 | 201 | int type; |
| 193 | 202 | |
| 194 | 203 | int * __percpu pmu_disable_count; |
| 195 | 204 | struct perf_cpu_context * __percpu pmu_cpu_context; |
| 196 | 205 | int task_ctx_nr; |
| 206 | + int hrtimer_interval_ms; | |
| 197 | 207 | |
| 198 | 208 | /* |
| 199 | 209 | * Fully disable/enable this PMU, can be used to protect from the PMI |
| @@ -500,8 +510,9 @@ struct perf_cpu_context { · 300 unmodified lines | ||
| 500 | 510 | struct perf_event_context *task_ctx; |
| 501 | 511 | int active_oncpu; |
| 502 | 512 | int exclusive; |
| 513 | + struct hrtimer hrtimer; | |
| 514 | + ktime_t hrtimer_interval; | |
| 503 | 515 | struct list_head rotation_list; |
| 504 | − int jiffies_interval; | |
| 505 | 516 | struct pmu *unique_pmu; |
| 506 | 517 | struct perf_cgroup *cgrp; |
| 507 | 518 | }; |
| @@ -517,7 +528,7 @@ struct perf_output_handle { · 9 unmodified lines | ||
| 517 | 528 | |
| 518 | 529 | #ifdef CONFIG_PERF_EVENTS |
| 519 | 530 | |
| 520 | −extern int perf_pmu_register(struct pmu *pmu, char *name, int type); | |
| 531 | +extern int perf_pmu_register(struct pmu *pmu, const char *name, int type); | |
| 521 | 532 | extern void perf_pmu_unregister(struct pmu *pmu); |
| 522 | 533 | |
| 523 | 534 | extern int perf_num_counters(void); |
| @@ -695,10 +706,17 @@ static inline void perf_callchain_store(struct perf_callchain_entry *entry, u64 · 171 unmodified lines | ||
| 695 | 706 | extern int sysctl_perf_event_paranoid; |
| 696 | 707 | extern int sysctl_perf_event_mlock; |
| 697 | 708 | extern int sysctl_perf_event_sample_rate; |
| 709 | +extern int sysctl_perf_cpu_time_max_percent; | |
| 710 | + | |
| 711 | +extern void perf_sample_event_took(u64 sample_len_ns); | |
| 698 | 712 | |
| 699 | 713 | extern int perf_proc_update_handler(struct ctl_table *table, int write, |
| 700 | 714 | void __user *buffer, size_t *lenp, |
| 701 | 715 | loff_t *ppos); |
| 716 | +extern int perf_cpu_time_max_percent_handler(struct ctl_table *table, int write, | |
| 717 | + void __user *buffer, size_t *lenp, | |
| 718 | + loff_t *ppos); | |
| 719 | + | |
| 702 | 720 | |
| 703 | 721 | static inline bool perf_paranoid_tracepoint_raw(void) |
| 704 | 722 | { |
| @@ -742,6 +760,7 @@ extern unsigned int perf_output_skip(struct perf_output_handle *handle, · 37 unmodified lines | ||
| 742 | 760 | unsigned int len); |
| 743 | 761 | extern int perf_swevent_get_recursion_context(void); |
| 744 | 762 | extern void perf_swevent_put_recursion_context(int rctx); |
| 763 | +extern u64 perf_swevent_set_period(struct perf_event *event); | |
| 745 | 764 | extern void perf_event_enable(struct perf_event *event); |
| 746 | 765 | extern void perf_event_disable(struct perf_event *event); |
| 747 | 766 | extern int __perf_event_disable(void *info); |
| @@ -781,6 +800,7 @@ static inline void perf_event_fork(struct task_struct *tsk) { } · 33 unmodified lines | ||
| 781 | 800 | static inline void perf_event_init(void) { } |
| 782 | 801 | static inline int perf_swevent_get_recursion_context(void) { return -1; } |
| 783 | 802 | static inline void perf_swevent_put_recursion_context(int rctx) { } |
| 803 | +static inline u64 perf_swevent_set_period(struct perf_event *event) { return 0; } | |
| 784 | 804 | static inline void perf_event_enable(struct perf_event *event) { } |
| 785 | 805 | static inline void perf_event_disable(struct perf_event *event) { } |
| 786 | 806 | static inline int __perf_event_disable(void *info) { return -1; } |
| @@ -0,0 +1,37 @@ | ||
| 1 | +#undef TRACE_SYSTEM | |
| 2 | +#define TRACE_SYSTEM nmi | |
| 3 | + | |
| 4 | +#if !defined(_TRACE_NMI_H) || defined(TRACE_HEADER_MULTI_READ) | |
| 5 | +#define _TRACE_NMI_H | |
| 6 | + | |
| 7 | +#include <linux/ktime.h> | |
| 8 | +#include <linux/tracepoint.h> | |
| 9 | + | |
| 10 | +TRACE_EVENT(nmi_handler, | |
| 11 | + | |
| 12 | + TP_PROTO(void *handler, s64 delta_ns, int handled), | |
| 13 | + | |
| 14 | + TP_ARGS(handler, delta_ns, handled), | |
| 15 | + | |
| 16 | + TP_STRUCT__entry( | |
| 17 | + __field( void *, handler ) | |
| 18 | + __field( s64, delta_ns) | |
| 19 | + __field( int, handled ) | |
| 20 | + ), | |
| 21 | + | |
| 22 | + TP_fast_assign( | |
| 23 | + __entry->handler = handler; | |
| 24 | + __entry->delta_ns = delta_ns; | |
| 25 | + __entry->handled = handled; | |
| 26 | + ), | |
| 27 | + | |
| 28 | + TP_printk("%ps() delta_ns: %lld handled: %d", | |
| 29 | + __entry->handler, | |
| 30 | + __entry->delta_ns, | |
| 31 | + __entry->handled) | |
| 32 | +); | |
| 33 | + | |
| 34 | +#endif /* _TRACE_NMI_H */ | |
| 35 | + | |
| 36 | +/* This part ust be outside protection */ | |
| 37 | +#include <trace/define_trace.h> | |
| @@ -157,8 +157,11 @@ enum perf_branch_sample_type { · 156 unmodified lines | ||
| 157 | 157 | PERF_SAMPLE_BRANCH_ANY_CALL = 1U << 4, /* any call branch */ |
| 158 | 158 | PERF_SAMPLE_BRANCH_ANY_RETURN = 1U << 5, /* any return branch */ |
| 159 | 159 | PERF_SAMPLE_BRANCH_IND_CALL = 1U << 6, /* indirect calls */ |
| 160 | + PERF_SAMPLE_BRANCH_ABORT_TX = 1U << 7, /* transaction aborts */ | |
| 161 | + PERF_SAMPLE_BRANCH_IN_TX = 1U << 8, /* in transaction */ | |
| 162 | + PERF_SAMPLE_BRANCH_NO_TX = 1U << 9, /* not in transaction */ | |
| 160 | 163 | |
| 161 | − PERF_SAMPLE_BRANCH_MAX = 1U << 7, /* non-ABI */ | |
| 164 | + PERF_SAMPLE_BRANCH_MAX = 1U << 10, /* non-ABI */ | |
| 162 | 165 | }; |
| 163 | 166 | |
| 164 | 167 | #define PERF_SAMPLE_BRANCH_PLM_ALL \ |
| @@ -542,7 +542,6 @@ asmlinkage void __init start_kernel(void) · 541 unmodified lines | ||
| 542 | 542 | if (WARN(!irqs_disabled(), "Interrupts were enabled *very* early, fixing it\n")) |
| 543 | 543 | local_irq_disable(); |
| 544 | 544 | idr_init_cache(); |
| 545 | − perf_event_init(); | |
| 546 | 545 | rcu_init(); |
| 547 | 546 | tick_nohz_init(); |
| 548 | 547 | radix_tree_init(); |
| @@ -555,6 +554,7 @@ asmlinkage void __init start_kernel(void) · 6 unmodified lines | ||
| 555 | 554 | softirq_init(); |
| 556 | 555 | timekeeping_init(); |
| 557 | 556 | time_init(); |
| 557 | + perf_event_init(); | |
| 558 | 558 | profile_init(); |
| 559 | 559 | call_function_init(); |
| 560 | 560 | WARN(!irqs_disabled(), "Interrupts were enabled early\n"); |
| @@ -165,10 +165,28 @@ int sysctl_perf_event_mlock __read_mostly = 512 + (PAGE_SIZE / 1024); /* 'free' · 164 unmodified lines | ||
| 165 | 165 | /* |
| 166 | 166 | * max perf event sample rate |
| 167 | 167 | */ |
| 168 | −#define DEFAULT_MAX_SAMPLE_RATE 100000 | |
| 169 | −int sysctl_perf_event_sample_rate __read_mostly = DEFAULT_MAX_SAMPLE_RATE; | |
| 170 | −static int max_samples_per_tick __read_mostly = | |
| 171 | − DIV_ROUND_UP(DEFAULT_MAX_SAMPLE_RATE, HZ); | |
| 168 | +#define DEFAULT_MAX_SAMPLE_RATE 100000 | |
| 169 | +#define DEFAULT_SAMPLE_PERIOD_NS (NSEC_PER_SEC / DEFAULT_MAX_SAMPLE_RATE) | |
| 170 | +#define DEFAULT_CPU_TIME_MAX_PERCENT 25 | |
| 171 | + | |
| 172 | +int sysctl_perf_event_sample_rate __read_mostly = DEFAULT_MAX_SAMPLE_RATE; | |
| 173 | + | |
| 174 | +static int max_samples_per_tick __read_mostly = DIV_ROUND_UP(DEFAULT_MAX_SAMPLE_RATE, HZ); | |
| 175 | +static int perf_sample_period_ns __read_mostly = DEFAULT_SAMPLE_PERIOD_NS; | |
| 176 | + | |
| 177 | +static atomic_t perf_sample_allowed_ns __read_mostly = | |
| 178 | + ATOMIC_INIT( DEFAULT_SAMPLE_PERIOD_NS * DEFAULT_CPU_TIME_MAX_PERCENT / 100); | |
| 179 | + | |
| 180 | +void update_perf_cpu_limits(void) | |
| 181 | +{ | |
| 182 | + u64 tmp = perf_sample_period_ns; | |
| 183 | + | |
| 184 | + tmp *= sysctl_perf_cpu_time_max_percent; | |
| 185 | + tmp = do_div(tmp, 100); | |
| 186 | + atomic_set(&perf_sample_allowed_ns, tmp); | |
| 187 | +} | |
| 188 | + | |
| 189 | +static int perf_rotate_context(struct perf_cpu_context *cpuctx); | |
| 172 | 190 | |
| 173 | 191 | int perf_proc_update_handler(struct ctl_table *table, int write, |
| 174 | 192 | void __user *buffer, size_t *lenp, |
| @@ -180,10 +198,78 @@ int perf_proc_update_handler(struct ctl_table *table, int write, · 5 unmodified lines | ||
| 180 | 198 | return ret; |
| 181 | 199 | |
| 182 | 200 | max_samples_per_tick = DIV_ROUND_UP(sysctl_perf_event_sample_rate, HZ); |
| 201 | + perf_sample_period_ns = NSEC_PER_SEC / sysctl_perf_event_sample_rate; | |
| 202 | + update_perf_cpu_limits(); | |
| 183 | 203 | |
| 184 | 204 | return 0; |
| 185 | 205 | } |
| 186 | 206 | |
| 207 | +int sysctl_perf_cpu_time_max_percent __read_mostly = DEFAULT_CPU_TIME_MAX_PERCENT; | |
| 208 | + | |
| 209 | +int perf_cpu_time_max_percent_handler(struct ctl_table *table, int write, | |
| 210 | + void __user *buffer, size_t *lenp, | |
| 211 | + loff_t *ppos) | |
| 212 | +{ | |
| 213 | + int ret = proc_dointvec(table, write, buffer, lenp, ppos); | |
| 214 | + | |
| 215 | + if (ret || !write) | |
| 216 | + return ret; | |
| 217 | + | |
| 218 | + update_perf_cpu_limits(); | |
| 219 | + | |
| 220 | + return 0; | |
| 221 | +} | |
| 222 | + | |
| 223 | +/* | |
| 224 | + * perf samples are done in some very critical code paths (NMIs). | |
| 225 | + * If they take too much CPU time, the system can lock up and not | |
| 226 | + * get any real work done. This will drop the sample rate when | |
| 227 | + * we detect that events are taking too long. | |
| 228 | + */ | |
| 229 | +#define NR_ACCUMULATED_SAMPLES 128 | |
| 230 | +DEFINE_PER_CPU(u64, running_sample_length); | |
| 231 | + | |
| 232 | +void perf_sample_event_took(u64 sample_len_ns) | |
| 233 | +{ | |
| 234 | + u64 avg_local_sample_len; | |
| 235 | + u64 local_samples_len = __get_cpu_var(running_sample_length); | |
| 236 | + | |
| 237 | + if (atomic_read(&perf_sample_allowed_ns) == 0) | |
| 238 | + return; | |
| 239 | + | |
| 240 | + /* decay the counter by 1 average sample */ | |
| 241 | + local_samples_len = __get_cpu_var(running_sample_length); | |
| 242 | + local_samples_len -= local_samples_len/NR_ACCUMULATED_SAMPLES; | |
| 243 | + local_samples_len += sample_len_ns; | |
| 244 | + __get_cpu_var(running_sample_length) = local_samples_len; | |
| 245 | + | |
| 246 | + /* | |
| 247 | + * note: this will be biased artifically low until we have | |
| 248 | + * seen NR_ACCUMULATED_SAMPLES. Doing it this way keeps us | |
| 249 | + * from having to maintain a count. | |
| 250 | + */ | |
| 251 | + avg_local_sample_len = local_samples_len/NR_ACCUMULATED_SAMPLES; | |
| 252 | + | |
| 253 | + if (avg_local_sample_len <= atomic_read(&perf_sample_allowed_ns)) | |
| 254 | + return; | |
| 255 | + | |
| 256 | + if (max_samples_per_tick <= 1) | |
| 257 | + return; | |
| 258 | + | |
| 259 | + max_samples_per_tick = DIV_ROUND_UP(max_samples_per_tick, 2); | |
| 260 | + sysctl_perf_event_sample_rate = max_samples_per_tick * HZ; | |
| 261 | + perf_sample_period_ns = NSEC_PER_SEC / sysctl_perf_event_sample_rate; | |
| 262 | + | |
| 263 | + printk_ratelimited(KERN_WARNING | |
| 264 | + "perf samples too long (%lld > %d), lowering " | |
| 265 | + "kernel.perf_event_max_sample_rate to %d\n", | |
| 266 | + avg_local_sample_len, | |
| 267 | + atomic_read(&perf_sample_allowed_ns), | |
| 268 | + sysctl_perf_event_sample_rate); | |
| 269 | + | |
| 270 | + update_perf_cpu_limits(); | |
| 271 | +} | |
| 272 | + | |
| 187 | 273 | static atomic64_t perf_event_id; |
| 188 | 274 | |
| 189 | 275 | static void cpu_ctx_sched_out(struct perf_cpu_context *cpuctx, |
| @@ -655,6 +741,106 @@ perf_cgroup_mark_enabled(struct perf_event *event, · 465 unmodified lines | ||
| 655 | 741 | } |
| 656 | 742 | #endif |
| 657 | 743 | |
| 744 | +/* | |
| 745 | + * set default to be dependent on timer tick just | |
| 746 | + * like original code | |
| 747 | + */ | |
| 748 | +#define PERF_CPU_HRTIMER (1000 / HZ) | |
| 749 | +/* | |
| 750 | + * function must be called with interrupts disbled | |
| 751 | + */ | |
| 752 | +static enum hrtimer_restart perf_cpu_hrtimer_handler(struct hrtimer *hr) | |
| 753 | +{ | |
| 754 | + struct perf_cpu_context *cpuctx; | |
| 755 | + enum hrtimer_restart ret = HRTIMER_NORESTART; | |
| 756 | + int rotations = 0; | |
| 757 | + | |
| 758 | + WARN_ON(!irqs_disabled()); | |
| 759 | + | |
| 760 | + cpuctx = container_of(hr, struct perf_cpu_context, hrtimer); | |
| 761 | + | |
| 762 | + rotations = perf_rotate_context(cpuctx); | |
| 763 | + | |
| 764 | + /* | |
| 765 | + * arm timer if needed | |
| 766 | + */ | |
| 767 | + if (rotations) { | |
| 768 | + hrtimer_forward_now(hr, cpuctx->hrtimer_interval); | |
| 769 | + ret = HRTIMER_RESTART; | |
| 770 | + } | |
| 771 | + | |
| 772 | + return ret; | |
| 773 | +} | |
| 774 | + | |
| 775 | +/* CPU is going down */ | |
| 776 | +void perf_cpu_hrtimer_cancel(int cpu) | |
| 777 | +{ | |
| 778 | + struct perf_cpu_context *cpuctx; | |
| 779 | + struct pmu *pmu; | |
| 780 | + unsigned long flags; | |
| 781 | + | |
| 782 | + if (WARN_ON(cpu != smp_processor_id())) | |
| 783 | + return; | |
| 784 | + | |
| 785 | + local_irq_save(flags); | |
| 786 | + | |
| 787 | + rcu_read_lock(); | |
| 788 | + | |
| 789 | + list_for_each_entry_rcu(pmu, &pmus, entry) { | |
| 790 | + cpuctx = this_cpu_ptr(pmu->pmu_cpu_context); | |
| 791 | + | |
| 792 | + if (pmu->task_ctx_nr == perf_sw_context) | |
| 793 | + continue; | |
| 794 | + | |
| 795 | + hrtimer_cancel(&cpuctx->hrtimer); | |
| 796 | + } | |
| 797 | + | |
| 798 | + rcu_read_unlock(); | |
| 799 | + | |
| 800 | + local_irq_restore(flags); | |
| 801 | +} | |
| 802 | + | |
| 803 | +static void __perf_cpu_hrtimer_init(struct perf_cpu_context *cpuctx, int cpu) | |
| 804 | +{ | |
| 805 | + struct hrtimer *hr = &cpuctx->hrtimer; | |
| 806 | + struct pmu *pmu = cpuctx->ctx.pmu; | |
| 807 | + int timer; | |
| 808 | + | |
| 809 | + /* no multiplexing needed for SW PMU */ | |
| 810 | + if (pmu->task_ctx_nr == perf_sw_context) | |
| 811 | + return; | |
| 812 | + | |
| 813 | + /* | |
| 814 | + * check default is sane, if not set then force to | |
| 815 | + * default interval (1/tick) | |
| 816 | + */ | |
| 817 | + timer = pmu->hrtimer_interval_ms; | |
| 818 | + if (timer < 1) | |
| 819 | + timer = pmu->hrtimer_interval_ms = PERF_CPU_HRTIMER; | |
| 820 | + | |
| 821 | + cpuctx->hrtimer_interval = ns_to_ktime(NSEC_PER_MSEC * timer); | |
| 822 | + | |
| 823 | + hrtimer_init(hr, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); | |
| 824 | + hr->function = perf_cpu_hrtimer_handler; | |
| 825 | +} | |
| 826 | + | |
| 827 | +static void perf_cpu_hrtimer_restart(struct perf_cpu_context *cpuctx) | |
| 828 | +{ | |
| 829 | + struct hrtimer *hr = &cpuctx->hrtimer; | |
| 830 | + struct pmu *pmu = cpuctx->ctx.pmu; | |
| 831 | + | |
| 832 | + /* not for SW PMU */ | |
| 833 | + if (pmu->task_ctx_nr == perf_sw_context) | |
| 834 | + return; | |
| 835 | + | |
| 836 | + if (hrtimer_active(hr)) | |
| 837 | + return; | |
| 838 | + | |
| 839 | + if (!hrtimer_callback_running(hr)) | |
| 840 | + __hrtimer_start_range_ns(hr, cpuctx->hrtimer_interval, | |
| 841 | + 0, HRTIMER_MODE_REL_PINNED, 0); | |
| 842 | +} | |
| 843 | + | |
| 658 | 844 | void perf_pmu_disable(struct pmu *pmu) |
| 659 | 845 | { |
| 660 | 846 | int *count = this_cpu_ptr(pmu->pmu_disable_count); |
| @@ -1503,6 +1689,7 @@ group_sched_in(struct perf_event *group_event, · 842 unmodified lines | ||
| 1503 | 1689 | |
| 1504 | 1690 | if (event_sched_in(group_event, cpuctx, ctx)) { |
| 1505 | 1691 | pmu->cancel_txn(pmu); |
| 1692 | + perf_cpu_hrtimer_restart(cpuctx); | |
| 1506 | 1693 | return -EAGAIN; |
| 1507 | 1694 | } |
| 1508 | 1695 | |
| @@ -1549,6 +1736,8 @@ group_error: · 40 unmodified lines | ||
| 1549 | 1736 | |
| 1550 | 1737 | pmu->cancel_txn(pmu); |
| 1551 | 1738 | |
| 1739 | + perf_cpu_hrtimer_restart(cpuctx); | |
| 1740 | + | |
| 1552 | 1741 | return -EAGAIN; |
| 1553 | 1742 | } |
| 1554 | 1743 | |
| @@ -1804,8 +1993,10 @@ static int __perf_event_enable(void *info) · 249 unmodified lines | ||
| 1804 | 1993 | * If this event can't go on and it's part of a |
| 1805 | 1994 | * group, then the whole group has to come off. |
| 1806 | 1995 | */ |
| 1807 | − if (leader != event) | |
| 1996 | + if (leader != event) { | |
| 1808 | 1997 | group_sched_out(leader, cpuctx, ctx); |
| 1998 | + perf_cpu_hrtimer_restart(cpuctx); | |
| 1999 | + } | |
| 1809 | 2000 | if (leader->attr.pinned) { |
| 1810 | 2001 | update_group_times(leader); |
| 1811 | 2002 | leader->state = PERF_EVENT_STATE_ERROR; |
| @@ -2552,7 +2743,7 @@ static void rotate_ctx(struct perf_event_context *ctx) · 740 unmodified lines | ||
| 2552 | 2743 | * because they're strictly cpu affine and rotate_start is called with IRQs |
| 2553 | 2744 | * disabled, while rotate_context is called from IRQ context. |
| 2554 | 2745 | */ |
| 2555 | −static void perf_rotate_context(struct perf_cpu_context *cpuctx) | |
| 2746 | +static int perf_rotate_context(struct perf_cpu_context *cpuctx) | |
| 2556 | 2747 | { |
| 2557 | 2748 | struct perf_event_context *ctx = NULL; |
| 2558 | 2749 | int rotate = 0, remove = 1; |
| @@ -2591,6 +2782,8 @@ static void perf_rotate_context(struct perf_cpu_context *cpuctx) · 32 unmodified lines | ||
| 2591 | 2782 | done: |
| 2592 | 2783 | if (remove) |
| 2593 | 2784 | list_del_init(&cpuctx->rotation_list); |
| 2785 | + | |
| 2786 | + return rotate; | |
| 2594 | 2787 | } |
| 2595 | 2788 | |
| 2596 | 2789 | #ifdef CONFIG_NO_HZ_FULL |
| @@ -2622,10 +2815,6 @@ void perf_event_task_tick(void) · 25 unmodified lines | ||
| 2622 | 2815 | ctx = cpuctx->task_ctx; |
| 2623 | 2816 | if (ctx) |
| 2624 | 2817 | perf_adjust_freq_unthr_context(ctx, throttled); |
| 2625 | − | |
| 2626 | − if (cpuctx->jiffies_interval == 1 || | |
| 2627 | − !(jiffies % cpuctx->jiffies_interval)) | |
| 2628 | − perf_rotate_context(cpuctx); | |
| 2629 | 2818 | } |
| 2630 | 2819 | } |
| 2631 | 2820 | |
| @@ -5036,7 +5225,7 @@ static DEFINE_PER_CPU(struct swevent_htable, swevent_htable); · 2404 unmodified lines | ||
| 5036 | 5225 | * sign as trigger. |
| 5037 | 5226 | */ |
| 5038 | 5227 | |
| 5039 | −static u64 perf_swevent_set_period(struct perf_event *event) | |
| 5228 | +u64 perf_swevent_set_period(struct perf_event *event) | |
| 5040 | 5229 | { |
| 5041 | 5230 | struct hw_perf_event *hwc = &event->hw; |
| 5042 | 5231 | u64 period = hwc->last_period; |
| @@ -5979,9 +6168,56 @@ type_show(struct device *dev, struct device_attribute *attr, char *page) · 936 unmodified lines | ||
| 5979 | 6168 | return snprintf(page, PAGE_SIZE-1, "%d\n", pmu->type); |
| 5980 | 6169 | } |
| 5981 | 6170 | |
| 6171 | +static ssize_t | |
| 6172 | +perf_event_mux_interval_ms_show(struct device *dev, | |
| 6173 | + struct device_attribute *attr, | |
| 6174 | + char *page) | |
| 6175 | +{ | |
| 6176 | + struct pmu *pmu = dev_get_drvdata(dev); | |
| 6177 | + | |
| 6178 | + return snprintf(page, PAGE_SIZE-1, "%d\n", pmu->hrtimer_interval_ms); | |
| 6179 | +} | |
| 6180 | + | |
| 6181 | +static ssize_t | |
| 6182 | +perf_event_mux_interval_ms_store(struct device *dev, | |
| 6183 | + struct device_attribute *attr, | |
| 6184 | + const char *buf, size_t count) | |
| 6185 | +{ | |
| 6186 | + struct pmu *pmu = dev_get_drvdata(dev); | |
| 6187 | + int timer, cpu, ret; | |
| 6188 | + | |
| 6189 | + ret = kstrtoint(buf, 0, &timer); | |
| 6190 | + if (ret) | |
| 6191 | + return ret; | |
| 6192 | + | |
| 6193 | + if (timer < 1) | |
| 6194 | + return -EINVAL; | |
| 6195 | + | |
| 6196 | + /* same value, noting to do */ | |
| 6197 | + if (timer == pmu->hrtimer_interval_ms) | |
| 6198 | + return count; | |
| 6199 | + | |
| 6200 | + pmu->hrtimer_interval_ms = timer; | |
| 6201 | + | |
| 6202 | + /* update all cpuctx for this PMU */ | |
| 6203 | + for_each_possible_cpu(cpu) { | |
| 6204 | + struct perf_cpu_context *cpuctx; | |
| 6205 | + cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); | |
| 6206 | + cpuctx->hrtimer_interval = ns_to_ktime(NSEC_PER_MSEC * timer); | |
| 6207 | + | |
| 6208 | + if (hrtimer_active(&cpuctx->hrtimer)) | |
| 6209 | + hrtimer_forward_now(&cpuctx->hrtimer, cpuctx->hrtimer_interval); | |
| 6210 | + } | |
| 6211 | + | |
| 6212 | + return count; | |
| 6213 | +} | |
| 6214 | + | |
| 6215 | +#define __ATTR_RW(attr) __ATTR(attr, 0644, attr##_show, attr##_store) | |
| 6216 | + | |
| 5982 | 6217 | static struct device_attribute pmu_dev_attrs[] = { |
| 5983 | − __ATTR_RO(type), | |
| 5984 | − __ATTR_NULL, | |
| 6218 | + __ATTR_RO(type), | |
| 6219 | + __ATTR_RW(perf_event_mux_interval_ms), | |
| 6220 | + __ATTR_NULL, | |
| 5985 | 6221 | }; |
| 5986 | 6222 | |
| 5987 | 6223 | static int pmu_bus_running; |
| @@ -6027,7 +6263,7 @@ free_dev: · 39 unmodified lines | ||
| 6027 | 6263 | static struct lock_class_key cpuctx_mutex; |
| 6028 | 6264 | static struct lock_class_key cpuctx_lock; |
| 6029 | 6265 | |
| 6030 | −int perf_pmu_register(struct pmu *pmu, char *name, int type) | |
| 6266 | +int perf_pmu_register(struct pmu *pmu, const char *name, int type) | |
| 6031 | 6267 | { |
| 6032 | 6268 | int cpu, ret; |
| 6033 | 6269 | |
| @@ -6076,7 +6312,9 @@ skip_type: · 42 unmodified lines | ||
| 6076 | 6312 | lockdep_set_class(&cpuctx->ctx.lock, &cpuctx_lock); |
| 6077 | 6313 | cpuctx->ctx.type = cpu_context; |
| 6078 | 6314 | cpuctx->ctx.pmu = pmu; |
| 6079 | − cpuctx->jiffies_interval = 1; | |
| 6315 | + | |
| 6316 | + __perf_cpu_hrtimer_init(cpuctx, cpu); | |
| 6317 | + | |
| 6080 | 6318 | INIT_LIST_HEAD(&cpuctx->rotation_list); |
| 6081 | 6319 | cpuctx->unique_pmu = pmu; |
| 6082 | 6320 | } |
| @@ -6402,11 +6640,6 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr, · 319 unmodified lines | ||
| 6402 | 6640 | if (!(mask & ~PERF_SAMPLE_BRANCH_PLM_ALL)) |
| 6403 | 6641 | return -EINVAL; |
| 6404 | 6642 | |
| 6405 | − /* kernel level capture: check permissions */ | |
| 6406 | − if ((mask & PERF_SAMPLE_BRANCH_PERM_PLM) | |
| 6407 | − && perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) | |
| 6408 | − return -EACCES; | |
| 6409 | − | |
| 6410 | 6643 | /* propagate priv level, when not set for branch */ |
| 6411 | 6644 | if (!(mask & PERF_SAMPLE_BRANCH_PLM_ALL)) { |
| 6412 | 6645 | |
| @@ -6424,6 +6657,10 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr, · 11 unmodified lines | ||
| 6424 | 6657 | */ |
| 6425 | 6658 | attr->branch_sample_type = mask; |
| 6426 | 6659 | } |
| 6660 | + /* privileged levels capture (kernel, hv): check permissions */ | |
| 6661 | + if ((mask & PERF_SAMPLE_BRANCH_PERM_PLM) | |
| 6662 | + && perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) | |
| 6663 | + return -EACCES; | |
| 6427 | 6664 | } |
| 6428 | 6665 | |
| 6429 | 6666 | if (attr->sample_type & PERF_SAMPLE_REGS_USER) { |
| @@ -7476,7 +7713,6 @@ perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) · 1046 unmodified lines | ||
| 7476 | 7713 | case CPU_DOWN_PREPARE: |
| 7477 | 7714 | perf_event_exit_cpu(cpu); |
| 7478 | 7715 | break; |
| 7479 | − | |
| 7480 | 7716 | default: |
| 7481 | 7717 | break; |
| 7482 | 7718 | } |
| @@ -46,23 +46,26 @@ · 45 unmodified lines | ||
| 46 | 46 | #include <linux/smp.h> |
| 47 | 47 | |
| 48 | 48 | #include <linux/hw_breakpoint.h> |
| 49 | − | |
| 50 | − | |
| 51 | 49 | /* |
| 52 | 50 | * Constraints data |
| 53 | 51 | */ |
| 52 | +struct bp_cpuinfo { | |
| 53 | + /* Number of pinned cpu breakpoints in a cpu */ | |
| 54 | + unsigned int cpu_pinned; | |
| 55 | + /* tsk_pinned[n] is the number of tasks having n+1 breakpoints */ | |
| 56 | + unsigned int *tsk_pinned; | |
| 57 | + /* Number of non-pinned cpu/task breakpoints in a cpu */ | |
| 58 | + unsigned int flexible; /* XXX: placeholder, see fetch_this_slot() */ | |
| 59 | +}; | |
| 54 | 60 | |
| 55 | −/* Number of pinned cpu breakpoints in a cpu */ | |
| 56 | −static DEFINE_PER_CPU(unsigned int, nr_cpu_bp_pinned[TYPE_MAX]); | |
| 57 | − | |
| 58 | −/* Number of pinned task breakpoints in a cpu */ | |
| 59 | −static DEFINE_PER_CPU(unsigned int *, nr_task_bp_pinned[TYPE_MAX]); | |
| 60 | − | |
| 61 | −/* Number of non-pinned cpu/task breakpoints in a cpu */ | |
| 62 | −static DEFINE_PER_CPU(unsigned int, nr_bp_flexible[TYPE_MAX]); | |
| 63 | − | |
| 61 | +static DEFINE_PER_CPU(struct bp_cpuinfo, bp_cpuinfo[TYPE_MAX]); | |
| 64 | 62 | static int nr_slots[TYPE_MAX]; |
| 65 | 63 | |
| 64 | +static struct bp_cpuinfo *get_bp_info(int cpu, enum bp_type_idx type) | |
| 65 | +{ | |
| 66 | + return per_cpu_ptr(bp_cpuinfo + type, cpu); | |
| 67 | +} | |
| 68 | + | |
| 66 | 69 | /* Keep track of the breakpoints attached to tasks */ |
| 67 | 70 | static LIST_HEAD(bp_task_head); |
| 68 | 71 | |
| @@ -96,8 +99,8 @@ static inline enum bp_type_idx find_slot_idx(struct perf_event *bp) · 27 unmodified lines | ||
| 96 | 99 | */ |
| 97 | 100 | static unsigned int max_task_bp_pinned(int cpu, enum bp_type_idx type) |
| 98 | 101 | { |
| 102 | + unsigned int *tsk_pinned = get_bp_info(cpu, type)->tsk_pinned; | |
| 99 | 103 | int i; |
| 100 | − unsigned int *tsk_pinned = per_cpu(nr_task_bp_pinned[type], cpu); | |
| 101 | 104 | |
| 102 | 105 | for (i = nr_slots[type] - 1; i >= 0; i--) { |
| 103 | 106 | if (tsk_pinned[i] > 0) |
| @@ -127,6 +130,13 @@ static int task_bp_pinned(int cpu, struct perf_event *bp, enum bp_type_idx type) · 23 unmodified lines | ||
| 127 | 130 | return count; |
| 128 | 131 | } |
| 129 | 132 | |
| 133 | +static const struct cpumask *cpumask_of_bp(struct perf_event *bp) | |
| 134 | +{ | |
| 135 | + if (bp->cpu >= 0) | |
| 136 | + return cpumask_of(bp->cpu); | |
| 137 | + return cpu_possible_mask; | |
| 138 | +} | |
| 139 | + | |
| 130 | 140 | /* |
| 131 | 141 | * Report the number of pinned/un-pinned breakpoints we have in |
| 132 | 142 | * a given cpu (cpu > -1) or in all of them (cpu = -1). |
| @@ -135,25 +145,15 @@ static void · 2 unmodified lines | ||
| 135 | 145 | fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp, |
| 136 | 146 | enum bp_type_idx type) |
| 137 | 147 | { |
| 138 | − int cpu = bp->cpu; | |
| 139 | − struct task_struct *tsk = bp->hw.bp_target; | |
| 140 | − | |
| 141 | − if (cpu >= 0) { | |
| 142 | − slots->pinned = per_cpu(nr_cpu_bp_pinned[type], cpu); | |
| 143 | − if (!tsk) | |
| 144 | − slots->pinned += max_task_bp_pinned(cpu, type); | |
| 145 | − else | |
| 146 | − slots->pinned += task_bp_pinned(cpu, bp, type); | |
| 147 | − slots->flexible = per_cpu(nr_bp_flexible[type], cpu); | |
| 148 | − | |
| 149 | − return; | |
| 150 | − } | |
| 148 | + const struct cpumask *cpumask = cpumask_of_bp(bp); | |
| 149 | + int cpu; | |
| 151 | 150 | |
| 152 | − for_each_possible_cpu(cpu) { | |
| 153 | − unsigned int nr; | |
| 151 | + for_each_cpu(cpu, cpumask) { | |
| 152 | + struct bp_cpuinfo *info = get_bp_info(cpu, type); | |
| 153 | + int nr; | |
| 154 | 154 | |
| 155 | − nr = per_cpu(nr_cpu_bp_pinned[type], cpu); | |
| 156 | − if (!tsk) | |
| 155 | + nr = info->cpu_pinned; | |
| 156 | + if (!bp->hw.bp_target) | |
| 157 | 157 | nr += max_task_bp_pinned(cpu, type); |
| 158 | 158 | else |
| 159 | 159 | nr += task_bp_pinned(cpu, bp, type); |
| @@ -161,8 +161,7 @@ fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp, · 1 unmodified line | ||
| 161 | 161 | if (nr > slots->pinned) |
| 162 | 162 | slots->pinned = nr; |
| 163 | 163 | |
| 164 | − nr = per_cpu(nr_bp_flexible[type], cpu); | |
| 165 | − | |
| 164 | + nr = info->flexible; | |
| 166 | 165 | if (nr > slots->flexible) |
| 167 | 166 | slots->flexible = nr; |
| 168 | 167 | } |
| @@ -182,29 +181,19 @@ fetch_this_slot(struct bp_busy_slots *slots, int weight) · 13 unmodified lines | ||
| 182 | 181 | /* |
| 183 | 182 | * Add a pinned breakpoint for the given task in our constraint table |
| 184 | 183 | */ |
| 185 | −static void toggle_bp_task_slot(struct perf_event *bp, int cpu, bool enable, | |
| 184 | +static void toggle_bp_task_slot(struct perf_event *bp, int cpu, | |
| 186 | 185 | enum bp_type_idx type, int weight) |
| 187 | 186 | { |
| 188 | − unsigned int *tsk_pinned; | |
| 189 | − int old_count = 0; | |
| 190 | − int old_idx = 0; | |
| 191 | − int idx = 0; | |
| 192 | − | |
| 193 | − old_count = task_bp_pinned(cpu, bp, type); | |
| 194 | − old_idx = old_count - 1; | |
| 195 | − idx = old_idx + weight; | |
| 196 | − | |
| 197 | − /* tsk_pinned[n] is the number of tasks having n breakpoints */ | |
| 198 | − tsk_pinned = per_cpu(nr_task_bp_pinned[type], cpu); | |
| 199 | − if (enable) { | |
| 200 | − tsk_pinned[idx]++; | |
| 201 | − if (old_count > 0) | |
| 202 | − tsk_pinned[old_idx]--; | |
| 203 | − } else { | |
| 204 | − tsk_pinned[idx]--; | |
| 205 | − if (old_count > 0) | |
| 206 | − tsk_pinned[old_idx]++; | |
| 207 | − } | |
| 187 | + unsigned int *tsk_pinned = get_bp_info(cpu, type)->tsk_pinned; | |
| 188 | + int old_idx, new_idx; | |
| 189 | + | |
| 190 | + old_idx = task_bp_pinned(cpu, bp, type) - 1; | |
| 191 | + new_idx = old_idx + weight; | |
| 192 | + | |
| 193 | + if (old_idx >= 0) | |
| 194 | + tsk_pinned[old_idx]--; | |
| 195 | + if (new_idx >= 0) | |
| 196 | + tsk_pinned[new_idx]++; | |
| 208 | 197 | } |
| 209 | 198 | |
| 210 | 199 | /* |
| @@ -214,33 +203,26 @@ static void · 3 unmodified lines | ||
| 214 | 203 | toggle_bp_slot(struct perf_event *bp, bool enable, enum bp_type_idx type, |
| 215 | 204 | int weight) |
| 216 | 205 | { |
| 217 | − int cpu = bp->cpu; | |
| 218 | − struct task_struct *tsk = bp->hw.bp_target; | |
| 206 | + const struct cpumask *cpumask = cpumask_of_bp(bp); | |
| 207 | + int cpu; | |
| 219 | 208 | |
| 220 | − /* Pinned counter cpu profiling */ | |
| 221 | − if (!tsk) { | |
| 209 | + if (!enable) | |
| 210 | + weight = -weight; | |
| 222 | 211 | |
| 223 | − if (enable) | |
| 224 | − per_cpu(nr_cpu_bp_pinned[type], bp->cpu) += weight; | |
| 225 | − else | |
| 226 | − per_cpu(nr_cpu_bp_pinned[type], bp->cpu) -= weight; | |
| 212 | + /* Pinned counter cpu profiling */ | |
| 213 | + if (!bp->hw.bp_target) { | |
| 214 | + get_bp_info(bp->cpu, type)->cpu_pinned += weight; | |
| 227 | 215 | return; |
| 228 | 216 | } |
| 229 | 217 | |
| 230 | 218 | /* Pinned counter task profiling */ |
| 231 | − | |
| 232 | − if (!enable) | |
| 233 | − list_del(&bp->hw.bp_list); | |
| 234 | − | |
| 235 | − if (cpu >= 0) { | |
| 236 | − toggle_bp_task_slot(bp, cpu, enable, type, weight); | |
| 237 | − } else { | |
| 238 | − for_each_possible_cpu(cpu) | |
| 239 | − toggle_bp_task_slot(bp, cpu, enable, type, weight); | |
| 240 | − } | |
| 219 | + for_each_cpu(cpu, cpumask) | |
| 220 | + toggle_bp_task_slot(bp, cpu, type, weight); | |
| 241 | 221 | |
| 242 | 222 | if (enable) |
| 243 | 223 | list_add_tail(&bp->hw.bp_list, &bp_task_head); |
| 224 | + else | |
| 225 | + list_del(&bp->hw.bp_list); | |
| 244 | 226 | } |
| 245 | 227 | |
| 246 | 228 | /* |
| @@ -261,8 +243,8 @@ __weak void arch_unregister_hw_breakpoint(struct perf_event *bp) · 14 unmodified lines | ||
| 261 | 243 | * |
| 262 | 244 | * - If attached to a single cpu, check: |
| 263 | 245 | * |
| 264 | − * (per_cpu(nr_bp_flexible, cpu) || (per_cpu(nr_cpu_bp_pinned, cpu) | |
| 265 | − * + max(per_cpu(nr_task_bp_pinned, cpu)))) < HBP_NUM | |
| 246 | + * (per_cpu(info->flexible, cpu) || (per_cpu(info->cpu_pinned, cpu) | |
| 247 | + * + max(per_cpu(info->tsk_pinned, cpu)))) < HBP_NUM | |
| 266 | 248 | * |
| 267 | 249 | * -> If there are already non-pinned counters in this cpu, it means |
| 268 | 250 | * there is already a free slot for them. |
| @@ -272,8 +254,8 @@ __weak void arch_unregister_hw_breakpoint(struct perf_event *bp) · 3 unmodified lines | ||
| 272 | 254 | * |
| 273 | 255 | * - If attached to every cpus, check: |
| 274 | 256 | * |
| 275 | − * (per_cpu(nr_bp_flexible, *) || (max(per_cpu(nr_cpu_bp_pinned, *)) | |
| 276 | − * + max(per_cpu(nr_task_bp_pinned, *)))) < HBP_NUM | |
| 257 | + * (per_cpu(info->flexible, *) || (max(per_cpu(info->cpu_pinned, *)) | |
| 258 | + * + max(per_cpu(info->tsk_pinned, *)))) < HBP_NUM | |
| 277 | 259 | * |
| 278 | 260 | * -> This is roughly the same, except we check the number of per cpu |
| 279 | 261 | * bp for every cpu and we keep the max one. Same for the per tasks |
| @@ -284,16 +266,16 @@ __weak void arch_unregister_hw_breakpoint(struct perf_event *bp) · 4 unmodified lines | ||
| 284 | 266 | * |
| 285 | 267 | * - If attached to a single cpu, check: |
| 286 | 268 | * |
| 287 | − * ((per_cpu(nr_bp_flexible, cpu) > 1) + per_cpu(nr_cpu_bp_pinned, cpu) | |
| 288 | − * + max(per_cpu(nr_task_bp_pinned, cpu))) < HBP_NUM | |
| 269 | + * ((per_cpu(info->flexible, cpu) > 1) + per_cpu(info->cpu_pinned, cpu) | |
| 270 | + * + max(per_cpu(info->tsk_pinned, cpu))) < HBP_NUM | |
| 289 | 271 | * |
| 290 | − * -> Same checks as before. But now the nr_bp_flexible, if any, must keep | |
| 272 | + * -> Same checks as before. But now the info->flexible, if any, must keep | |
| 291 | 273 | * one register at least (or they will never be fed). |
| 292 | 274 | * |
| 293 | 275 | * - If attached to every cpus, check: |
| 294 | 276 | * |
| 295 | − * ((per_cpu(nr_bp_flexible, *) > 1) + max(per_cpu(nr_cpu_bp_pinned, *)) | |
| 296 | − * + max(per_cpu(nr_task_bp_pinned, *))) < HBP_NUM | |
| 277 | + * ((per_cpu(info->flexible, *) > 1) + max(per_cpu(info->cpu_pinned, *)) | |
| 278 | + * + max(per_cpu(info->tsk_pinned, *))) < HBP_NUM | |
| 297 | 279 | */ |
| 298 | 280 | static int __reserve_bp_slot(struct perf_event *bp) |
| 299 | 281 | { |
| @@ -518,8 +500,8 @@ register_wide_hw_breakpoint(struct perf_event_attr *attr, · 218 unmodified lines | ||
| 518 | 500 | perf_overflow_handler_t triggered, |
| 519 | 501 | void *context) |
| 520 | 502 | { |
| 521 | − struct perf_event * __percpu *cpu_events, **pevent, *bp; | |
| 522 | − long err; | |
| 503 | + struct perf_event * __percpu *cpu_events, *bp; | |
| 504 | + long err = 0; | |
| 523 | 505 | int cpu; |
| 524 | 506 | |
| 525 | 507 | cpu_events = alloc_percpu(typeof(*cpu_events)); |
| @@ -528,31 +510,21 @@ register_wide_hw_breakpoint(struct perf_event_attr *attr, · 2 unmodified lines | ||
| 528 | 510 | |
| 529 | 511 | get_online_cpus(); |
| 530 | 512 | for_each_online_cpu(cpu) { |
| 531 | − pevent = per_cpu_ptr(cpu_events, cpu); | |
| 532 | 513 | bp = perf_event_create_kernel_counter(attr, cpu, NULL, |
| 533 | 514 | triggered, context); |
| 534 | − | |
| 535 | − *pevent = bp; | |
| 536 | − | |
| 537 | 515 | if (IS_ERR(bp)) { |
| 538 | 516 | err = PTR_ERR(bp); |
| 539 | − goto fail; | |
| 517 | + break; | |
| 540 | 518 | } |
| 541 | − } | |
| 542 | − put_online_cpus(); | |
| 543 | 519 | |
| 544 | − return cpu_events; | |
| 545 | − | |
| 546 | −fail: | |
| 547 | − for_each_online_cpu(cpu) { | |
| 548 | − pevent = per_cpu_ptr(cpu_events, cpu); | |
| 549 | − if (IS_ERR(*pevent)) | |
| 550 | − break; | |
| 551 | − unregister_hw_breakpoint(*pevent); | |
| 520 | + per_cpu(*cpu_events, cpu) = bp; | |
| 552 | 521 | } |
| 553 | 522 | put_online_cpus(); |
| 554 | 523 | |
| 555 | − free_percpu(cpu_events); | |
| 524 | + if (likely(!err)) | |
| 525 | + return cpu_events; | |
| 526 | + | |
| 527 | + unregister_wide_hw_breakpoint(cpu_events); | |
| 556 | 528 | return (void __percpu __force *)ERR_PTR(err); |
| 557 | 529 | } |
| 558 | 530 | EXPORT_SYMBOL_GPL(register_wide_hw_breakpoint); |
| @@ -564,12 +536,10 @@ EXPORT_SYMBOL_GPL(register_wide_hw_breakpoint); · 5 unmodified lines | ||
| 564 | 536 | void unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events) |
| 565 | 537 | { |
| 566 | 538 | int cpu; |
| 567 | − struct perf_event **pevent; | |
| 568 | 539 | |
| 569 | − for_each_possible_cpu(cpu) { | |
| 570 | − pevent = per_cpu_ptr(cpu_events, cpu); | |
| 571 | − unregister_hw_breakpoint(*pevent); | |
| 572 | − } | |
| 540 | + for_each_possible_cpu(cpu) | |
| 541 | + unregister_hw_breakpoint(per_cpu(*cpu_events, cpu)); | |
| 542 | + | |
| 573 | 543 | free_percpu(cpu_events); |
| 574 | 544 | } |
| 575 | 545 | EXPORT_SYMBOL_GPL(unregister_wide_hw_breakpoint); |
| @@ -612,6 +582,11 @@ static int hw_breakpoint_add(struct perf_event *bp, int flags) · 36 unmodified lines | ||
| 612 | 582 | if (!(flags & PERF_EF_START)) |
| 613 | 583 | bp->hw.state = PERF_HES_STOPPED; |
| 614 | 584 | |
| 585 | + if (is_sampling_event(bp)) { | |
| 586 | + bp->hw.last_period = bp->hw.sample_period; | |
| 587 | + perf_swevent_set_period(bp); | |
| 588 | + } | |
| 589 | + | |
| 615 | 590 | return arch_install_hw_breakpoint(bp); |
| 616 | 591 | } |
| 617 | 592 | |
| @@ -650,7 +625,6 @@ static struct pmu perf_breakpoint = { · 32 unmodified lines | ||
| 650 | 625 | |
| 651 | 626 | int __init init_hw_breakpoint(void) |
| 652 | 627 | { |
| 653 | − unsigned int **task_bp_pinned; | |
| 654 | 628 | int cpu, err_cpu; |
| 655 | 629 | int i; |
| 656 | 630 | |
| @@ -659,10 +633,11 @@ int __init init_hw_breakpoint(void) · 2 unmodified lines | ||
| 659 | 633 | |
| 660 | 634 | for_each_possible_cpu(cpu) { |
| 661 | 635 | for (i = 0; i < TYPE_MAX; i++) { |
| 662 | − task_bp_pinned = &per_cpu(nr_task_bp_pinned[i], cpu); | |
| 663 | − *task_bp_pinned = kzalloc(sizeof(int) * nr_slots[i], | |
| 664 | − GFP_KERNEL); | |
| 665 | − if (!*task_bp_pinned) | |
| 636 | + struct bp_cpuinfo *info = get_bp_info(cpu, i); | |
| 637 | + | |
| 638 | + info->tsk_pinned = kcalloc(nr_slots[i], sizeof(int), | |
| 639 | + GFP_KERNEL); | |
| 640 | + if (!info->tsk_pinned) | |
| 666 | 641 | goto err_alloc; |
| 667 | 642 | } |
| 668 | 643 | } |
| @@ -676,7 +651,7 @@ int __init init_hw_breakpoint(void) · 7 unmodified lines | ||
| 676 | 651 | err_alloc: |
| 677 | 652 | for_each_possible_cpu(err_cpu) { |
| 678 | 653 | for (i = 0; i < TYPE_MAX; i++) |
| 679 | − kfree(per_cpu(nr_task_bp_pinned[i], err_cpu)); | |
| 654 | + kfree(get_bp_info(err_cpu, i)->tsk_pinned); | |
| 680 | 655 | if (err_cpu == cpu) |
| 681 | 656 | break; |
| 682 | 657 | } |
| @@ -120,7 +120,6 @@ extern int blk_iopoll_enabled; · 119 unmodified lines | ||
| 120 | 120 | /* Constants used for minimum and maximum */ |
| 121 | 121 | #ifdef CONFIG_LOCKUP_DETECTOR |
| 122 | 122 | static int sixty = 60; |
| 123 | −static int neg_one = -1; | |
| 124 | 123 | #endif |
| 125 | 124 | |
| 126 | 125 | static int zero; |
| @@ -814,7 +813,7 @@ static struct ctl_table kern_table[] = { · 687 unmodified lines | ||
| 814 | 813 | .maxlen = sizeof(int), |
| 815 | 814 | .mode = 0644, |
| 816 | 815 | .proc_handler = proc_dowatchdog, |
| 817 | − .extra1 = &neg_one, | |
| 816 | + .extra1 = &zero, | |
| 818 | 817 | .extra2 = &sixty, |
| 819 | 818 | }, |
| 820 | 819 | { |
| @@ -1044,6 +1043,15 @@ static struct ctl_table kern_table[] = { · 223 unmodified lines | ||
| 1044 | 1043 | .mode = 0644, |
| 1045 | 1044 | .proc_handler = perf_proc_update_handler, |
| 1046 | 1045 | }, |
| 1046 | + { | |
| 1047 | + .procname = "perf_cpu_time_max_percent", | |
| 1048 | + .data = &sysctl_perf_cpu_time_max_percent, | |
| 1049 | + .maxlen = sizeof(sysctl_perf_cpu_time_max_percent), | |
| 1050 | + .mode = 0644, | |
| 1051 | + .proc_handler = perf_cpu_time_max_percent_handler, | |
| 1052 | + .extra1 = &zero, | |
| 1053 | + .extra2 = &one_hundred, | |
| 1054 | + }, | |
| 1047 | 1055 | #endif |
| 1048 | 1056 | #ifdef CONFIG_KMEMCHECK |
| 1049 | 1057 | { |
| @@ -1,5 +1,8 @@ | ||
| 1 | 1 | include ../../scripts/Makefile.include |
| 2 | 2 | |
| 3 | +CC = $(CROSS_COMPILE)gcc | |
| 4 | +AR = $(CROSS_COMPILE)ar | |
| 5 | + | |
| 3 | 6 | # guard against environment variables |
| 4 | 7 | LIB_H= |
| 5 | 8 | LIB_OBJS= |
| @@ -13,7 +13,7 @@ SYNOPSIS · 12 unmodified lines | ||
| 13 | 13 | DESCRIPTION |
| 14 | 14 | ----------- |
| 15 | 15 | This command runs runs perf-buildid-list --with-hits, and collects the files |
| 16 | −with the buildids found so that analisys of perf.data contents can be possible | |
| 16 | +with the buildids found so that analysis of perf.data contents can be possible | |
| 17 | 17 | on another machine. |
| 18 | 18 | |
| 19 | 19 | |
| @@ -210,6 +210,10 @@ OPTIONS · 209 unmodified lines | ||
| 210 | 210 | Demangle symbol names to human readable form. It's enabled by default, |
| 211 | 211 | disable with --no-demangle. |
| 212 | 212 | |
| 213 | +--percent-limit:: | |
| 214 | + Do not show entries which have an overhead under that percent. | |
| 215 | + (Default: 0). | |
| 216 | + | |
| 213 | 217 | SEE ALSO |
| 214 | 218 | -------- |
| 215 | 219 | linkperf:perf-stat[1], linkperf:perf-annotate[1] |
| @@ -155,6 +155,10 @@ Default is to monitor all CPUS. · 154 unmodified lines | ||
| 155 | 155 | |
| 156 | 156 | Default: fractal,0.5,callee. |
| 157 | 157 | |
| 158 | +--percent-limit:: | |
| 159 | + Do not show entries which have an overhead under that percent. | |
| 160 | + (Default: 0). | |
| 161 | + | |
| 158 | 162 | INTERACTIVE PROMPTING KEYS |
| 159 | 163 | -------------------------- |
| 160 | 164 | |
| @@ -51,189 +51,63 @@ include config/utilities.mak · 50 unmodified lines | ||
| 51 | 51 | # Define NO_BACKTRACE if you do not want stack backtrace debug feature |
| 52 | 52 | # |
| 53 | 53 | # Define NO_LIBNUMA if you do not want numa perf benchmark |
| 54 | +# | |
| 55 | +# Define NO_LIBAUDIT if you do not want libaudit support | |
| 56 | +# | |
| 57 | +# Define NO_LIBBIONIC if you do not want bionic support | |
| 54 | 58 | |
| 55 | −$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE | |
| 56 | − @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) | |
| 57 | − | |
| 58 | −uname_M := $(shell uname -m 2>/dev/null || echo not) | |
| 59 | − | |
| 60 | −ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ | |
| 61 | − -e s/arm.*/arm/ -e s/sa110/arm/ \ | |
| 62 | − -e s/s390x/s390/ -e s/parisc64/parisc/ \ | |
| 63 | − -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ | |
| 64 | − -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ ) | |
| 65 | −NO_PERF_REGS := 1 | |
| 66 | − | |
| 67 | −CC = $(CROSS_COMPILE)gcc | |
| 68 | −AR = $(CROSS_COMPILE)ar | |
| 69 | − | |
| 70 | −# Additional ARCH settings for x86 | |
| 71 | −ifeq ($(ARCH),i386) | |
| 72 | − override ARCH := x86 | |
| 73 | − NO_PERF_REGS := 0 | |
| 74 | − LIBUNWIND_LIBS = -lunwind -lunwind-x86 | |
| 75 | −endif | |
| 76 | −ifeq ($(ARCH),x86_64) | |
| 77 | − override ARCH := x86 | |
| 78 | − IS_X86_64 := 0 | |
| 79 | − ifeq (, $(findstring m32,$(EXTRA_CFLAGS))) | |
| 80 | − IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1) | |
| 81 | − endif | |
| 82 | − ifeq (${IS_X86_64}, 1) | |
| 83 | − RAW_ARCH := x86_64 | |
| 84 | − ARCH_CFLAGS := -DARCH_X86_64 | |
| 85 | − ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S | |
| 86 | − endif | |
| 87 | − NO_PERF_REGS := 0 | |
| 88 | − LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 | |
| 89 | −endif | |
| 90 | − | |
| 91 | −# Treat warnings as errors unless directed not to | |
| 92 | −ifneq ($(WERROR),0) | |
| 93 | − CFLAGS_WERROR := -Werror | |
| 94 | −endif | |
| 95 | − | |
| 96 | −ifeq ("$(origin DEBUG)", "command line") | |
| 97 | − PERF_DEBUG = $(DEBUG) | |
| 98 | −endif | |
| 99 | −ifndef PERF_DEBUG | |
| 100 | − CFLAGS_OPTIMIZE = -O6 | |
| 59 | +ifeq ($(srctree),) | |
| 60 | +srctree := $(patsubst %/,%,$(dir $(shell pwd))) | |
| 61 | +srctree := $(patsubst %/,%,$(dir $(srctree))) | |
| 62 | +#$(info Determined 'srctree' to be $(srctree)) | |
| 101 | 63 | endif |
| 102 | 64 | |
| 103 | −ifdef PARSER_DEBUG | |
| 104 | − PARSER_DEBUG_BISON := -t | |
| 105 | − PARSER_DEBUG_FLEX := -d | |
| 106 | − PARSER_DEBUG_CFLAGS := -DPARSER_DEBUG | |
| 65 | +ifneq ($(objtree),) | |
| 66 | +#$(info Determined 'objtree' to be $(objtree)) | |
| 107 | 67 | endif |
| 108 | 68 | |
| 109 | −ifdef NO_NEWT | |
| 110 | − NO_SLANG=1 | |
| 69 | +ifneq ($(OUTPUT),) | |
| 70 | +#$(info Determined 'OUTPUT' to be $(OUTPUT)) | |
| 111 | 71 | endif |
| 112 | 72 | |
| 113 | −CFLAGS = -fno-omit-frame-pointer -ggdb3 -funwind-tables -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) $(PARSER_DEBUG_CFLAGS) | |
| 114 | −EXTLIBS = -lpthread -lrt -lelf -lm | |
| 115 | −ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE | |
| 116 | −ALL_LDFLAGS = $(LDFLAGS) | |
| 117 | −STRIP ?= strip | |
| 118 | − | |
| 119 | −# Among the variables below, these: | |
| 120 | −# perfexecdir | |
| 121 | −# template_dir | |
| 122 | −# mandir | |
| 123 | −# infodir | |
| 124 | −# htmldir | |
| 125 | −# ETC_PERFCONFIG (but not sysconfdir) | |
| 126 | −# can be specified as a relative path some/where/else; | |
| 127 | −# this is interpreted as relative to $(prefix) and "perf" at | |
| 128 | −# runtime figures out where they are based on the path to the executable. | |
| 129 | −# This can help installing the suite in a relocatable way. | |
| 130 | − | |
| 131 | −# Make the path relative to DESTDIR, not to prefix | |
| 132 | −ifndef DESTDIR | |
| 133 | −prefix = $(HOME) | |
| 134 | −endif | |
| 135 | −bindir_relative = bin | |
| 136 | −bindir = $(prefix)/$(bindir_relative) | |
| 137 | −mandir = share/man | |
| 138 | −infodir = share/info | |
| 139 | −perfexecdir = libexec/perf-core | |
| 140 | −sharedir = $(prefix)/share | |
| 141 | −template_dir = share/perf-core/templates | |
| 142 | −htmldir = share/doc/perf-doc | |
| 143 | −ifeq ($(prefix),/usr) | |
| 144 | −sysconfdir = /etc | |
| 145 | −ETC_PERFCONFIG = $(sysconfdir)/perfconfig | |
| 146 | −else | |
| 147 | −sysconfdir = $(prefix)/etc | |
| 148 | −ETC_PERFCONFIG = etc/perfconfig | |
| 149 | −endif | |
| 150 | −lib = lib | |
| 73 | +$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE | |
| 74 | + @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) | |
| 151 | 75 | |
| 152 | −export prefix bindir sharedir sysconfdir | |
| 76 | +CC = $(CROSS_COMPILE)gcc | |
| 77 | +AR = $(CROSS_COMPILE)ar | |
| 153 | 78 | |
| 154 | −RM = rm -f | |
| 155 | −MKDIR = mkdir | |
| 156 | −FIND = find | |
| 79 | +RM = rm -f | |
| 80 | +MKDIR = mkdir | |
| 81 | +FIND = find | |
| 157 | 82 | INSTALL = install |
| 158 | −FLEX = flex | |
| 159 | −BISON= bison | |
| 160 | − | |
| 161 | −# sparse is architecture-neutral, which means that we need to tell it | |
| 162 | −# explicitly what architecture to check for. Fix this up for yours.. | |
| 163 | −SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ | |
| 164 | − | |
| 165 | −ifneq ($(MAKECMDGOALS),clean) | |
| 166 | −ifneq ($(MAKECMDGOALS),tags) | |
| 167 | −-include config/feature-tests.mak | |
| 168 | − | |
| 169 | −ifeq ($(call get-executable,$(FLEX)),) | |
| 170 | − dummy := $(error Error: $(FLEX) is missing on this system, please install it) | |
| 171 | −endif | |
| 172 | − | |
| 173 | −ifeq ($(call get-executable,$(BISON)),) | |
| 174 | − dummy := $(error Error: $(BISON) is missing on this system, please install it) | |
| 175 | −endif | |
| 83 | +FLEX = flex | |
| 84 | +BISON = bison | |
| 85 | +STRIP = strip | |
| 176 | 86 | |
| 177 | −ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y) | |
| 178 | − CFLAGS := $(CFLAGS) -fstack-protector-all | |
| 179 | −endif | |
| 87 | +LK_DIR = $(srctree)/tools/lib/lk/ | |
| 88 | +TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/ | |
| 180 | 89 | |
| 181 | −ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wstack-protector,-Wstack-protector),y) | |
| 182 | − CFLAGS := $(CFLAGS) -Wstack-protector | |
| 183 | −endif | |
| 90 | +# include config/Makefile by default and rule out | |
| 91 | +# non-config cases | |
| 92 | +config := 1 | |
| 184 | 93 | |
| 185 | −ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wvolatile-register-var,-Wvolatile-register-var),y) | |
| 186 | − CFLAGS := $(CFLAGS) -Wvolatile-register-var | |
| 187 | −endif | |
| 94 | +NON_CONFIG_TARGETS := clean TAGS tags cscope help | |
| 188 | 95 | |
| 189 | −ifndef PERF_DEBUG | |
| 190 | − ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -D_FORTIFY_SOURCE=2,-D_FORTIFY_SOURCE=2),y) | |
| 191 | − CFLAGS := $(CFLAGS) -D_FORTIFY_SOURCE=2 | |
| 192 | − endif | |
| 96 | +ifdef MAKECMDGOALS | |
| 97 | +ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),) | |
| 98 | + config := 0 | |
| 193 | 99 | endif |
| 194 | − | |
| 195 | −### --- END CONFIGURATION SECTION --- | |
| 196 | − | |
| 197 | −ifeq ($(srctree),) | |
| 198 | −srctree := $(patsubst %/,%,$(dir $(shell pwd))) | |
| 199 | −srctree := $(patsubst %/,%,$(dir $(srctree))) | |
| 200 | −#$(info Determined 'srctree' to be $(srctree)) | |
| 201 | 100 | endif |
| 202 | 101 | |
| 203 | −ifneq ($(objtree),) | |
| 204 | −#$(info Determined 'objtree' to be $(objtree)) | |
| 102 | +ifeq ($(config),1) | |
| 103 | +include config/Makefile | |
| 205 | 104 | endif |
| 206 | 105 | |
| 207 | −ifneq ($(OUTPUT),) | |
| 208 | −#$(info Determined 'OUTPUT' to be $(OUTPUT)) | |
| 209 | −endif | |
| 106 | +export prefix bindir sharedir sysconfdir | |
| 210 | 107 | |
| 211 | −BASIC_CFLAGS = \ | |
| 212 | − -Iutil/include \ | |
| 213 | − -Iarch/$(ARCH)/include \ | |
| 214 | − $(if $(objtree),-I$(objtree)/arch/$(ARCH)/include/generated/uapi) \ | |
| 215 | − -I$(srctree)/arch/$(ARCH)/include/uapi \ | |
| 216 | − -I$(srctree)/arch/$(ARCH)/include \ | |
| 217 | − $(if $(objtree),-I$(objtree)/include/generated/uapi) \ | |
| 218 | − -I$(srctree)/include/uapi \ | |
| 219 | − -I$(srctree)/include \ | |
| 220 | − -I$(OUTPUT)util \ | |
| 221 | − -Iutil \ | |
| 222 | − -I. \ | |
| 223 | − -I$(TRACE_EVENT_DIR) \ | |
| 224 | − -I../lib/ \ | |
| 225 | − -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE | |
| 226 | − | |
| 227 | −BASIC_LDFLAGS = | |
| 228 | − | |
| 229 | −ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y) | |
| 230 | − BIONIC := 1 | |
| 231 | − EXTLIBS := $(filter-out -lrt,$(EXTLIBS)) | |
| 232 | − EXTLIBS := $(filter-out -lpthread,$(EXTLIBS)) | |
| 233 | − BASIC_CFLAGS += -I. | |
| 234 | −endif | |
| 235 | −endif # MAKECMDGOALS != tags | |
| 236 | −endif # MAKECMDGOALS != clean | |
| 108 | +# sparse is architecture-neutral, which means that we need to tell it | |
| 109 | +# explicitly what architecture to check for. Fix this up for yours.. | |
| 110 | +SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ | |
| 237 | 111 | |
| 238 | 112 | # Guard against environment variables |
| 239 | 113 | BUILTIN_OBJS = |
| @@ -247,20 +121,17 @@ SCRIPT_SH += perf-archive.sh · 7 unmodified lines | ||
| 247 | 121 | grep-libs = $(filter -l%,$(1)) |
| 248 | 122 | strip-libs = $(filter-out -l%,$(1)) |
| 249 | 123 | |
| 250 | −LK_DIR = ../lib/lk/ | |
| 251 | −TRACE_EVENT_DIR = ../lib/traceevent/ | |
| 252 | − | |
| 253 | 124 | LK_PATH=$(LK_DIR) |
| 254 | 125 | |
| 255 | 126 | ifneq ($(OUTPUT),) |
| 256 | − TE_PATH=$(OUTPUT) | |
| 127 | + TE_PATH=$(OUTPUT) | |
| 257 | 128 | ifneq ($(subdir),) |
| 258 | − LK_PATH=$(OUTPUT)$(LK_DIR) | |
| 129 | + LK_PATH=$(OUTPUT)$(LK_DIR) | |
| 259 | 130 | else |
| 260 | − LK_PATH=$(OUTPUT) | |
| 131 | + LK_PATH=$(OUTPUT) | |
| 261 | 132 | endif |
| 262 | 133 | else |
| 263 | − TE_PATH=$(TRACE_EVENT_DIR) | |
| 134 | + TE_PATH=$(TRACE_EVENT_DIR) | |
| 264 | 135 | endif |
| 265 | 136 | |
| 266 | 137 | LIBTRACEEVENT = $(TE_PATH)libtraceevent.a |
| @@ -278,10 +149,10 @@ export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP · 11 unmodified lines | ||
| 278 | 149 | python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so |
| 279 | 150 | |
| 280 | 151 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) |
| 281 | −PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) | |
| 152 | +PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBLK) | |
| 282 | 153 | |
| 283 | 154 | $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) |
| 284 | − $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ | |
| 155 | + $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \ | |
| 285 | 156 | --quiet build_ext; \ |
| 286 | 157 | mkdir -p $(OUTPUT)python && \ |
| 287 | 158 | cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/ |
| @@ -296,8 +167,6 @@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) · 8 unmodified lines | ||
| 296 | 167 | # |
| 297 | 168 | PROGRAMS += $(OUTPUT)perf |
| 298 | 169 | |
| 299 | −LANG_BINDINGS = | |
| 300 | − | |
| 301 | 170 | # what 'all' will build and 'install' will install, in perfexecdir |
| 302 | 171 | ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) |
| 303 | 172 | |
| @@ -306,10 +175,10 @@ OTHER_PROGRAMS = $(OUTPUT)perf · 2 unmodified lines | ||
| 306 | 175 | |
| 307 | 176 | # Set paths to tools early so that they can be used for version tests. |
| 308 | 177 | ifndef SHELL_PATH |
| 309 | − SHELL_PATH = /bin/sh | |
| 178 | + SHELL_PATH = /bin/sh | |
| 310 | 179 | endif |
| 311 | 180 | ifndef PERL_PATH |
| 312 | − PERL_PATH = /usr/bin/perl | |
| 181 | + PERL_PATH = /usr/bin/perl | |
| 313 | 182 | endif |
| 314 | 183 | |
| 315 | 184 | export PERL_PATH |
| @@ -557,79 +426,14 @@ BUILTIN_OBJS += $(OUTPUT)builtin-mem.o · 241 unmodified lines | ||
| 557 | 426 | |
| 558 | 427 | PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT) |
| 559 | 428 | |
| 560 | −# | |
| 561 | −# Platform specific tweaks | |
| 562 | −# | |
| 563 | −ifneq ($(MAKECMDGOALS),clean) | |
| 564 | −ifneq ($(MAKECMDGOALS),tags) | |
| 565 | − | |
| 566 | 429 | # We choose to avoid "if .. else if .. else .. endif endif" |
| 567 | 430 | # because maintaining the nesting to match is a pain. If |
| 568 | 431 | # we had "elif" things would have been much nicer... |
| 569 | 432 | |
| 570 | −ifdef NO_LIBELF | |
| 571 | − NO_DWARF := 1 | |
| 572 | − NO_DEMANGLE := 1 | |
| 573 | − NO_LIBUNWIND := 1 | |
| 574 | −else | |
| 575 | −FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) | |
| 576 | −ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF),libelf),y) | |
| 577 | − FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS) | |
| 578 | − ifeq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC),glibc),y) | |
| 579 | − LIBC_SUPPORT := 1 | |
| 580 | − endif | |
| 581 | − ifeq ($(BIONIC),1) | |
| 582 | − LIBC_SUPPORT := 1 | |
| 583 | − endif | |
| 584 | − ifeq ($(LIBC_SUPPORT),1) | |
| 585 | − msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev); | |
| 586 | − | |
| 587 | − NO_LIBELF := 1 | |
| 588 | − NO_DWARF := 1 | |
| 589 | − NO_DEMANGLE := 1 | |
| 590 | − else | |
| 591 | − msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); | |
| 592 | − endif | |
| 593 | −else | |
| 594 | − # for linking with debug library, run like: | |
| 595 | − # make DEBUG=1 LIBDW_DIR=/opt/libdw/ | |
| 596 | − ifdef LIBDW_DIR | |
| 597 | − LIBDW_CFLAGS := -I$(LIBDW_DIR)/include | |
| 598 | − LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib | |
| 599 | − endif | |
| 600 | − | |
| 601 | − FLAGS_DWARF=$(ALL_CFLAGS) $(LIBDW_CFLAGS) -ldw -lelf $(LIBDW_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) | |
| 602 | − ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF),libdw),y) | |
| 603 | − msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); | |
| 604 | − NO_DWARF := 1 | |
| 605 | − endif # Dwarf support | |
| 606 | −endif # SOURCE_LIBELF | |
| 607 | −endif # NO_LIBELF | |
| 608 | − | |
| 609 | −# There's only x86 (both 32 and 64) support for CFI unwind so far | |
| 610 | −ifneq ($(ARCH),x86) | |
| 611 | − NO_LIBUNWIND := 1 | |
| 612 | −endif | |
| 613 | − | |
| 614 | −ifndef NO_LIBUNWIND | |
| 615 | −# for linking with debug library, run like: | |
| 616 | −# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/ | |
| 617 | −ifdef LIBUNWIND_DIR | |
| 618 | − LIBUNWIND_CFLAGS := -I$(LIBUNWIND_DIR)/include | |
| 619 | − LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib | |
| 620 | −endif | |
| 621 | − | |
| 622 | −FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(ALL_CFLAGS) $(LIBUNWIND_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS) | |
| 623 | −ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND),libunwind),y) | |
| 624 | − msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99); | |
| 625 | − NO_LIBUNWIND := 1 | |
| 626 | −endif # Libunwind support | |
| 627 | −endif # NO_LIBUNWIND | |
| 628 | − | |
| 629 | 433 | -include arch/$(ARCH)/Makefile |
| 630 | 434 | |
| 631 | 435 | ifneq ($(OUTPUT),) |
| 632 | − BASIC_CFLAGS += -I$(OUTPUT) | |
| 436 | + CFLAGS += -I$(OUTPUT) | |
| 633 | 437 | endif |
| 634 | 438 | |
| 635 | 439 | ifdef NO_LIBELF |
| @@ -647,281 +451,74 @@ BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS)) · 11 unmodified lines | ||
| 647 | 451 | LIB_OBJS += $(OUTPUT)util/symbol-minimal.o |
| 648 | 452 | |
| 649 | 453 | else # NO_LIBELF |
| 650 | −BASIC_CFLAGS += -DLIBELF_SUPPORT | |
| 651 | − | |
| 652 | −FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) | |
| 653 | −ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y) | |
| 654 | − BASIC_CFLAGS += -DLIBELF_MMAP | |
| 655 | −endif | |
| 656 | − | |
| 657 | 454 | ifndef NO_DWARF |
| 658 | −ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) | |
| 659 | − msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); | |
| 660 | −else | |
| 661 | − BASIC_CFLAGS := -DDWARF_SUPPORT $(LIBDW_CFLAGS) $(BASIC_CFLAGS) | |
| 662 | − BASIC_LDFLAGS := $(LIBDW_LDFLAGS) $(BASIC_LDFLAGS) | |
| 663 | − EXTLIBS += -lelf -ldw | |
| 664 | − LIB_OBJS += $(OUTPUT)util/probe-finder.o | |
| 665 | − LIB_OBJS += $(OUTPUT)util/dwarf-aux.o | |
| 666 | −endif # PERF_HAVE_DWARF_REGS | |
| 455 | + LIB_OBJS += $(OUTPUT)util/probe-finder.o | |
| 456 | + LIB_OBJS += $(OUTPUT)util/dwarf-aux.o | |
| 667 | 457 | endif # NO_DWARF |
| 668 | 458 | endif # NO_LIBELF |
| 669 | 459 | |
| 670 | 460 | ifndef NO_LIBUNWIND |
| 671 | − BASIC_CFLAGS += -DLIBUNWIND_SUPPORT | |
| 672 | − EXTLIBS += $(LIBUNWIND_LIBS) | |
| 673 | − BASIC_CFLAGS := $(LIBUNWIND_CFLAGS) $(BASIC_CFLAGS) | |
| 674 | − BASIC_LDFLAGS := $(LIBUNWIND_LDFLAGS) $(BASIC_LDFLAGS) | |
| 675 | − LIB_OBJS += $(OUTPUT)util/unwind.o | |
| 461 | + LIB_OBJS += $(OUTPUT)util/unwind.o | |
| 676 | 462 | endif |
| 677 | 463 | |
| 678 | 464 | ifndef NO_LIBAUDIT |
| 679 | − FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit | |
| 680 | − ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT),libaudit),y) | |
| 681 | − msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev); | |
| 682 | − else | |
| 683 | − BASIC_CFLAGS += -DLIBAUDIT_SUPPORT | |
| 684 | − BUILTIN_OBJS += $(OUTPUT)builtin-trace.o | |
| 685 | − EXTLIBS += -laudit | |
| 686 | − endif | |
| 465 | + BUILTIN_OBJS += $(OUTPUT)builtin-trace.o | |
| 687 | 466 | endif |
| 688 | 467 | |
| 689 | 468 | ifndef NO_SLANG |
| 690 | − FLAGS_SLANG=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -I/usr/include/slang -lslang | |
| 691 | − ifneq ($(call try-cc,$(SOURCE_SLANG),$(FLAGS_SLANG),libslang),y) | |
| 692 | − msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev); | |
| 693 | − else | |
| 694 | − # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h | |
| 695 | − BASIC_CFLAGS += -I/usr/include/slang | |
| 696 | − BASIC_CFLAGS += -DSLANG_SUPPORT | |
| 697 | − EXTLIBS += -lslang | |
| 698 | − LIB_OBJS += $(OUTPUT)ui/browser.o | |
| 699 | − LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o | |
| 700 | − LIB_OBJS += $(OUTPUT)ui/browsers/hists.o | |
| 701 | − LIB_OBJS += $(OUTPUT)ui/browsers/map.o | |
| 702 | − LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o | |
| 703 | − LIB_OBJS += $(OUTPUT)ui/tui/setup.o | |
| 704 | − LIB_OBJS += $(OUTPUT)ui/tui/util.o | |
| 705 | − LIB_OBJS += $(OUTPUT)ui/tui/helpline.o | |
| 706 | − LIB_OBJS += $(OUTPUT)ui/tui/progress.o | |
| 707 | − LIB_H += ui/browser.h | |
| 708 | − LIB_H += ui/browsers/map.h | |
| 709 | − LIB_H += ui/keysyms.h | |
| 710 | − LIB_H += ui/libslang.h | |
| 711 | − endif | |
| 469 | + LIB_OBJS += $(OUTPUT)ui/browser.o | |
| 470 | + LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o | |
| 471 | + LIB_OBJS += $(OUTPUT)ui/browsers/hists.o | |
| 472 | + LIB_OBJS += $(OUTPUT)ui/browsers/map.o | |
| 473 | + LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o | |
| 474 | + LIB_OBJS += $(OUTPUT)ui/tui/setup.o | |
| 475 | + LIB_OBJS += $(OUTPUT)ui/tui/util.o | |
| 476 | + LIB_OBJS += $(OUTPUT)ui/tui/helpline.o | |
| 477 | + LIB_OBJS += $(OUTPUT)ui/tui/progress.o | |
| 478 | + LIB_H += ui/browser.h | |
| 479 | + LIB_H += ui/browsers/map.h | |
| 480 | + LIB_H += ui/keysyms.h | |
| 481 | + LIB_H += ui/libslang.h | |
| 712 | 482 | endif |
| 713 | 483 | |
| 714 | 484 | ifndef NO_GTK2 |
| 715 | − FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) | |
| 716 | − ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2),gtk2),y) | |
| 717 | − msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); | |
| 718 | − else | |
| 719 | − ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2),-DHAVE_GTK_INFO_BAR),y) | |
| 720 | − BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR | |
| 721 | − endif | |
| 722 | − BASIC_CFLAGS += -DGTK2_SUPPORT | |
| 723 | − BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null) | |
| 724 | − EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null) | |
| 725 | − LIB_OBJS += $(OUTPUT)ui/gtk/browser.o | |
| 726 | − LIB_OBJS += $(OUTPUT)ui/gtk/hists.o | |
| 727 | − LIB_OBJS += $(OUTPUT)ui/gtk/setup.o | |
| 728 | − LIB_OBJS += $(OUTPUT)ui/gtk/util.o | |
| 729 | − LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o | |
| 730 | − LIB_OBJS += $(OUTPUT)ui/gtk/progress.o | |
| 731 | − LIB_OBJS += $(OUTPUT)ui/gtk/annotate.o | |
| 732 | − endif | |
| 485 | + LIB_OBJS += $(OUTPUT)ui/gtk/browser.o | |
| 486 | + LIB_OBJS += $(OUTPUT)ui/gtk/hists.o | |
| 487 | + LIB_OBJS += $(OUTPUT)ui/gtk/setup.o | |
| 488 | + LIB_OBJS += $(OUTPUT)ui/gtk/util.o | |
| 489 | + LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o | |
| 490 | + LIB_OBJS += $(OUTPUT)ui/gtk/progress.o | |
| 491 | + LIB_OBJS += $(OUTPUT)ui/gtk/annotate.o | |
| 733 | 492 | endif |
| 734 | 493 | |
| 735 | −ifdef NO_LIBPERL | |
| 736 | − BASIC_CFLAGS += -DNO_LIBPERL | |
| 737 | −else | |
| 738 | − PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null) | |
| 739 | − PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS)) | |
| 740 | − PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS)) | |
| 741 | − PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` | |
| 742 | − FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) | |
| 743 | − | |
| 744 | − ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED),perl),y) | |
| 745 | − BASIC_CFLAGS += -DNO_LIBPERL | |
| 746 | − else | |
| 747 | − ALL_LDFLAGS += $(PERL_EMBED_LDFLAGS) | |
| 748 | − EXTLIBS += $(PERL_EMBED_LIBADD) | |
| 749 | − LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o | |
| 750 | − LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o | |
| 751 | − endif | |
| 494 | +ifndef NO_LIBPERL | |
| 495 | + LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o | |
| 496 | + LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o | |
| 752 | 497 | endif |
| 753 | 498 | |
| 754 | −disable-python = $(eval $(disable-python_code)) | |
| 755 | −define disable-python_code | |
| 756 | − BASIC_CFLAGS += -DNO_LIBPYTHON | |
| 757 | − $(if $(1),$(warning No $(1) was found)) | |
| 758 | − $(warning Python support will not be built) | |
| 759 | −endef | |
| 760 | − | |
| 761 | −override PYTHON := \ | |
| 762 | − $(call get-executable-or-default,PYTHON,python) | |
| 763 | − | |
| 764 | −ifndef PYTHON | |
| 765 | − $(call disable-python,python interpreter) | |
| 766 | −else | |
| 767 | − | |
| 768 | − PYTHON_WORD := $(call shell-wordify,$(PYTHON)) | |
| 769 | − | |
| 770 | − ifdef NO_LIBPYTHON | |
| 771 | − $(call disable-python) | |
| 772 | − else | |
| 773 | − | |
| 774 | − override PYTHON_CONFIG := \ | |
| 775 | − $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config) | |
| 776 | − | |
| 777 | − ifndef PYTHON_CONFIG | |
| 778 | − $(call disable-python,python-config tool) | |
| 779 | − else | |
| 780 | − | |
| 781 | − PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG)) | |
| 782 | − | |
| 783 | − PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) | |
| 784 | − PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS)) | |
| 785 | − PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) | |
| 786 | − PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) | |
| 787 | − FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) | |
| 788 | − | |
| 789 | − ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED),python),y) | |
| 790 | − $(call disable-python,Python.h (for Python 2.x)) | |
| 791 | − else | |
| 792 | − | |
| 793 | − ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED),python version),y) | |
| 794 | − $(warning Python 3 is not yet supported; please set) | |
| 795 | − $(warning PYTHON and/or PYTHON_CONFIG appropriately.) | |
| 796 | − $(warning If you also have Python 2 installed, then) | |
| 797 | − $(warning try something like:) | |
| 798 | − $(warning $(and ,)) | |
| 799 | − $(warning $(and ,) make PYTHON=python2) | |
| 800 | − $(warning $(and ,)) | |
| 801 | − $(warning Otherwise, disable Python support entirely:) | |
| 802 | − $(warning $(and ,)) | |
| 803 | − $(warning $(and ,) make NO_LIBPYTHON=1) | |
| 804 | − $(warning $(and ,)) | |
| 805 | − $(error $(and ,)) | |
| 806 | − else | |
| 807 | − ALL_LDFLAGS += $(PYTHON_EMBED_LDFLAGS) | |
| 808 | − EXTLIBS += $(PYTHON_EMBED_LIBADD) | |
| 809 | − LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o | |
| 810 | − LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o | |
| 811 | − LANG_BINDINGS += $(OUTPUT)python/perf.so | |
| 812 | − endif | |
| 813 | − | |
| 814 | − endif | |
| 815 | − endif | |
| 816 | − endif | |
| 817 | −endif | |
| 818 | − | |
| 819 | −ifdef NO_DEMANGLE | |
| 820 | − BASIC_CFLAGS += -DNO_DEMANGLE | |
| 821 | −else | |
| 822 | − ifdef HAVE_CPLUS_DEMANGLE | |
| 823 | − EXTLIBS += -liberty | |
| 824 | − BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE | |
| 825 | − else | |
| 826 | − FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd | |
| 827 | − has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD),libbfd) | |
| 828 | − ifeq ($(has_bfd),y) | |
| 829 | − EXTLIBS += -lbfd | |
| 830 | − else | |
| 831 | − FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty | |
| 832 | − has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY),liberty) | |
| 833 | − ifeq ($(has_bfd_iberty),y) | |
| 834 | − EXTLIBS += -lbfd -liberty | |
| 835 | − else | |
| 836 | − FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz | |
| 837 | − has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z),libz) | |
| 838 | − ifeq ($(has_bfd_iberty_z),y) | |
| 839 | − EXTLIBS += -lbfd -liberty -lz | |
| 840 | − else | |
| 841 | − FLAGS_CPLUS_DEMANGLE=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -liberty | |
| 842 | − has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE),demangle) | |
| 843 | − ifeq ($(has_cplus_demangle),y) | |
| 844 | − EXTLIBS += -liberty | |
| 845 | − BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE | |
| 846 | − else | |
| 847 | − msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling) | |
| 848 | − BASIC_CFLAGS += -DNO_DEMANGLE | |
| 849 | − endif | |
| 850 | − endif | |
| 851 | − endif | |
| 852 | − endif | |
| 853 | − endif | |
| 499 | +ifndef NO_LIBPYTHON | |
| 500 | + LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o | |
| 501 | + LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o | |
| 854 | 502 | endif |
| 855 | 503 | |
| 856 | 504 | ifeq ($(NO_PERF_REGS),0) |
| 857 | − ifeq ($(ARCH),x86) | |
| 858 | − LIB_H += arch/x86/include/perf_regs.h | |
| 859 | − endif | |
| 860 | − BASIC_CFLAGS += -DHAVE_PERF_REGS | |
| 861 | −endif | |
| 862 | − | |
| 863 | −ifndef NO_STRLCPY | |
| 864 | − ifeq ($(call try-cc,$(SOURCE_STRLCPY),,-DHAVE_STRLCPY),y) | |
| 865 | − BASIC_CFLAGS += -DHAVE_STRLCPY | |
| 866 | − endif | |
| 867 | −endif | |
| 868 | − | |
| 869 | −ifndef NO_ON_EXIT | |
| 870 | − ifeq ($(call try-cc,$(SOURCE_ON_EXIT),,-DHAVE_ON_EXIT),y) | |
| 871 | − BASIC_CFLAGS += -DHAVE_ON_EXIT | |
| 872 | − endif | |
| 873 | −endif | |
| 874 | − | |
| 875 | −ifndef NO_BACKTRACE | |
| 876 | − ifeq ($(call try-cc,$(SOURCE_BACKTRACE),,-DBACKTRACE_SUPPORT),y) | |
| 877 | − BASIC_CFLAGS += -DBACKTRACE_SUPPORT | |
| 878 | − endif | |
| 505 | + ifeq ($(ARCH),x86) | |
| 506 | + LIB_H += arch/x86/include/perf_regs.h | |
| 507 | + endif | |
| 879 | 508 | endif |
| 880 | 509 | |
| 881 | 510 | ifndef NO_LIBNUMA |
| 882 | − FLAGS_LIBNUMA = $(ALL_CFLAGS) $(ALL_LDFLAGS) -lnuma | |
| 883 | − ifneq ($(call try-cc,$(SOURCE_LIBNUMA),$(FLAGS_LIBNUMA),libnuma),y) | |
| 884 | − msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev); | |
| 885 | − else | |
| 886 | − BASIC_CFLAGS += -DLIBNUMA_SUPPORT | |
| 887 | − BUILTIN_OBJS += $(OUTPUT)bench/numa.o | |
| 888 | − EXTLIBS += -lnuma | |
| 889 | − endif | |
| 511 | + BUILTIN_OBJS += $(OUTPUT)bench/numa.o | |
| 890 | 512 | endif |
| 891 | 513 | |
| 892 | 514 | ifdef ASCIIDOC8 |
| 893 | − export ASCIIDOC8 | |
| 515 | + export ASCIIDOC8 | |
| 894 | 516 | endif |
| 895 | 517 | |
| 896 | −endif # MAKECMDGOALS != tags | |
| 897 | −endif # MAKECMDGOALS != clean | |
| 898 | − | |
| 899 | −# Shell quote (do not use $(call) to accommodate ancient setups); | |
| 900 | − | |
| 901 | −ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) | |
| 902 | − | |
| 903 | −DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) | |
| 904 | −bindir_SQ = $(subst ','\'',$(bindir)) | |
| 905 | −bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) | |
| 906 | −mandir_SQ = $(subst ','\'',$(mandir)) | |
| 907 | −infodir_SQ = $(subst ','\'',$(infodir)) | |
| 908 | −perfexecdir_SQ = $(subst ','\'',$(perfexecdir)) | |
| 909 | −template_dir_SQ = $(subst ','\'',$(template_dir)) | |
| 910 | −htmldir_SQ = $(subst ','\'',$(htmldir)) | |
| 911 | −prefix_SQ = $(subst ','\'',$(prefix)) | |
| 912 | −sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) | |
| 913 | − | |
| 914 | −SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) | |
| 915 | − | |
| 916 | 518 | LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group |
| 917 | 519 | |
| 918 | −ALL_CFLAGS += $(BASIC_CFLAGS) | |
| 919 | −ALL_CFLAGS += $(ARCH_CFLAGS) | |
| 920 | −ALL_LDFLAGS += $(BASIC_LDFLAGS) | |
| 921 | − | |
| 922 | 520 | export INSTALL SHELL_PATH |
| 923 | 521 | |
| 924 | − | |
| 925 | 522 | ### Build rules |
| 926 | 523 | |
| 927 | 524 | SHELL = $(SHELL_PATH) |
| @@ -939,20 +536,20 @@ strip: $(PROGRAMS) $(OUTPUT)perf · 11 unmodified lines | ||
| 939 | 536 | $(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS |
| 940 | 537 | $(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \ |
| 941 | 538 | '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ |
| 942 | − $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@ | |
| 539 | + $(CFLAGS) -c $(filter %.c,$^) -o $@ | |
| 943 | 540 | |
| 944 | 541 | $(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS) |
| 945 | − $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \ | |
| 542 | + $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(OUTPUT)perf.o \ | |
| 946 | 543 | $(BUILTIN_OBJS) $(LIBS) -o $@ |
| 947 | 544 | |
| 948 | 545 | $(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS |
| 949 | − $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ | |
| 546 | + $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \ | |
| 950 | 547 | '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ |
| 951 | 548 | '-DPERF_MAN_PATH="$(mandir_SQ)"' \ |
| 952 | 549 | '-DPERF_INFO_PATH="$(infodir_SQ)"' $< |
| 953 | 550 | |
| 954 | 551 | $(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS |
| 955 | − $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ | |
| 552 | + $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \ | |
| 956 | 553 | '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ |
| 957 | 554 | '-DPERF_MAN_PATH="$(mandir_SQ)"' \ |
| 958 | 555 | '-DPERF_INFO_PATH="$(infodir_SQ)"' $< |
| @@ -977,77 +574,77 @@ $(OUTPUT)perf.o perf.spec \ · 18 unmodified lines | ||
| 977 | 574 | # over the general rule for .o |
| 978 | 575 | |
| 979 | 576 | $(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS |
| 980 | − $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(ALL_CFLAGS) -w $< | |
| 577 | + $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -w $< | |
| 981 | 578 | |
| 982 | 579 | $(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS |
| 983 | − $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(ALL_CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w $< | |
| 580 | + $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w $< | |
| 984 | 581 | |
| 985 | 582 | $(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS |
| 986 | − $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< | |
| 583 | + $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $< | |
| 987 | 584 | $(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS |
| 988 | − $(QUIET_CC)$(CC) -o $@ -E $(ALL_CFLAGS) $< | |
| 585 | + $(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $< | |
| 989 | 586 | $(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS |
| 990 | − $(QUIET_CC)$(CC) -o $@ -S $(ALL_CFLAGS) $< | |
| 587 | + $(QUIET_CC)$(CC) -o $@ -S $(CFLAGS) $< | |
| 991 | 588 | $(OUTPUT)%.o: %.S |
| 992 | − $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< | |
| 589 | + $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $< | |
| 993 | 590 | $(OUTPUT)%.s: %.S |
| 994 | − $(QUIET_CC)$(CC) -o $@ -E $(ALL_CFLAGS) $< | |
| 591 | + $(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $< | |
| 995 | 592 | |
| 996 | 593 | $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS |
| 997 | − $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ | |
| 594 | + $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \ | |
| 998 | 595 | '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \ |
| 999 | 596 | '-DPREFIX="$(prefix_SQ)"' \ |
| 1000 | 597 | $< |
| 1001 | 598 | |
| 1002 | 599 | $(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS |
| 1003 | − $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ | |
| 600 | + $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \ | |
| 1004 | 601 | '-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \ |
| 1005 | 602 | $< |
| 1006 | 603 | |
| 1007 | 604 | $(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS |
| 1008 | − $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ | |
| 605 | + $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \ | |
| 1009 | 606 | -DPYTHONPATH='"$(OUTPUT)python"' \ |
| 1010 | 607 | -DPYTHON='"$(PYTHON_WORD)"' \ |
| 1011 | 608 | $< |
| 1012 | 609 | |
| 1013 | 610 | $(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS |
| 1014 | − $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | |
| 611 | + $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | |
| 1015 | 612 | |
| 1016 | 613 | $(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS |
| 1017 | − $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< | |
| 614 | + $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< | |
| 1018 | 615 | |
| 1019 | 616 | $(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS |
| 1020 | − $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< | |
| 617 | + $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< | |
| 1021 | 618 | |
| 1022 | 619 | $(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS |
| 1023 | − $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< | |
| 620 | + $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< | |
| 1024 | 621 | |
| 1025 | 622 | $(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS |
| 1026 | − $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< | |
| 623 | + $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< | |
| 1027 | 624 | |
| 1028 | 625 | $(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS |
| 1029 | − $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< | |
| 626 | + $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< | |
| 1030 | 627 | |
| 1031 | 628 | $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS |
| 1032 | − $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | |
| 629 | + $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | |
| 1033 | 630 | |
| 1034 | 631 | $(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS |
| 1035 | − $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls $< | |
| 632 | + $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-redundant-decls $< | |
| 1036 | 633 | |
| 1037 | 634 | $(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS |
| 1038 | − $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< | |
| 635 | + $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< | |
| 1039 | 636 | |
| 1040 | 637 | $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS |
| 1041 | − $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< | |
| 638 | + $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< | |
| 1042 | 639 | |
| 1043 | 640 | $(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS |
| 1044 | − $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< | |
| 641 | + $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< | |
| 1045 | 642 | |
| 1046 | 643 | $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS |
| 1047 | − $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< | |
| 644 | + $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< | |
| 1048 | 645 | |
| 1049 | 646 | $(OUTPUT)perf-%: %.o $(PERFLIBS) |
| 1050 | − $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) | |
| 647 | + $(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS) | |
| 1051 | 648 | |
| 1052 | 649 | $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) |
| 1053 | 650 | $(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) |
| @@ -1134,7 +731,7 @@ cscope: · 80 unmodified lines | ||
| 1134 | 731 | $(FIND) . -name '*.[hcS]' -print | xargs cscope -b |
| 1135 | 732 | |
| 1136 | 733 | ### Detect prefix changes |
| 1137 | −TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\ | |
| 734 | +TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\ | |
| 1138 | 735 | $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ) |
| 1139 | 736 | |
| 1140 | 737 | $(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS |
| @@ -1155,7 +752,7 @@ check: $(OUTPUT)common-cmds.h · 14 unmodified lines | ||
| 1155 | 752 | then \ |
| 1156 | 753 | for i in *.c */*.c; \ |
| 1157 | 754 | do \ |
| 1158 | − sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \ | |
| 755 | + sparse $(CFLAGS) $(SPARSE_FLAGS) $$i || exit; \ | |
| 1159 | 756 | done; \ |
| 1160 | 757 | else \ |
| 1161 | 758 | exit 1; \ |
| @@ -1163,13 +760,6 @@ check: $(OUTPUT)common-cmds.h · 1 unmodified line | ||
| 1163 | 760 | |
| 1164 | 761 | ### Installation rules |
| 1165 | 762 | |
| 1166 | −ifneq ($(filter /%,$(firstword $(perfexecdir))),) | |
| 1167 | −perfexec_instdir = $(perfexecdir) | |
| 1168 | −else | |
| 1169 | −perfexec_instdir = $(prefix)/$(perfexecdir) | |
| 1170 | −endif | |
| 1171 | −perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) | |
| 1172 | − | |
| 1173 | 763 | install-bin: all |
| 1174 | 764 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' |
| 1175 | 765 | $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)' |
| @@ -323,13 +323,20 @@ static void hists__baseline_only(struct hists *hists) · 322 unmodified lines | ||
| 323 | 323 | |
| 324 | 324 | static void hists__precompute(struct hists *hists) |
| 325 | 325 | { |
| 326 | − struct rb_node *next = rb_first(&hists->entries); | |
| 326 | + struct rb_root *root; | |
| 327 | + struct rb_node *next; | |
| 328 | + | |
| 329 | + if (sort__need_collapse) | |
| 330 | + root = &hists->entries_collapsed; | |
| 331 | + else | |
| 332 | + root = hists->entries_in; | |
| 327 | 333 | |
| 334 | + next = rb_first(root); | |
| 328 | 335 | while (next != NULL) { |
| 329 | − struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); | |
| 336 | + struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in); | |
| 330 | 337 | struct hist_entry *pair = hist_entry__next_pair(he); |
| 331 | 338 | |
| 332 | − next = rb_next(&he->rb_node); | |
| 339 | + next = rb_next(&he->rb_node_in); | |
| 333 | 340 | if (!pair) |
| 334 | 341 | continue; |
| 335 | 342 | |
| @@ -457,7 +464,7 @@ static void hists__process(struct hists *old, struct hists *new) · 121 unmodified lines | ||
| 457 | 464 | hists__output_resort(new); |
| 458 | 465 | } |
| 459 | 466 | |
| 460 | − hists__fprintf(new, true, 0, 0, stdout); | |
| 467 | + hists__fprintf(new, true, 0, 0, 0, stdout); | |
| 461 | 468 | } |
| 462 | 469 | |
| 463 | 470 | static int __cmd_diff(void) |
| @@ -611,9 +618,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) · 147 unmodified lines | ||
| 611 | 618 | |
| 612 | 619 | setup_pager(); |
| 613 | 620 | |
| 614 | − sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL); | |
| 615 | − sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", NULL); | |
| 616 | − sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", NULL); | |
| 621 | + sort__setup_elide(NULL); | |
| 617 | 622 | |
| 618 | 623 | return __cmd_diff(); |
| 619 | 624 | } |
| @@ -328,6 +328,7 @@ static int kvm_events_hash_fn(u64 key) · 327 unmodified lines | ||
| 328 | 328 | static bool kvm_event_expand(struct kvm_event *event, int vcpu_id) |
| 329 | 329 | { |
| 330 | 330 | int old_max_vcpu = event->max_vcpu; |
| 331 | + void *prev; | |
| 331 | 332 | |
| 332 | 333 | if (vcpu_id < event->max_vcpu) |
| 333 | 334 | return true; |
| @@ -335,9 +336,11 @@ static bool kvm_event_expand(struct kvm_event *event, int vcpu_id) · 1 unmodified line | ||
| 335 | 336 | while (event->max_vcpu <= vcpu_id) |
| 336 | 337 | event->max_vcpu += DEFAULT_VCPU_NUM; |
| 337 | 338 | |
| 339 | + prev = event->vcpu; | |
| 338 | 340 | event->vcpu = realloc(event->vcpu, |
| 339 | 341 | event->max_vcpu * sizeof(*event->vcpu)); |
| 340 | 342 | if (!event->vcpu) { |
| 343 | + free(prev); | |
| 341 | 344 | pr_err("Not enough memory\n"); |
| 342 | 345 | return false; |
| 343 | 346 | } |
| @@ -198,7 +198,6 @@ static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg) · 197 unmodified lines | ||
| 198 | 198 | return; |
| 199 | 199 | |
| 200 | 200 | signal(signr, SIG_DFL); |
| 201 | − kill(getpid(), signr); | |
| 202 | 201 | } |
| 203 | 202 | |
| 204 | 203 | static bool perf_evlist__equal(struct perf_evlist *evlist, |
| @@ -404,6 +403,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) · 199 unmodified lines | ||
| 404 | 403 | signal(SIGCHLD, sig_handler); |
| 405 | 404 | signal(SIGINT, sig_handler); |
| 406 | 405 | signal(SIGUSR1, sig_handler); |
| 406 | + signal(SIGTERM, sig_handler); | |
| 407 | 407 | |
| 408 | 408 | if (!output_name) { |
| 409 | 409 | if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) |
| @@ -52,6 +52,7 @@ struct perf_report { · 51 unmodified lines | ||
| 52 | 52 | symbol_filter_t annotate_init; |
| 53 | 53 | const char *cpu_list; |
| 54 | 54 | const char *symbol_filter_str; |
| 55 | + float min_percent; | |
| 55 | 56 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
| 56 | 57 | }; |
| 57 | 58 | |
| @@ -61,6 +62,11 @@ static int perf_report_config(const char *var, const char *value, void *cb) · 3 unmodified lines | ||
| 61 | 62 | symbol_conf.event_group = perf_config_bool(var, value); |
| 62 | 63 | return 0; |
| 63 | 64 | } |
| 65 | + if (!strcmp(var, "report.percent-limit")) { | |
| 66 | + struct perf_report *rep = cb; | |
| 67 | + rep->min_percent = strtof(value, NULL); | |
| 68 | + return 0; | |
| 69 | + } | |
| 64 | 70 | |
| 65 | 71 | return perf_default_config(var, value, cb); |
| 66 | 72 | } |
| @@ -187,6 +193,9 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool, · 120 unmodified lines | ||
| 187 | 193 | for (i = 0; i < sample->branch_stack->nr; i++) { |
| 188 | 194 | if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym)) |
| 189 | 195 | continue; |
| 196 | + | |
| 197 | + err = -ENOMEM; | |
| 198 | + | |
| 190 | 199 | /* |
| 191 | 200 | * The report shows the percentage of total branches captured |
| 192 | 201 | * and not events sampled. Thus we use a pseudo period of 1. |
| @@ -195,7 +204,6 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool, · 2 unmodified lines | ||
| 195 | 204 | &bi[i], 1, 1); |
| 196 | 205 | if (he) { |
| 197 | 206 | struct annotation *notes; |
| 198 | − err = -ENOMEM; | |
| 199 | 207 | bx = he->branch_info; |
| 200 | 208 | if (bx->from.sym && use_browser == 1 && sort__has_sym) { |
| 201 | 209 | notes = symbol__annotation(bx->from.sym); |
| @@ -226,11 +234,12 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool, · 24 unmodified lines | ||
| 226 | 234 | } |
| 227 | 235 | evsel->hists.stats.total_period += 1; |
| 228 | 236 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); |
| 229 | − err = 0; | |
| 230 | 237 | } else |
| 231 | − return -ENOMEM; | |
| 238 | + goto out; | |
| 232 | 239 | } |
| 240 | + err = 0; | |
| 233 | 241 | out: |
| 242 | + free(bi); | |
| 234 | 243 | return err; |
| 235 | 244 | } |
| 236 | 245 | |
| @@ -294,6 +303,7 @@ static int process_sample_event(struct perf_tool *tool, · 57 unmodified lines | ||
| 294 | 303 | { |
| 295 | 304 | struct perf_report *rep = container_of(tool, struct perf_report, tool); |
| 296 | 305 | struct addr_location al; |
| 306 | + int ret; | |
| 297 | 307 | |
| 298 | 308 | if (perf_event__preprocess_sample(event, machine, &al, sample, |
| 299 | 309 | rep->annotate_init) < 0) { |
| @@ -308,28 +318,25 @@ static int process_sample_event(struct perf_tool *tool, · 8 unmodified lines | ||
| 308 | 318 | if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) |
| 309 | 319 | return 0; |
| 310 | 320 | |
| 311 | − if (sort__branch_mode == 1) { | |
| 312 | − if (perf_report__add_branch_hist_entry(tool, &al, sample, | |
| 313 | − evsel, machine)) { | |
| 321 | + if (sort__mode == SORT_MODE__BRANCH) { | |
| 322 | + ret = perf_report__add_branch_hist_entry(tool, &al, sample, | |
| 323 | + evsel, machine); | |
| 324 | + if (ret < 0) | |
| 314 | 325 | pr_debug("problem adding lbr entry, skipping event\n"); |
| 315 | − return -1; | |
| 316 | − } | |
| 317 | 326 | } else if (rep->mem_mode == 1) { |
| 318 | − if (perf_report__add_mem_hist_entry(tool, &al, sample, | |
| 319 | − evsel, machine, event)) { | |
| 327 | + ret = perf_report__add_mem_hist_entry(tool, &al, sample, | |
| 328 | + evsel, machine, event); | |
| 329 | + if (ret < 0) | |
| 320 | 330 | pr_debug("problem adding mem entry, skipping event\n"); |
| 321 | − return -1; | |
| 322 | − } | |
| 323 | 331 | } else { |
| 324 | 332 | if (al.map != NULL) |
| 325 | 333 | al.map->dso->hit = 1; |
| 326 | 334 | |
| 327 | − if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) { | |
| 335 | + ret = perf_evsel__add_hist_entry(evsel, &al, sample, machine); | |
| 336 | + if (ret < 0) | |
| 328 | 337 | pr_debug("problem incrementing symbol period, skipping event\n"); |
| 329 | − return -1; | |
| 330 | − } | |
| 331 | 338 | } |
| 332 | − return 0; | |
| 339 | + return ret; | |
| 333 | 340 | } |
| 334 | 341 | |
| 335 | 342 | static int process_read_event(struct perf_tool *tool, |
| @@ -384,7 +391,7 @@ static int perf_report__setup_sample_type(struct perf_report *rep) · 48 unmodified lines | ||
| 384 | 391 | } |
| 385 | 392 | } |
| 386 | 393 | |
| 387 | − if (sort__branch_mode == 1) { | |
| 394 | + if (sort__mode == SORT_MODE__BRANCH) { | |
| 388 | 395 | if (!self->fd_pipe && |
| 389 | 396 | !(sample_type & PERF_SAMPLE_BRANCH_STACK)) { |
| 390 | 397 | ui__error("Selected -b but no branch data. " |
| @@ -455,7 +462,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, · 64 unmodified lines | ||
| 455 | 462 | continue; |
| 456 | 463 | |
| 457 | 464 | hists__fprintf_nr_sample_events(rep, hists, evname, stdout); |
| 458 | − hists__fprintf(hists, true, 0, 0, stdout); | |
| 465 | + hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout); | |
| 459 | 466 | fprintf(stdout, "\n\n"); |
| 460 | 467 | } |
| 461 | 468 | |
| @@ -574,8 +581,8 @@ static int __cmd_report(struct perf_report *rep) · 112 unmodified lines | ||
| 574 | 581 | if (use_browser > 0) { |
| 575 | 582 | if (use_browser == 1) { |
| 576 | 583 | ret = perf_evlist__tui_browse_hists(session->evlist, |
| 577 | − help, | |
| 578 | − NULL, | |
| 584 | + help, NULL, | |
| 585 | + rep->min_percent, | |
| 579 | 586 | &session->header.env); |
| 580 | 587 | /* |
| 581 | 588 | * Usually "ret" is the last pressed key, and we only |
| @@ -586,7 +593,7 @@ static int __cmd_report(struct perf_report *rep) · 4 unmodified lines | ||
| 586 | 593 | |
| 587 | 594 | } else if (use_browser == 2) { |
| 588 | 595 | perf_evlist__gtk_browse_hists(session->evlist, help, |
| 589 | − NULL); | |
| 596 | + NULL, rep->min_percent); | |
| 590 | 597 | } |
| 591 | 598 | } else |
| 592 | 599 | perf_evlist__tty_browse_hists(session->evlist, rep, help); |
| @@ -691,7 +698,19 @@ static int · 98 unmodified lines | ||
| 691 | 698 | parse_branch_mode(const struct option *opt __maybe_unused, |
| 692 | 699 | const char *str __maybe_unused, int unset) |
| 693 | 700 | { |
| 694 | − sort__branch_mode = !unset; | |
| 701 | + int *branch_mode = opt->value; | |
| 702 | + | |
| 703 | + *branch_mode = !unset; | |
| 704 | + return 0; | |
| 705 | +} | |
| 706 | + | |
| 707 | +static int | |
| 708 | +parse_percent_limit(const struct option *opt, const char *str, | |
| 709 | + int unset __maybe_unused) | |
| 710 | +{ | |
| 711 | + struct perf_report *rep = opt->value; | |
| 712 | + | |
| 713 | + rep->min_percent = strtof(str, NULL); | |
| 695 | 714 | return 0; |
| 696 | 715 | } |
| 697 | 716 | |
| @@ -700,6 +719,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) · 2 unmodified lines | ||
| 700 | 719 | struct perf_session *session; |
| 701 | 720 | struct stat st; |
| 702 | 721 | bool has_br_stack = false; |
| 722 | + int branch_mode = -1; | |
| 703 | 723 | int ret = -1; |
| 704 | 724 | char callchain_default_opt[] = "fractal,0.5,callee"; |
| 705 | 725 | const char * const report_usage[] = { |
| @@ -796,17 +816,19 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) · 90 unmodified lines | ||
| 796 | 816 | "Show a column with the sum of periods"), |
| 797 | 817 | OPT_BOOLEAN(0, "group", &symbol_conf.event_group, |
| 798 | 818 | "Show event group information together"), |
| 799 | − OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "", | |
| 819 | + OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "", | |
| 800 | 820 | "use branch records for histogram filling", parse_branch_mode), |
| 801 | 821 | OPT_STRING(0, "objdump", &objdump_path, "path", |
| 802 | 822 | "objdump binary to use for disassembly and annotations"), |
| 803 | 823 | OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, |
| 804 | 824 | "Disable symbol demangling"), |
| 805 | 825 | OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"), |
| 826 | + OPT_CALLBACK(0, "percent-limit", &report, "percent", | |
| 827 | + "Don't show entries under that percent", parse_percent_limit), | |
| 806 | 828 | OPT_END() |
| 807 | 829 | }; |
| 808 | 830 | |
| 809 | − perf_config(perf_report_config, NULL); | |
| 831 | + perf_config(perf_report_config, &report); | |
| 810 | 832 | |
| 811 | 833 | argc = parse_options(argc, argv, options, report_usage, 0); |
| 812 | 834 | |
| @@ -846,11 +868,11 @@ repeat: · 33 unmodified lines | ||
| 846 | 868 | has_br_stack = perf_header__has_feat(&session->header, |
| 847 | 869 | HEADER_BRANCH_STACK); |
| 848 | 870 | |
| 849 | − if (sort__branch_mode == -1 && has_br_stack) | |
| 850 | − sort__branch_mode = 1; | |
| 871 | + if (branch_mode == -1 && has_br_stack) | |
| 872 | + sort__mode = SORT_MODE__BRANCH; | |
| 851 | 873 | |
| 852 | − /* sort__branch_mode could be 0 if --no-branch-stack */ | |
| 853 | − if (sort__branch_mode == 1) { | |
| 874 | + /* sort__mode could be NORMAL if --no-branch-stack */ | |
| 875 | + if (sort__mode == SORT_MODE__BRANCH) { | |
| 854 | 876 | /* |
| 855 | 877 | * if no sort_order is provided, then specify |
| 856 | 878 | * branch-mode specific order |
| @@ -861,10 +883,12 @@ repeat: · 4 unmodified lines | ||
| 861 | 883 | |
| 862 | 884 | } |
| 863 | 885 | if (report.mem_mode) { |
| 864 | − if (sort__branch_mode == 1) { | |
| 886 | + if (sort__mode == SORT_MODE__BRANCH) { | |
| 865 | 887 | fprintf(stderr, "branch and mem mode incompatible\n"); |
| 866 | 888 | goto error; |
| 867 | 889 | } |
| 890 | + sort__mode = SORT_MODE__MEMORY; | |
| 891 | + | |
| 868 | 892 | /* |
| 869 | 893 | * if no sort_order is provided, then specify |
| 870 | 894 | * branch-mode specific order |
| @@ -929,25 +953,7 @@ repeat: · 58 unmodified lines | ||
| 929 | 953 | report.symbol_filter_str = argv[0]; |
| 930 | 954 | } |
| 931 | 955 | |
| 932 | − sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); | |
| 933 | − | |
| 934 | − if (sort__branch_mode == 1) { | |
| 935 | − sort_entry__setup_elide(&sort_dso_from, symbol_conf.dso_from_list, "dso_from", stdout); | |
| 936 | − sort_entry__setup_elide(&sort_dso_to, symbol_conf.dso_to_list, "dso_to", stdout); | |
| 937 | − sort_entry__setup_elide(&sort_sym_from, symbol_conf.sym_from_list, "sym_from", stdout); | |
| 938 | − sort_entry__setup_elide(&sort_sym_to, symbol_conf.sym_to_list, "sym_to", stdout); | |
| 939 | − } else { | |
| 940 | − if (report.mem_mode) { | |
| 941 | − sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "symbol_daddr", stdout); | |
| 942 | − sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso_daddr", stdout); | |
| 943 | − sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "mem", stdout); | |
| 944 | − sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "local_weight", stdout); | |
| 945 | − sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "tlb", stdout); | |
| 946 | − sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "snoop", stdout); | |
| 947 | − } | |
| 948 | − sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout); | |
| 949 | − sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout); | |
| 950 | − } | |
| 956 | + sort__setup_elide(stdout); | |
| 951 | 957 | |
| 952 | 958 | ret = __cmd_report(&report); |
| 953 | 959 | if (ret == K_SWITCH_INPUT_DATA) { |
| @@ -70,10 +70,11 @@ · 69 unmodified lines | ||
| 70 | 70 | |
| 71 | 71 | static volatile int done; |
| 72 | 72 | |
| 73 | +#define HEADER_LINE_NR 5 | |
| 74 | + | |
| 73 | 75 | static void perf_top__update_print_entries(struct perf_top *top) |
| 74 | 76 | { |
| 75 | − if (top->print_entries > 9) | |
| 76 | − top->print_entries -= 9; | |
| 77 | + top->print_entries = top->winsize.ws_row - HEADER_LINE_NR; | |
| 77 | 78 | } |
| 78 | 79 | |
| 79 | 80 | static void perf_top__sig_winch(int sig __maybe_unused, |
| @@ -82,13 +83,6 @@ static void perf_top__sig_winch(int sig __maybe_unused, · 2 unmodified lines | ||
| 82 | 83 | struct perf_top *top = arg; |
| 83 | 84 | |
| 84 | 85 | get_term_dimensions(&top->winsize); |
| 85 | − if (!top->print_entries | |
| 86 | − || (top->print_entries+4) > top->winsize.ws_row) { | |
| 87 | − top->print_entries = top->winsize.ws_row; | |
| 88 | − } else { | |
| 89 | − top->print_entries += 4; | |
| 90 | − top->winsize.ws_row = top->print_entries; | |
| 91 | − } | |
| 92 | 86 | perf_top__update_print_entries(top); |
| 93 | 87 | } |
| 94 | 88 | |
| @@ -251,8 +245,11 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel, · 156 unmodified lines | ||
| 251 | 245 | { |
| 252 | 246 | struct hist_entry *he; |
| 253 | 247 | |
| 248 | + pthread_mutex_lock(&evsel->hists.lock); | |
| 254 | 249 | he = __hists__add_entry(&evsel->hists, al, NULL, sample->period, |
| 255 | 250 | sample->weight); |
| 251 | + pthread_mutex_unlock(&evsel->hists.lock); | |
| 252 | + | |
| 256 | 253 | if (he == NULL) |
| 257 | 254 | return NULL; |
| 258 | 255 | |
| @@ -290,16 +287,17 @@ static void perf_top__print_sym_table(struct perf_top *top) · 31 unmodified lines | ||
| 290 | 287 | return; |
| 291 | 288 | } |
| 292 | 289 | |
| 293 | − hists__collapse_resort_threaded(&top->sym_evsel->hists); | |
| 294 | − hists__output_resort_threaded(&top->sym_evsel->hists); | |
| 295 | − hists__decay_entries_threaded(&top->sym_evsel->hists, | |
| 296 | − top->hide_user_symbols, | |
| 297 | − top->hide_kernel_symbols); | |
| 290 | + hists__collapse_resort(&top->sym_evsel->hists); | |
| 291 | + hists__output_resort(&top->sym_evsel->hists); | |
| 292 | + hists__decay_entries(&top->sym_evsel->hists, | |
| 293 | + top->hide_user_symbols, | |
| 294 | + top->hide_kernel_symbols); | |
| 298 | 295 | hists__output_recalc_col_len(&top->sym_evsel->hists, |
| 299 | − top->winsize.ws_row - 3); | |
| 296 | + top->print_entries - printed); | |
| 300 | 297 | putchar('\n'); |
| 301 | 298 | hists__fprintf(&top->sym_evsel->hists, false, |
| 302 | − top->winsize.ws_row - 4 - printed, win_width, stdout); | |
| 299 | + top->print_entries - printed, win_width, | |
| 300 | + top->min_percent, stdout); | |
| 303 | 301 | } |
| 304 | 302 | |
| 305 | 303 | static void prompt_integer(int *target, const char *msg) |
| @@ -477,7 +475,6 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) · 171 unmodified lines | ||
| 477 | 475 | perf_top__sig_winch(SIGWINCH, NULL, top); |
| 478 | 476 | sigaction(SIGWINCH, &act, NULL); |
| 479 | 477 | } else { |
| 480 | − perf_top__sig_winch(SIGWINCH, NULL, top); | |
| 481 | 478 | signal(SIGWINCH, SIG_DFL); |
| 482 | 479 | } |
| 483 | 480 | break; |
| @@ -556,11 +553,11 @@ static void perf_top__sort_new_samples(void *arg) · 72 unmodified lines | ||
| 556 | 553 | if (t->evlist->selected != NULL) |
| 557 | 554 | t->sym_evsel = t->evlist->selected; |
| 558 | 555 | |
| 559 | − hists__collapse_resort_threaded(&t->sym_evsel->hists); | |
| 560 | − hists__output_resort_threaded(&t->sym_evsel->hists); | |
| 561 | − hists__decay_entries_threaded(&t->sym_evsel->hists, | |
| 562 | − t->hide_user_symbols, | |
| 563 | − t->hide_kernel_symbols); | |
| 556 | + hists__collapse_resort(&t->sym_evsel->hists); | |
| 557 | + hists__output_resort(&t->sym_evsel->hists); | |
| 558 | + hists__decay_entries(&t->sym_evsel->hists, | |
| 559 | + t->hide_user_symbols, | |
| 560 | + t->hide_kernel_symbols); | |
| 564 | 561 | } |
| 565 | 562 | |
| 566 | 563 | static void *display_thread_tui(void *arg) |
| @@ -584,7 +581,7 @@ static void *display_thread_tui(void *arg) · 17 unmodified lines | ||
| 584 | 581 | list_for_each_entry(pos, &top->evlist->entries, node) |
| 585 | 582 | pos->hists.uid_filter_str = top->record_opts.target.uid_str; |
| 586 | 583 | |
| 587 | − perf_evlist__tui_browse_hists(top->evlist, help, &hbt, | |
| 584 | + perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent, | |
| 588 | 585 | &top->session->header.env); |
| 589 | 586 | |
| 590 | 587 | done = 1; |
| @@ -794,7 +791,7 @@ static void perf_event__process_sample(struct perf_tool *tool, · 203 unmodified lines | ||
| 794 | 791 | return; |
| 795 | 792 | } |
| 796 | 793 | |
| 797 | − if (top->sort_has_symbols) | |
| 794 | + if (sort__has_sym) | |
| 798 | 795 | perf_top__record_precise_ip(top, he, evsel->idx, ip); |
| 799 | 796 | } |
| 800 | 797 | |
| @@ -912,9 +909,9 @@ out_err: · 111 unmodified lines | ||
| 912 | 909 | return -1; |
| 913 | 910 | } |
| 914 | 911 | |
| 915 | −static int perf_top__setup_sample_type(struct perf_top *top) | |
| 912 | +static int perf_top__setup_sample_type(struct perf_top *top __maybe_unused) | |
| 916 | 913 | { |
| 917 | − if (!top->sort_has_symbols) { | |
| 914 | + if (!sort__has_sym) { | |
| 918 | 915 | if (symbol_conf.use_callchain) { |
| 919 | 916 | ui__error("Selected -g but \"sym\" not present in --sort/-s."); |
| 920 | 917 | return -EINVAL; |
| @@ -1025,6 +1022,16 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) · 104 unmodified lines | ||
| 1025 | 1022 | return record_parse_callchain_opt(opt, arg, unset); |
| 1026 | 1023 | } |
| 1027 | 1024 | |
| 1025 | +static int | |
| 1026 | +parse_percent_limit(const struct option *opt, const char *arg, | |
| 1027 | + int unset __maybe_unused) | |
| 1028 | +{ | |
| 1029 | + struct perf_top *top = opt->value; | |
| 1030 | + | |
| 1031 | + top->min_percent = strtof(arg, NULL); | |
| 1032 | + return 0; | |
| 1033 | +} | |
| 1034 | + | |
| 1028 | 1035 | int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) |
| 1029 | 1036 | { |
| 1030 | 1037 | int status; |
| @@ -1110,6 +1117,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) · 79 unmodified lines | ||
| 1110 | 1117 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", |
| 1111 | 1118 | "Specify disassembler style (e.g. -M intel for intel syntax)"), |
| 1112 | 1119 | OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), |
| 1120 | + OPT_CALLBACK(0, "percent-limit", &top, "percent", | |
| 1121 | + "Don't show entries under that percent", parse_percent_limit), | |
| 1113 | 1122 | OPT_END() |
| 1114 | 1123 | }; |
| 1115 | 1124 | const char * const top_usage[] = { |
| @@ -1133,6 +1142,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) · 17 unmodified lines | ||
| 1133 | 1142 | if (setup_sorting() < 0) |
| 1134 | 1143 | usage_with_options(top_usage, options); |
| 1135 | 1144 | |
| 1145 | + /* display thread wants entries to be collapsed in a different tree */ | |
| 1146 | + sort__need_collapse = 1; | |
| 1147 | + | |
| 1136 | 1148 | if (top.use_stdio) |
| 1137 | 1149 | use_browser = 0; |
| 1138 | 1150 | else if (top.use_tui) |
| @@ -1200,15 +1212,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) · 61 unmodified lines | ||
| 1200 | 1212 | if (symbol__init() < 0) |
| 1201 | 1213 | return -1; |
| 1202 | 1214 | |
| 1203 | − sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout); | |
| 1204 | − sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); | |
| 1205 | − sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout); | |
| 1206 | − | |
| 1207 | − /* | |
| 1208 | − * Avoid annotation data structures overhead when symbols aren't on the | |
| 1209 | − * sort list. | |
| 1210 | − */ | |
| 1211 | − top.sort_has_symbols = sort_sym.list.next != NULL; | |
| 1215 | + sort__setup_elide(stdout); | |
| 1212 | 1216 | |
| 1213 | 1217 | get_term_dimensions(&top.winsize); |
| 1214 | 1218 | if (top.print_entries == 0) { |
| @@ -0,0 +1,477 @@ | ||
| 1 | +uname_M := $(shell uname -m 2>/dev/null || echo not) | |
| 2 | + | |
| 3 | +ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ | |
| 4 | + -e s/arm.*/arm/ -e s/sa110/arm/ \ | |
| 5 | + -e s/s390x/s390/ -e s/parisc64/parisc/ \ | |
| 6 | + -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ | |
| 7 | + -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ ) | |
| 8 | +NO_PERF_REGS := 1 | |
| 9 | +CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS) | |
| 10 | + | |
| 11 | +# Additional ARCH settings for x86 | |
| 12 | +ifeq ($(ARCH),i386) | |
| 13 | + override ARCH := x86 | |
| 14 | + NO_PERF_REGS := 0 | |
| 15 | + LIBUNWIND_LIBS = -lunwind -lunwind-x86 | |
| 16 | +endif | |
| 17 | + | |
| 18 | +ifeq ($(ARCH),x86_64) | |
| 19 | + override ARCH := x86 | |
| 20 | + IS_X86_64 := 0 | |
| 21 | + ifeq (, $(findstring m32,$(CFLAGS))) | |
| 22 | + IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1) | |
| 23 | + endif | |
| 24 | + ifeq (${IS_X86_64}, 1) | |
| 25 | + RAW_ARCH := x86_64 | |
| 26 | + CFLAGS += -DARCH_X86_64 | |
| 27 | + ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S | |
| 28 | + endif | |
| 29 | + NO_PERF_REGS := 0 | |
| 30 | + LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 | |
| 31 | +endif | |
| 32 | + | |
| 33 | +ifeq ($(NO_PERF_REGS),0) | |
| 34 | + CFLAGS += -DHAVE_PERF_REGS | |
| 35 | +endif | |
| 36 | + | |
| 37 | +ifeq ($(src-perf),) | |
| 38 | +src-perf := $(srctree)/tools/perf | |
| 39 | +endif | |
| 40 | + | |
| 41 | +ifeq ($(obj-perf),) | |
| 42 | +obj-perf := $(objtree) | |
| 43 | +endif | |
| 44 | + | |
| 45 | +ifneq ($(obj-perf),) | |
| 46 | +obj-perf := $(abspath $(obj-perf))/ | |
| 47 | +endif | |
| 48 | + | |
| 49 | +# include ARCH specific config | |
| 50 | +-include $(src-perf)/arch/$(ARCH)/Makefile | |
| 51 | + | |
| 52 | +include $(src-perf)/config/feature-tests.mak | |
| 53 | +include $(src-perf)/config/utilities.mak | |
| 54 | + | |
| 55 | +ifeq ($(call get-executable,$(FLEX)),) | |
| 56 | + dummy := $(error Error: $(FLEX) is missing on this system, please install it) | |
| 57 | +endif | |
| 58 | + | |
| 59 | +ifeq ($(call get-executable,$(BISON)),) | |
| 60 | + dummy := $(error Error: $(BISON) is missing on this system, please install it) | |
| 61 | +endif | |
| 62 | + | |
| 63 | +# Treat warnings as errors unless directed not to | |
| 64 | +ifneq ($(WERROR),0) | |
| 65 | + CFLAGS += -Werror | |
| 66 | +endif | |
| 67 | + | |
| 68 | +ifeq ("$(origin DEBUG)", "command line") | |
| 69 | + PERF_DEBUG = $(DEBUG) | |
| 70 | +endif | |
| 71 | +ifndef PERF_DEBUG | |
| 72 | + CFLAGS += -O6 | |
| 73 | +endif | |
| 74 | + | |
| 75 | +ifdef PARSER_DEBUG | |
| 76 | + PARSER_DEBUG_BISON := -t | |
| 77 | + PARSER_DEBUG_FLEX := -d | |
| 78 | + CFLAGS += -DPARSER_DEBUG | |
| 79 | +endif | |
| 80 | + | |
| 81 | +CFLAGS += -fno-omit-frame-pointer | |
| 82 | +CFLAGS += -ggdb3 | |
| 83 | +CFLAGS += -funwind-tables | |
| 84 | +CFLAGS += -Wall | |
| 85 | +CFLAGS += -Wextra | |
| 86 | +CFLAGS += -std=gnu99 | |
| 87 | + | |
| 88 | +EXTLIBS = -lpthread -lrt -lelf -lm | |
| 89 | + | |
| 90 | +ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y) | |
| 91 | + CFLAGS += -fstack-protector-all | |
| 92 | +endif | |
| 93 | + | |
| 94 | +ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wstack-protector,-Wstack-protector),y) | |
| 95 | + CFLAGS += -Wstack-protector | |
| 96 | +endif | |
| 97 | + | |
| 98 | +ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wvolatile-register-var,-Wvolatile-register-var),y) | |
| 99 | + CFLAGS += -Wvolatile-register-var | |
| 100 | +endif | |
| 101 | + | |
| 102 | +ifndef PERF_DEBUG | |
| 103 | + ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -D_FORTIFY_SOURCE=2,-D_FORTIFY_SOURCE=2),y) | |
| 104 | + CFLAGS += -D_FORTIFY_SOURCE=2 | |
| 105 | + endif | |
| 106 | +endif | |
| 107 | + | |
| 108 | +CFLAGS += -I$(src-perf)/util/include | |
| 109 | +CFLAGS += -I$(src-perf)/arch/$(ARCH)/include | |
| 110 | +CFLAGS += -I$(srctree)/arch/$(ARCH)/include/uapi | |
| 111 | +CFLAGS += -I$(srctree)/arch/$(ARCH)/include | |
| 112 | +CFLAGS += -I$(srctree)/include/uapi | |
| 113 | +CFLAGS += -I$(srctree)/include | |
| 114 | + | |
| 115 | +# $(obj-perf) for generated common-cmds.h | |
| 116 | +# $(obj-perf)/util for generated bison/flex headers | |
| 117 | +ifneq ($(OUTPUT),) | |
| 118 | +CFLAGS += -I$(obj-perf)/util | |
| 119 | +CFLAGS += -I$(obj-perf) | |
| 120 | +endif | |
| 121 | + | |
| 122 | +CFLAGS += -I$(src-perf)/util | |
| 123 | +CFLAGS += -I$(src-perf) | |
| 124 | +CFLAGS += -I$(TRACE_EVENT_DIR) | |
| 125 | +CFLAGS += -I$(srctree)/tools/lib/ | |
| 126 | + | |
| 127 | +CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE | |
| 128 | + | |
| 129 | +ifndef NO_BIONIC | |
| 130 | +ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y) | |
| 131 | + BIONIC := 1 | |
| 132 | + EXTLIBS := $(filter-out -lrt,$(EXTLIBS)) | |
| 133 | + EXTLIBS := $(filter-out -lpthread,$(EXTLIBS)) | |
| 134 | +endif | |
| 135 | +endif # NO_BIONIC | |
| 136 | + | |
| 137 | +ifdef NO_LIBELF | |
| 138 | + NO_DWARF := 1 | |
| 139 | + NO_DEMANGLE := 1 | |
| 140 | + NO_LIBUNWIND := 1 | |
| 141 | +else | |
| 142 | +FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) | |
| 143 | +ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF),libelf),y) | |
| 144 | + FLAGS_GLIBC=$(CFLAGS) $(LDFLAGS) | |
| 145 | + ifeq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC),glibc),y) | |
| 146 | + LIBC_SUPPORT := 1 | |
| 147 | + endif | |
| 148 | + ifeq ($(BIONIC),1) | |
| 149 | + LIBC_SUPPORT := 1 | |
| 150 | + endif | |
| 151 | + ifeq ($(LIBC_SUPPORT),1) | |
| 152 | + msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev); | |
| 153 | + | |
| 154 | + NO_LIBELF := 1 | |
| 155 | + NO_DWARF := 1 | |
| 156 | + NO_DEMANGLE := 1 | |
| 157 | + else | |
| 158 | + msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); | |
| 159 | + endif | |
| 160 | +else | |
| 161 | + # for linking with debug library, run like: | |
| 162 | + # make DEBUG=1 LIBDW_DIR=/opt/libdw/ | |
| 163 | + ifdef LIBDW_DIR | |
| 164 | + LIBDW_CFLAGS := -I$(LIBDW_DIR)/include | |
| 165 | + LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib | |
| 166 | + endif | |
| 167 | + | |
| 168 | + FLAGS_DWARF=$(CFLAGS) $(LIBDW_CFLAGS) -ldw -lelf $(LIBDW_LDFLAGS) $(LDFLAGS) $(EXTLIBS) | |
| 169 | + ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF),libdw),y) | |
| 170 | + msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); | |
| 171 | + NO_DWARF := 1 | |
| 172 | + endif # Dwarf support | |
| 173 | +endif # SOURCE_LIBELF | |
| 174 | +endif # NO_LIBELF | |
| 175 | + | |
| 176 | +ifndef NO_LIBELF | |
| 177 | +CFLAGS += -DLIBELF_SUPPORT | |
| 178 | +FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) | |
| 179 | +ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y) | |
| 180 | + CFLAGS += -DLIBELF_MMAP | |
| 181 | +endif | |
| 182 | + | |
| 183 | +# include ARCH specific config | |
| 184 | +-include $(src-perf)/arch/$(ARCH)/Makefile | |
| 185 | + | |
| 186 | +ifndef NO_DWARF | |
| 187 | +ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) | |
| 188 | + msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); | |
| 189 | + NO_DWARF := 1 | |
| 190 | +else | |
| 191 | + CFLAGS += -DDWARF_SUPPORT $(LIBDW_CFLAGS) | |
| 192 | + LDFLAGS += $(LIBDW_LDFLAGS) | |
| 193 | + EXTLIBS += -lelf -ldw | |
| 194 | +endif # PERF_HAVE_DWARF_REGS | |
| 195 | +endif # NO_DWARF | |
| 196 | + | |
| 197 | +endif # NO_LIBELF | |
| 198 | + | |
| 199 | +ifndef NO_LIBELF | |
| 200 | +CFLAGS += -DLIBELF_SUPPORT | |
| 201 | +FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) | |
| 202 | +ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y) | |
| 203 | + CFLAGS += -DLIBELF_MMAP | |
| 204 | +endif # try-cc | |
| 205 | +endif # NO_LIBELF | |
| 206 | + | |
| 207 | +# There's only x86 (both 32 and 64) support for CFI unwind so far | |
| 208 | +ifneq ($(ARCH),x86) | |
| 209 | + NO_LIBUNWIND := 1 | |
| 210 | +endif | |
| 211 | + | |
| 212 | +ifndef NO_LIBUNWIND | |
| 213 | +# for linking with debug library, run like: | |
| 214 | +# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/ | |
| 215 | +ifdef LIBUNWIND_DIR | |
| 216 | + LIBUNWIND_CFLAGS := -I$(LIBUNWIND_DIR)/include | |
| 217 | + LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib | |
| 218 | +endif | |
| 219 | + | |
| 220 | +FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(CFLAGS) $(LIBUNWIND_LDFLAGS) $(LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS) | |
| 221 | +ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND),libunwind),y) | |
| 222 | + msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99); | |
| 223 | + NO_LIBUNWIND := 1 | |
| 224 | +endif # Libunwind support | |
| 225 | +endif # NO_LIBUNWIND | |
| 226 | + | |
| 227 | +ifndef NO_LIBUNWIND | |
| 228 | + CFLAGS += -DLIBUNWIND_SUPPORT | |
| 229 | + EXTLIBS += $(LIBUNWIND_LIBS) | |
| 230 | + CFLAGS += $(LIBUNWIND_CFLAGS) | |
| 231 | + LDFLAGS += $(LIBUNWIND_LDFLAGS) | |
| 232 | +endif # NO_LIBUNWIND | |
| 233 | + | |
| 234 | +ifndef NO_LIBAUDIT | |
| 235 | + FLAGS_LIBAUDIT = $(CFLAGS) $(LDFLAGS) -laudit | |
| 236 | + ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT),libaudit),y) | |
| 237 | + msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev); | |
| 238 | + NO_LIBAUDIT := 1 | |
| 239 | + else | |
| 240 | + CFLAGS += -DLIBAUDIT_SUPPORT | |
| 241 | + EXTLIBS += -laudit | |
| 242 | + endif | |
| 243 | +endif | |
| 244 | + | |
| 245 | +ifdef NO_NEWT | |
| 246 | + NO_SLANG=1 | |
| 247 | +endif | |
| 248 | + | |
| 249 | +ifndef NO_SLANG | |
| 250 | + FLAGS_SLANG=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -I/usr/include/slang -lslang | |
| 251 | + ifneq ($(call try-cc,$(SOURCE_SLANG),$(FLAGS_SLANG),libslang),y) | |
| 252 | + msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev); | |
| 253 | + NO_SLANG := 1 | |
| 254 | + else | |
| 255 | + # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h | |
| 256 | + CFLAGS += -I/usr/include/slang | |
| 257 | + CFLAGS += -DSLANG_SUPPORT | |
| 258 | + EXTLIBS += -lslang | |
| 259 | + endif | |
| 260 | +endif | |
| 261 | + | |
| 262 | +ifndef NO_GTK2 | |
| 263 | + FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) | |
| 264 | + ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2),gtk2),y) | |
| 265 | + msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); | |
| 266 | + NO_GTK2 := 1 | |
| 267 | + else | |
| 268 | + ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2),-DHAVE_GTK_INFO_BAR),y) | |
| 269 | + CFLAGS += -DHAVE_GTK_INFO_BAR | |
| 270 | + endif | |
| 271 | + CFLAGS += -DGTK2_SUPPORT | |
| 272 | + CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null) | |
| 273 | + EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null) | |
| 274 | + endif | |
| 275 | +endif | |
| 276 | + | |
| 277 | +grep-libs = $(filter -l%,$(1)) | |
| 278 | +strip-libs = $(filter-out -l%,$(1)) | |
| 279 | + | |
| 280 | +ifdef NO_LIBPERL | |
| 281 | + CFLAGS += -DNO_LIBPERL | |
| 282 | +else | |
| 283 | + PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null) | |
| 284 | + PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS)) | |
| 285 | + PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS)) | |
| 286 | + PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` | |
| 287 | + FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) | |
| 288 | + | |
| 289 | + ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED),perl),y) | |
| 290 | + CFLAGS += -DNO_LIBPERL | |
| 291 | + NO_LIBPERL := 1 | |
| 292 | + else | |
| 293 | + LDFLAGS += $(PERL_EMBED_LDFLAGS) | |
| 294 | + EXTLIBS += $(PERL_EMBED_LIBADD) | |
| 295 | + endif | |
| 296 | +endif | |
| 297 | + | |
| 298 | +disable-python = $(eval $(disable-python_code)) | |
| 299 | +define disable-python_code | |
| 300 | + CFLAGS += -DNO_LIBPYTHON | |
| 301 | + $(if $(1),$(warning No $(1) was found)) | |
| 302 | + $(warning Python support will not be built) | |
| 303 | + NO_LIBPYTHON := 1 | |
| 304 | +endef | |
| 305 | + | |
| 306 | +override PYTHON := \ | |
| 307 | + $(call get-executable-or-default,PYTHON,python) | |
| 308 | + | |
| 309 | +ifndef PYTHON | |
| 310 | + $(call disable-python,python interpreter) | |
| 311 | +else | |
| 312 | + | |
| 313 | + PYTHON_WORD := $(call shell-wordify,$(PYTHON)) | |
| 314 | + | |
| 315 | + ifdef NO_LIBPYTHON | |
| 316 | + $(call disable-python) | |
| 317 | + else | |
| 318 | + | |
| 319 | + override PYTHON_CONFIG := \ | |
| 320 | + $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config) | |
| 321 | + | |
| 322 | + ifndef PYTHON_CONFIG | |
| 323 | + $(call disable-python,python-config tool) | |
| 324 | + else | |
| 325 | + | |
| 326 | + PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG)) | |
| 327 | + | |
| 328 | + PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) | |
| 329 | + PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS)) | |
| 330 | + PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) | |
| 331 | + PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) | |
| 332 | + FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) | |
| 333 | + | |
| 334 | + ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED),python),y) | |
| 335 | + $(call disable-python,Python.h (for Python 2.x)) | |
| 336 | + else | |
| 337 | + | |
| 338 | + ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED),python version),y) | |
| 339 | + $(warning Python 3 is not yet supported; please set) | |
| 340 | + $(warning PYTHON and/or PYTHON_CONFIG appropriately.) | |
| 341 | + $(warning If you also have Python 2 installed, then) | |
| 342 | + $(warning try something like:) | |
| 343 | + $(warning $(and ,)) | |
| 344 | + $(warning $(and ,) make PYTHON=python2) | |
| 345 | + $(warning $(and ,)) | |
| 346 | + $(warning Otherwise, disable Python support entirely:) | |
| 347 | + $(warning $(and ,)) | |
| 348 | + $(warning $(and ,) make NO_LIBPYTHON=1) | |
| 349 | + $(warning $(and ,)) | |
| 350 | + $(error $(and ,)) | |
| 351 | + else | |
| 352 | + LDFLAGS += $(PYTHON_EMBED_LDFLAGS) | |
| 353 | + EXTLIBS += $(PYTHON_EMBED_LIBADD) | |
| 354 | + LANG_BINDINGS += $(obj-perf)python/perf.so | |
| 355 | + endif | |
| 356 | + endif | |
| 357 | + endif | |
| 358 | + endif | |
| 359 | +endif | |
| 360 | + | |
| 361 | +ifdef NO_DEMANGLE | |
| 362 | + CFLAGS += -DNO_DEMANGLE | |
| 363 | +else | |
| 364 | + ifdef HAVE_CPLUS_DEMANGLE | |
| 365 | + EXTLIBS += -liberty | |
| 366 | + CFLAGS += -DHAVE_CPLUS_DEMANGLE | |
| 367 | + else | |
| 368 | + FLAGS_BFD=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd | |
| 369 | + has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD),libbfd) | |
| 370 | + ifeq ($(has_bfd),y) | |
| 371 | + EXTLIBS += -lbfd | |
| 372 | + else | |
| 373 | + FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty | |
| 374 | + has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY),liberty) | |
| 375 | + ifeq ($(has_bfd_iberty),y) | |
| 376 | + EXTLIBS += -lbfd -liberty | |
| 377 | + else | |
| 378 | + FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz | |
| 379 | + has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z),libz) | |
| 380 | + ifeq ($(has_bfd_iberty_z),y) | |
| 381 | + EXTLIBS += -lbfd -liberty -lz | |
| 382 | + else | |
| 383 | + FLAGS_CPLUS_DEMANGLE=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -liberty | |
| 384 | + has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE),demangle) | |
| 385 | + ifeq ($(has_cplus_demangle),y) | |
| 386 | + EXTLIBS += -liberty | |
| 387 | + CFLAGS += -DHAVE_CPLUS_DEMANGLE | |
| 388 | + else | |
| 389 | + msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling) | |
| 390 | + CFLAGS += -DNO_DEMANGLE | |
| 391 | + endif | |
| 392 | + endif | |
| 393 | + endif | |
| 394 | + endif | |
| 395 | + endif | |
| 396 | +endif | |
| 397 | + | |
| 398 | +ifndef NO_STRLCPY | |
| 399 | + ifeq ($(call try-cc,$(SOURCE_STRLCPY),,-DHAVE_STRLCPY),y) | |
| 400 | + CFLAGS += -DHAVE_STRLCPY | |
| 401 | + endif | |
| 402 | +endif | |
| 403 | + | |
| 404 | +ifndef NO_ON_EXIT | |
| 405 | + ifeq ($(call try-cc,$(SOURCE_ON_EXIT),,-DHAVE_ON_EXIT),y) | |
| 406 | + CFLAGS += -DHAVE_ON_EXIT | |
| 407 | + endif | |
| 408 | +endif | |
| 409 | + | |
| 410 | +ifndef NO_BACKTRACE | |
| 411 | + ifeq ($(call try-cc,$(SOURCE_BACKTRACE),,-DBACKTRACE_SUPPORT),y) | |
| 412 | + CFLAGS += -DBACKTRACE_SUPPORT | |
| 413 | + endif | |
| 414 | +endif | |
| 415 | + | |
| 416 | +ifndef NO_LIBNUMA | |
| 417 | + FLAGS_LIBNUMA = $(CFLAGS) $(LDFLAGS) -lnuma | |
| 418 | + ifneq ($(call try-cc,$(SOURCE_LIBNUMA),$(FLAGS_LIBNUMA),libnuma),y) | |
| 419 | + msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev); | |
| 420 | + NO_LIBNUMA := 1 | |
| 421 | + else | |
| 422 | + CFLAGS += -DLIBNUMA_SUPPORT | |
| 423 | + EXTLIBS += -lnuma | |
| 424 | + endif | |
| 425 | +endif | |
| 426 | + | |
| 427 | +# Among the variables below, these: | |
| 428 | +# perfexecdir | |
| 429 | +# template_dir | |
| 430 | +# mandir | |
| 431 | +# infodir | |
| 432 | +# htmldir | |
| 433 | +# ETC_PERFCONFIG (but not sysconfdir) | |
| 434 | +# can be specified as a relative path some/where/else; | |
| 435 | +# this is interpreted as relative to $(prefix) and "perf" at | |
| 436 | +# runtime figures out where they are based on the path to the executable. | |
| 437 | +# This can help installing the suite in a relocatable way. | |
| 438 | + | |
| 439 | +# Make the path relative to DESTDIR, not to prefix | |
| 440 | +ifndef DESTDIR | |
| 441 | +prefix = $(HOME) | |
| 442 | +endif | |
| 443 | +bindir_relative = bin | |
| 444 | +bindir = $(prefix)/$(bindir_relative) | |
| 445 | +mandir = share/man | |
| 446 | +infodir = share/info | |
| 447 | +perfexecdir = libexec/perf-core | |
| 448 | +sharedir = $(prefix)/share | |
| 449 | +template_dir = share/perf-core/templates | |
| 450 | +htmldir = share/doc/perf-doc | |
| 451 | +ifeq ($(prefix),/usr) | |
| 452 | +sysconfdir = /etc | |
| 453 | +ETC_PERFCONFIG = $(sysconfdir)/perfconfig | |
| 454 | +else | |
| 455 | +sysconfdir = $(prefix)/etc | |
| 456 | +ETC_PERFCONFIG = etc/perfconfig | |
| 457 | +endif | |
| 458 | +lib = lib | |
| 459 | + | |
| 460 | +# Shell quote (do not use $(call) to accommodate ancient setups); | |
| 461 | +ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) | |
| 462 | +DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) | |
| 463 | +bindir_SQ = $(subst ','\'',$(bindir)) | |
| 464 | +mandir_SQ = $(subst ','\'',$(mandir)) | |
| 465 | +infodir_SQ = $(subst ','\'',$(infodir)) | |
| 466 | +perfexecdir_SQ = $(subst ','\'',$(perfexecdir)) | |
| 467 | +template_dir_SQ = $(subst ','\'',$(template_dir)) | |
| 468 | +htmldir_SQ = $(subst ','\'',$(htmldir)) | |
| 469 | +prefix_SQ = $(subst ','\'',$(prefix)) | |
| 470 | +sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) | |
| 471 | + | |
| 472 | +ifneq ($(filter /%,$(firstword $(perfexecdir))),) | |
| 473 | +perfexec_instdir = $(perfexecdir) | |
| 474 | +else | |
| 475 | +perfexec_instdir = $(prefix)/$(perfexecdir) | |
| 476 | +endif | |
| 477 | +perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) | |
| @@ -27,8 +27,8 @@ watermark=0 · 26 unmodified lines | ||
| 27 | 27 | precise_ip=0 |
| 28 | 28 | mmap_data=0 |
| 29 | 29 | sample_id_all=1 |
| 30 | −exclude_host=0 | |
| 31 | −exclude_guest=1 | |
| 30 | +exclude_host=0|1 | |
| 31 | +exclude_guest=0|1 | |
| 32 | 32 | exclude_callchain_kernel=0 |
| 33 | 33 | exclude_callchain_user=0 |
| 34 | 34 | wakeup_events=0 |
| @@ -27,8 +27,8 @@ watermark=0 · 26 unmodified lines | ||
| 27 | 27 | precise_ip=0 |
| 28 | 28 | mmap_data=0 |
| 29 | 29 | sample_id_all=0 |
| 30 | −exclude_host=0 | |
| 31 | −exclude_guest=1 | |
| 30 | +exclude_host=0|1 | |
| 31 | +exclude_guest=0|1 | |
| 32 | 32 | exclude_callchain_kernel=0 |
| 33 | 33 | exclude_callchain_user=0 |
| 34 | 34 | wakeup_events=0 |
| @@ -4,5 +4,8 @@ args = -d kill >/dev/null 2>&1 · 3 unmodified lines | ||
| 4 | 4 | |
| 5 | 5 | [event:base-record] |
| 6 | 6 | sample_period=4000 |
| 7 | −sample_type=271 | |
| 7 | + | |
| 8 | +# sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | | |
| 9 | +# PERF_SAMPLE_ADDR | PERF_SAMPLE_PERIOD | PERF_SAMPLE_DATA_SRC | |
| 10 | +sample_type=33039 | |
| 8 | 11 | mmap_data=1 |
| @@ -4,6 +4,12 @@ · 3 unmodified lines | ||
| 4 | 4 | * (git://github.com/deater/perf_event_tests) |
| 5 | 5 | */ |
| 6 | 6 | |
| 7 | +/* | |
| 8 | + * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select | |
| 9 | + * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu. | |
| 10 | + */ | |
| 11 | +#define __SANE_USERSPACE_TYPES__ | |
| 12 | + | |
| 7 | 13 | #include <stdlib.h> |
| 8 | 14 | #include <stdio.h> |
| 9 | 15 | #include <unistd.h> |
| @@ -3,6 +3,12 @@ · 2 unmodified lines | ||
| 3 | 3 | * perf_event_tests (git://github.com/deater/perf_event_tests) |
| 4 | 4 | */ |
| 5 | 5 | |
| 6 | +/* | |
| 7 | + * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select | |
| 8 | + * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu. | |
| 9 | + */ | |
| 10 | +#define __SANE_USERSPACE_TYPES__ | |
| 11 | + | |
| 6 | 12 | #include <stdlib.h> |
| 7 | 13 | #include <stdio.h> |
| 8 | 14 | #include <unistd.h> |
| @@ -70,7 +70,7 @@ static struct test { · 69 unmodified lines | ||
| 70 | 70 | .func = test__attr, |
| 71 | 71 | }, |
| 72 | 72 | { |
| 73 | − .desc = "Test matching and linking mutliple hists", | |
| 73 | + .desc = "Test matching and linking multiple hists", | |
| 74 | 74 | .func = test__hists_link, |
| 75 | 75 | }, |
| 76 | 76 | { |
| @@ -0,0 +1,138 @@ | ||
| 1 | +PERF := . | |
| 2 | +MK := Makefile | |
| 3 | + | |
| 4 | +# standard single make variable specified | |
| 5 | +make_clean_all := clean all | |
| 6 | +make_python_perf_so := python/perf.so | |
| 7 | +make_debug := DEBUG=1 | |
| 8 | +make_no_libperl := NO_LIBPERL=1 | |
| 9 | +make_no_libpython := NO_LIBPYTHON=1 | |
| 10 | +make_no_scripts := NO_LIBPYTHON=1 NO_LIBPERL=1 | |
| 11 | +make_no_newt := NO_NEWT=1 | |
| 12 | +make_no_slang := NO_SLANG=1 | |
| 13 | +make_no_gtk2 := NO_GTK2=1 | |
| 14 | +make_no_ui := NO_NEWT=1 NO_SLANG=1 NO_GTK2=1 | |
| 15 | +make_no_demangle := NO_DEMANGLE=1 | |
| 16 | +make_no_libelf := NO_LIBELF=1 | |
| 17 | +make_no_libunwind := NO_LIBUNWIND=1 | |
| 18 | +make_no_backtrace := NO_BACKTRACE=1 | |
| 19 | +make_no_libnuma := NO_LIBNUMA=1 | |
| 20 | +make_no_libaudit := NO_LIBAUDIT=1 | |
| 21 | +make_no_libbionic := NO_LIBBIONIC=1 | |
| 22 | +make_tags := tags | |
| 23 | +make_cscope := cscope | |
| 24 | +make_help := help | |
| 25 | +make_doc := doc | |
| 26 | +make_perf_o := perf.o | |
| 27 | +make_util_map_o := util/map.o | |
| 28 | + | |
| 29 | +# all the NO_* variable combined | |
| 30 | +make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1 | |
| 31 | +make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 | |
| 32 | +make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 | |
| 33 | + | |
| 34 | +# $(run) contains all available tests | |
| 35 | +run := make_pure | |
| 36 | +run += make_clean_all | |
| 37 | +run += make_python_perf_so | |
| 38 | +run += make_debug | |
| 39 | +run += make_no_libperl | |
| 40 | +run += make_no_libpython | |
| 41 | +run += make_no_scripts | |
| 42 | +run += make_no_newt | |
| 43 | +run += make_no_slang | |
| 44 | +run += make_no_gtk2 | |
| 45 | +run += make_no_ui | |
| 46 | +run += make_no_demangle | |
| 47 | +run += make_no_libelf | |
| 48 | +run += make_no_libunwind | |
| 49 | +run += make_no_backtrace | |
| 50 | +run += make_no_libnuma | |
| 51 | +run += make_no_libaudit | |
| 52 | +run += make_no_libbionic | |
| 53 | +run += make_tags | |
| 54 | +run += make_cscope | |
| 55 | +run += make_help | |
| 56 | +run += make_doc | |
| 57 | +run += make_perf_o | |
| 58 | +run += make_util_map_o | |
| 59 | +run += make_minimal | |
| 60 | + | |
| 61 | +# $(run_O) contains same portion of $(run) tests with '_O' attached | |
| 62 | +# to distinguish O=... tests | |
| 63 | +run_O := $(addsuffix _O,$(run)) | |
| 64 | + | |
| 65 | +# disable some tests for O=... | |
| 66 | +run_O := $(filter-out make_python_perf_so_O,$(run_O)) | |
| 67 | + | |
| 68 | +# define test for each compile as 'test_NAME' variable | |
| 69 | +# with the test itself as a value | |
| 70 | +test_make_tags = test -f tags | |
| 71 | +test_make_cscope = test -f cscope.out | |
| 72 | + | |
| 73 | +test_make_tags_O := $(test_make_tags) | |
| 74 | +test_make_cscope_O := $(test_make_cscope) | |
| 75 | + | |
| 76 | +test_ok := true | |
| 77 | +test_make_help := $(test_ok) | |
| 78 | +test_make_doc := $(test_ok) | |
| 79 | +test_make_help_O := $(test_ok) | |
| 80 | +test_make_doc_O := $(test_ok) | |
| 81 | + | |
| 82 | +test_make_python_perf_so := test -f $(PERF)/python/perf.so | |
| 83 | + | |
| 84 | +test_make_perf_o := test -f $(PERF)/perf.o | |
| 85 | +test_make_util_map_o := test -f $(PERF)/util/map.o | |
| 86 | + | |
| 87 | +# Kbuild tests only | |
| 88 | +#test_make_python_perf_so_O := test -f $$TMP/tools/perf/python/perf.so | |
| 89 | +#test_make_perf_o_O := test -f $$TMP/tools/perf/perf.o | |
| 90 | +#test_make_util_map_o_O := test -f $$TMP/tools/perf/util/map.o | |
| 91 | + | |
| 92 | +test_make_perf_o_O := true | |
| 93 | +test_make_util_map_o_O := true | |
| 94 | + | |
| 95 | +test_default = test -x $(PERF)/perf | |
| 96 | +test = $(if $(test_$1),$(test_$1),$(test_default)) | |
| 97 | + | |
| 98 | +test_default_O = test -x $$TMP/perf | |
| 99 | +test_O = $(if $(test_$1),$(test_$1),$(test_default_O)) | |
| 100 | + | |
| 101 | +all: | |
| 102 | + | |
| 103 | +ifdef DEBUG | |
| 104 | +d := $(info run $(run)) | |
| 105 | +d := $(info run_O $(run_O)) | |
| 106 | +endif | |
| 107 | + | |
| 108 | +MAKEFLAGS := --no-print-directory | |
| 109 | + | |
| 110 | +clean := @(cd $(PERF); make -s -f $(MK) clean >/dev/null) | |
| 111 | + | |
| 112 | +$(run): | |
| 113 | + $(call clean) | |
| 114 | + @cmd="cd $(PERF) && make -f $(MK) $($@)"; \ | |
| 115 | + echo "- $@: $$cmd" && echo $$cmd > $@ && \ | |
| 116 | + ( eval $$cmd ) >> $@ 2>&1; \ | |
| 117 | + echo " test: $(call test,$@)"; \ | |
| 118 | + $(call test,$@) && \ | |
| 119 | + rm -f $@ | |
| 120 | + | |
| 121 | +$(run_O): | |
| 122 | + $(call clean) | |
| 123 | + @TMP=$$(mktemp -d); \ | |
| 124 | + cmd="cd $(PERF) && make -f $(MK) $($(patsubst %_O,%,$@)) O=$$TMP"; \ | |
| 125 | + echo "- $@: $$cmd" && echo $$cmd > $@ && \ | |
| 126 | + ( eval $$cmd ) >> $@ 2>&1 && \ | |
| 127 | + echo " test: $(call test_O,$@)"; \ | |
| 128 | + $(call test_O,$@) && \ | |
| 129 | + rm -f $@ && \ | |
| 130 | + rm -rf $$TMP | |
| 131 | + | |
| 132 | +all: $(run) $(run_O) | |
| 133 | + @echo OK | |
| 134 | + | |
| 135 | +out: $(run_O) | |
| 136 | + @echo OK | |
| 137 | + | |
| 138 | +.PHONY: all $(run) $(run_O) clean | |
| @@ -25,7 +25,8 @@ struct hist_browser { · 24 unmodified lines | ||
| 25 | 25 | struct map_symbol *selection; |
| 26 | 26 | int print_seq; |
| 27 | 27 | bool show_dso; |
| 28 | − bool has_symbols; | |
| 28 | + float min_pcnt; | |
| 29 | + u64 nr_pcnt_entries; | |
| 29 | 30 | }; |
| 30 | 31 | |
| 31 | 32 | extern void hist_browser__init_hpp(void); |
| @@ -309,6 +310,8 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser) · 277 unmodified lines | ||
| 309 | 310 | "Or reduce the sampling frequency."); |
| 310 | 311 | } |
| 311 | 312 | |
| 313 | +static void hist_browser__update_pcnt_entries(struct hist_browser *hb); | |
| 314 | + | |
| 312 | 315 | static int hist_browser__run(struct hist_browser *browser, const char *ev_name, |
| 313 | 316 | struct hist_browser_timer *hbt) |
| 314 | 317 | { |
| @@ -318,6 +321,8 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name, · 3 unmodified lines | ||
| 318 | 321 | |
| 319 | 322 | browser->b.entries = &browser->hists->entries; |
| 320 | 323 | browser->b.nr_entries = browser->hists->nr_entries; |
| 324 | + if (browser->min_pcnt) | |
| 325 | + browser->b.nr_entries = browser->nr_pcnt_entries; | |
| 321 | 326 | |
| 322 | 327 | hist_browser__refresh_dimensions(browser); |
| 323 | 328 | hists__browser_title(browser->hists, title, sizeof(title), ev_name); |
| @@ -330,9 +335,18 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name, · 6 unmodified lines | ||
| 330 | 335 | key = ui_browser__run(&browser->b, delay_secs); |
| 331 | 336 | |
| 332 | 337 | switch (key) { |
| 333 | − case K_TIMER: | |
| 338 | + case K_TIMER: { | |
| 339 | + u64 nr_entries; | |
| 334 | 340 | hbt->timer(hbt->arg); |
| 335 | − ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); | |
| 341 | + | |
| 342 | + if (browser->min_pcnt) { | |
| 343 | + hist_browser__update_pcnt_entries(browser); | |
| 344 | + nr_entries = browser->nr_pcnt_entries; | |
| 345 | + } else { | |
| 346 | + nr_entries = browser->hists->nr_entries; | |
| 347 | + } | |
| 348 | + | |
| 349 | + ui_browser__update_nr_entries(&browser->b, nr_entries); | |
| 336 | 350 | |
| 337 | 351 | if (browser->hists->stats.nr_lost_warned != |
| 338 | 352 | browser->hists->stats.nr_events[PERF_RECORD_LOST]) { |
| @@ -344,6 +358,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name, · 5 unmodified lines | ||
| 344 | 358 | hists__browser_title(browser->hists, title, sizeof(title), ev_name); |
| 345 | 359 | ui_browser__show_title(&browser->b, title); |
| 346 | 360 | continue; |
| 361 | + } | |
| 347 | 362 | case 'D': { /* Debug */ |
| 348 | 363 | static int seq; |
| 349 | 364 | struct hist_entry *h = rb_entry(browser->b.top, |
| @@ -796,10 +811,15 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser) · 446 unmodified lines | ||
| 796 | 811 | |
| 797 | 812 | for (nd = browser->top; nd; nd = rb_next(nd)) { |
| 798 | 813 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
| 814 | + float percent = h->stat.period * 100.0 / | |
| 815 | + hb->hists->stats.total_period; | |
| 799 | 816 | |
| 800 | 817 | if (h->filtered) |
| 801 | 818 | continue; |
| 802 | 819 | |
| 820 | + if (percent < hb->min_pcnt) | |
| 821 | + continue; | |
| 822 | + | |
| 803 | 823 | row += hist_browser__show_entry(hb, h, row); |
| 804 | 824 | if (row == browser->height) |
| 805 | 825 | break; |
| @@ -808,10 +828,18 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser) · 2 unmodified lines | ||
| 808 | 828 | return row; |
| 809 | 829 | } |
| 810 | 830 | |
| 811 | −static struct rb_node *hists__filter_entries(struct rb_node *nd) | |
| 831 | +static struct rb_node *hists__filter_entries(struct rb_node *nd, | |
| 832 | + struct hists *hists, | |
| 833 | + float min_pcnt) | |
| 812 | 834 | { |
| 813 | 835 | while (nd != NULL) { |
| 814 | 836 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
| 837 | + float percent = h->stat.period * 100.0 / | |
| 838 | + hists->stats.total_period; | |
| 839 | + | |
| 840 | + if (percent < min_pcnt) | |
| 841 | + return NULL; | |
| 842 | + | |
| 815 | 843 | if (!h->filtered) |
| 816 | 844 | return nd; |
| 817 | 845 | |
| @@ -821,11 +849,16 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd) · 3 unmodified lines | ||
| 821 | 849 | return NULL; |
| 822 | 850 | } |
| 823 | 851 | |
| 824 | −static struct rb_node *hists__filter_prev_entries(struct rb_node *nd) | |
| 852 | +static struct rb_node *hists__filter_prev_entries(struct rb_node *nd, | |
| 853 | + struct hists *hists, | |
| 854 | + float min_pcnt) | |
| 825 | 855 | { |
| 826 | 856 | while (nd != NULL) { |
| 827 | 857 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
| 828 | − if (!h->filtered) | |
| 858 | + float percent = h->stat.period * 100.0 / | |
| 859 | + hists->stats.total_period; | |
| 860 | + | |
| 861 | + if (!h->filtered && percent >= min_pcnt) | |
| 829 | 862 | return nd; |
| 830 | 863 | |
| 831 | 864 | nd = rb_prev(nd); |
| @@ -840,6 +873,9 @@ static void ui_browser__hists_seek(struct ui_browser *browser, · 8 unmodified lines | ||
| 840 | 873 | struct hist_entry *h; |
| 841 | 874 | struct rb_node *nd; |
| 842 | 875 | bool first = true; |
| 876 | + struct hist_browser *hb; | |
| 877 | + | |
| 878 | + hb = container_of(browser, struct hist_browser, b); | |
| 843 | 879 | |
| 844 | 880 | if (browser->nr_entries == 0) |
| 845 | 881 | return; |
| @@ -848,13 +884,15 @@ static void ui_browser__hists_seek(struct ui_browser *browser, · 2 unmodified lines | ||
| 848 | 884 | |
| 849 | 885 | switch (whence) { |
| 850 | 886 | case SEEK_SET: |
| 851 | − nd = hists__filter_entries(rb_first(browser->entries)); | |
| 887 | + nd = hists__filter_entries(rb_first(browser->entries), | |
| 888 | + hb->hists, hb->min_pcnt); | |
| 852 | 889 | break; |
| 853 | 890 | case SEEK_CUR: |
| 854 | 891 | nd = browser->top; |
| 855 | 892 | goto do_offset; |
| 856 | 893 | case SEEK_END: |
| 857 | − nd = hists__filter_prev_entries(rb_last(browser->entries)); | |
| 894 | + nd = hists__filter_prev_entries(rb_last(browser->entries), | |
| 895 | + hb->hists, hb->min_pcnt); | |
| 858 | 896 | first = false; |
| 859 | 897 | break; |
| 860 | 898 | default: |
| @@ -897,7 +935,8 @@ do_offset: · 36 unmodified lines | ||
| 897 | 935 | break; |
| 898 | 936 | } |
| 899 | 937 | } |
| 900 | − nd = hists__filter_entries(rb_next(nd)); | |
| 938 | + nd = hists__filter_entries(rb_next(nd), hb->hists, | |
| 939 | + hb->min_pcnt); | |
| 901 | 940 | if (nd == NULL) |
| 902 | 941 | break; |
| 903 | 942 | --offset; |
| @@ -930,7 +969,8 @@ do_offset: · 26 unmodified lines | ||
| 930 | 969 | } |
| 931 | 970 | } |
| 932 | 971 | |
| 933 | − nd = hists__filter_prev_entries(rb_prev(nd)); | |
| 972 | + nd = hists__filter_prev_entries(rb_prev(nd), hb->hists, | |
| 973 | + hb->min_pcnt); | |
| 934 | 974 | if (nd == NULL) |
| 935 | 975 | break; |
| 936 | 976 | ++offset; |
| @@ -1099,14 +1139,17 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser, · 162 unmodified lines | ||
| 1099 | 1139 | |
| 1100 | 1140 | static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) |
| 1101 | 1141 | { |
| 1102 | − struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries)); | |
| 1142 | + struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries), | |
| 1143 | + browser->hists, | |
| 1144 | + browser->min_pcnt); | |
| 1103 | 1145 | int printed = 0; |
| 1104 | 1146 | |
| 1105 | 1147 | while (nd) { |
| 1106 | 1148 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
| 1107 | 1149 | |
| 1108 | 1150 | printed += hist_browser__fprintf_entry(browser, h, fp); |
| 1109 | − nd = hists__filter_entries(rb_next(nd)); | |
| 1151 | + nd = hists__filter_entries(rb_next(nd), browser->hists, | |
| 1152 | + browser->min_pcnt); | |
| 1110 | 1153 | } |
| 1111 | 1154 | |
| 1112 | 1155 | return printed; |
| @@ -1155,10 +1198,6 @@ static struct hist_browser *hist_browser__new(struct hists *hists) · 42 unmodified lines | ||
| 1155 | 1198 | browser->b.refresh = hist_browser__refresh; |
| 1156 | 1199 | browser->b.seek = ui_browser__hists_seek; |
| 1157 | 1200 | browser->b.use_navkeypressed = true; |
| 1158 | − if (sort__branch_mode == 1) | |
| 1159 | − browser->has_symbols = sort_sym_from.list.next != NULL; | |
| 1160 | − else | |
| 1161 | − browser->has_symbols = sort_sym.list.next != NULL; | |
| 1162 | 1201 | } |
| 1163 | 1202 | |
| 1164 | 1203 | return browser; |
| @@ -1329,11 +1368,25 @@ close_file_and_continue: · 164 unmodified lines | ||
| 1329 | 1368 | return ret; |
| 1330 | 1369 | } |
| 1331 | 1370 | |
| 1371 | +static void hist_browser__update_pcnt_entries(struct hist_browser *hb) | |
| 1372 | +{ | |
| 1373 | + u64 nr_entries = 0; | |
| 1374 | + struct rb_node *nd = rb_first(&hb->hists->entries); | |
| 1375 | + | |
| 1376 | + while (nd) { | |
| 1377 | + nr_entries++; | |
| 1378 | + nd = hists__filter_entries(rb_next(nd), hb->hists, | |
| 1379 | + hb->min_pcnt); | |
| 1380 | + } | |
| 1381 | + | |
| 1382 | + hb->nr_pcnt_entries = nr_entries; | |
| 1383 | +} | |
| 1332 | 1384 | |
| 1333 | 1385 | static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, |
| 1334 | 1386 | const char *helpline, const char *ev_name, |
| 1335 | 1387 | bool left_exits, |
| 1336 | 1388 | struct hist_browser_timer *hbt, |
| 1389 | + float min_pcnt, | |
| 1337 | 1390 | struct perf_session_env *env) |
| 1338 | 1391 | { |
| 1339 | 1392 | struct hists *hists = &evsel->hists; |
| @@ -1350,6 +1403,11 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, · 10 unmodified lines | ||
| 1350 | 1403 | if (browser == NULL) |
| 1351 | 1404 | return -1; |
| 1352 | 1405 | |
| 1406 | + if (min_pcnt) { | |
| 1407 | + browser->min_pcnt = min_pcnt; | |
| 1408 | + hist_browser__update_pcnt_entries(browser); | |
| 1409 | + } | |
| 1410 | + | |
| 1353 | 1411 | fstack = pstack__new(2); |
| 1354 | 1412 | if (fstack == NULL) |
| 1355 | 1413 | goto out; |
| @@ -1386,7 +1444,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, · 30 unmodified lines | ||
| 1386 | 1444 | */ |
| 1387 | 1445 | goto out_free_stack; |
| 1388 | 1446 | case 'a': |
| 1389 | − if (!browser->has_symbols) { | |
| 1447 | + if (!sort__has_sym) { | |
| 1390 | 1448 | ui_browser__warning(&browser->b, delay_secs * 2, |
| 1391 | 1449 | "Annotation is only available for symbolic views, " |
| 1392 | 1450 | "include \"sym*\" in --sort to use it."); |
| @@ -1485,10 +1543,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, · 92 unmodified lines | ||
| 1485 | 1543 | continue; |
| 1486 | 1544 | } |
| 1487 | 1545 | |
| 1488 | − if (!browser->has_symbols) | |
| 1546 | + if (!sort__has_sym) | |
| 1489 | 1547 | goto add_exit_option; |
| 1490 | 1548 | |
| 1491 | − if (sort__branch_mode == 1) { | |
| 1549 | + if (sort__mode == SORT_MODE__BRANCH) { | |
| 1492 | 1550 | bi = browser->he_selection->branch_info; |
| 1493 | 1551 | if (browser->selection != NULL && |
| 1494 | 1552 | bi && |
| @@ -1689,6 +1747,7 @@ struct perf_evsel_menu { · 194 unmodified lines | ||
| 1689 | 1747 | struct ui_browser b; |
| 1690 | 1748 | struct perf_evsel *selection; |
| 1691 | 1749 | bool lost_events, lost_events_warned; |
| 1750 | + float min_pcnt; | |
| 1692 | 1751 | struct perf_session_env *env; |
| 1693 | 1752 | }; |
| 1694 | 1753 | |
| @@ -1782,6 +1841,7 @@ browse_hists: · 87 unmodified lines | ||
| 1782 | 1841 | ev_name = perf_evsel__name(pos); |
| 1783 | 1842 | key = perf_evsel__hists_browse(pos, nr_events, help, |
| 1784 | 1843 | ev_name, true, hbt, |
| 1844 | + menu->min_pcnt, | |
| 1785 | 1845 | menu->env); |
| 1786 | 1846 | ui_browser__show_title(&menu->b, title); |
| 1787 | 1847 | switch (key) { |
| @@ -1843,6 +1903,7 @@ static bool filter_group_entries(struct ui_browser *self __maybe_unused, · 55 unmodified lines | ||
| 1843 | 1903 | static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, |
| 1844 | 1904 | int nr_entries, const char *help, |
| 1845 | 1905 | struct hist_browser_timer *hbt, |
| 1906 | + float min_pcnt, | |
| 1846 | 1907 | struct perf_session_env *env) |
| 1847 | 1908 | { |
| 1848 | 1909 | struct perf_evsel *pos; |
| @@ -1856,6 +1917,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, · 7 unmodified lines | ||
| 1856 | 1917 | .nr_entries = nr_entries, |
| 1857 | 1918 | .priv = evlist, |
| 1858 | 1919 | }, |
| 1920 | + .min_pcnt = min_pcnt, | |
| 1859 | 1921 | .env = env, |
| 1860 | 1922 | }; |
| 1861 | 1923 | |
| @@ -1874,6 +1936,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, · 12 unmodified lines | ||
| 1874 | 1936 | |
| 1875 | 1937 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, |
| 1876 | 1938 | struct hist_browser_timer *hbt, |
| 1939 | + float min_pcnt, | |
| 1877 | 1940 | struct perf_session_env *env) |
| 1878 | 1941 | { |
| 1879 | 1942 | int nr_entries = evlist->nr_entries; |
| @@ -1885,7 +1948,8 @@ single_entry: · 5 unmodified lines | ||
| 1885 | 1948 | const char *ev_name = perf_evsel__name(first); |
| 1886 | 1949 | |
| 1887 | 1950 | return perf_evsel__hists_browse(first, nr_entries, help, |
| 1888 | − ev_name, false, hbt, env); | |
| 1951 | + ev_name, false, hbt, min_pcnt, | |
| 1952 | + env); | |
| 1889 | 1953 | } |
| 1890 | 1954 | |
| 1891 | 1955 | if (symbol_conf.event_group) { |
| @@ -1901,5 +1965,5 @@ single_entry: · 9 unmodified lines | ||
| 1901 | 1965 | } |
| 1902 | 1966 | |
| 1903 | 1967 | return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, |
| 1904 | − hbt, env); | |
| 1968 | + hbt, min_pcnt, env); | |
| 1905 | 1969 | } |
| @@ -124,7 +124,8 @@ void perf_gtk__init_hpp(void) · 123 unmodified lines | ||
| 124 | 124 | perf_gtk__hpp_color_overhead_guest_us; |
| 125 | 125 | } |
| 126 | 126 | |
| 127 | −static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) | |
| 127 | +static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, | |
| 128 | + float min_pcnt) | |
| 128 | 129 | { |
| 129 | 130 | struct perf_hpp_fmt *fmt; |
| 130 | 131 | GType col_types[MAX_COLUMNS]; |
| @@ -189,10 +190,15 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) · 58 unmodified lines | ||
| 189 | 190 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { |
| 190 | 191 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
| 191 | 192 | GtkTreeIter iter; |
| 193 | + float percent = h->stat.period * 100.0 / | |
| 194 | + hists->stats.total_period; | |
| 192 | 195 | |
| 193 | 196 | if (h->filtered) |
| 194 | 197 | continue; |
| 195 | 198 | |
| 199 | + if (percent < min_pcnt) | |
| 200 | + continue; | |
| 201 | + | |
| 196 | 202 | gtk_list_store_append(store, &iter); |
| 197 | 203 | |
| 198 | 204 | col_idx = 0; |
| @@ -222,7 +228,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) · 23 unmodified lines | ||
| 222 | 228 | |
| 223 | 229 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, |
| 224 | 230 | const char *help, |
| 225 | − struct hist_browser_timer *hbt __maybe_unused) | |
| 231 | + struct hist_browser_timer *hbt __maybe_unused, | |
| 232 | + float min_pcnt) | |
| 226 | 233 | { |
| 227 | 234 | struct perf_evsel *pos; |
| 228 | 235 | GtkWidget *vbox; |
| @@ -286,7 +293,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, · 57 unmodified lines | ||
| 286 | 293 | GTK_POLICY_AUTOMATIC, |
| 287 | 294 | GTK_POLICY_AUTOMATIC); |
| 288 | 295 | |
| 289 | − perf_gtk__show_hists(scrolled_window, hists); | |
| 296 | + perf_gtk__show_hists(scrolled_window, hists, min_pcnt); | |
| 290 | 297 | |
| 291 | 298 | tab_label = gtk_label_new(evname); |
| 292 | 299 | |
| @@ -334,7 +334,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, · 333 unmodified lines | ||
| 334 | 334 | } |
| 335 | 335 | |
| 336 | 336 | size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, |
| 337 | − int max_cols, FILE *fp) | |
| 337 | + int max_cols, float min_pcnt, FILE *fp) | |
| 338 | 338 | { |
| 339 | 339 | struct perf_hpp_fmt *fmt; |
| 340 | 340 | struct sort_entry *se; |
| @@ -440,10 +440,15 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, · 99 unmodified lines | ||
| 440 | 440 | print_entries: |
| 441 | 441 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { |
| 442 | 442 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
| 443 | + float percent = h->stat.period * 100.0 / | |
| 444 | + hists->stats.total_period; | |
| 443 | 445 | |
| 444 | 446 | if (h->filtered) |
| 445 | 447 | continue; |
| 446 | 448 | |
| 449 | + if (percent < min_pcnt) | |
| 450 | + continue; | |
| 451 | + | |
| 447 | 452 | ret += hist_entry__fprintf(h, max_cols, hists, fp); |
| 448 | 453 | |
| 449 | 454 | if (max_rows && ++nr_rows >= max_rows) |
| @@ -776,6 +776,8 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, · 775 unmodified lines | ||
| 776 | 776 | if (pipe_output) |
| 777 | 777 | dup2(2, 1); |
| 778 | 778 | |
| 779 | + signal(SIGTERM, SIG_DFL); | |
| 780 | + | |
| 779 | 781 | close(child_ready_pipe[0]); |
| 780 | 782 | close(go_pipe[1]); |
| 781 | 783 | fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); |
| @@ -1514,7 +1514,7 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, · 1513 unmodified lines | ||
| 1514 | 1514 | switch (err) { |
| 1515 | 1515 | case EPERM: |
| 1516 | 1516 | case EACCES: |
| 1517 | − return scnprintf(msg, size, "%s", | |
| 1517 | + return scnprintf(msg, size, | |
| 1518 | 1518 | "You may not have permission to collect %sstats.\n" |
| 1519 | 1519 | "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" |
| 1520 | 1520 | " -1 - Not paranoid at all\n" |
| @@ -2391,7 +2391,6 @@ out_err_write: · 2390 unmodified lines | ||
| 2391 | 2391 | } |
| 2392 | 2392 | lseek(fd, header->data_offset + header->data_size, SEEK_SET); |
| 2393 | 2393 | |
| 2394 | − header->frozen = 1; | |
| 2395 | 2394 | return 0; |
| 2396 | 2395 | } |
| 2397 | 2396 | |
| @@ -2871,7 +2870,6 @@ int perf_session__read_header(struct perf_session *session, int fd) · 473 unmodified lines | ||
| 2871 | 2870 | session->pevent)) |
| 2872 | 2871 | goto out_delete_evlist; |
| 2873 | 2872 | |
| 2874 | − header->frozen = 1; | |
| 2875 | 2873 | return 0; |
| 2876 | 2874 | out_errno: |
| 2877 | 2875 | return -errno; |
| @@ -84,7 +84,6 @@ struct perf_session_env { · 83 unmodified lines | ||
| 84 | 84 | }; |
| 85 | 85 | |
| 86 | 86 | struct perf_header { |
| 87 | − int frozen; | |
| 88 | 87 | bool needs_swap; |
| 89 | 88 | s64 attr_offset; |
| 90 | 89 | u64 data_offset; |
| @@ -70,9 +70,17 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) · 69 unmodified lines | ||
| 70 | 70 | int symlen; |
| 71 | 71 | u16 len; |
| 72 | 72 | |
| 73 | − if (h->ms.sym) | |
| 74 | − hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4); | |
| 75 | − else { | |
| 73 | + /* | |
| 74 | + * +4 accounts for '[x] ' priv level info | |
| 75 | + * +2 accounts for 0x prefix on raw addresses | |
| 76 | + * +3 accounts for ' y ' symtab origin info | |
| 77 | + */ | |
| 78 | + if (h->ms.sym) { | |
| 79 | + symlen = h->ms.sym->namelen + 4; | |
| 80 | + if (verbose) | |
| 81 | + symlen += BITS_PER_LONG / 4 + 2 + 3; | |
| 82 | + hists__new_col_len(hists, HISTC_SYMBOL, symlen); | |
| 83 | + } else { | |
| 76 | 84 | symlen = unresolved_col_width + 4 + 2; |
| 77 | 85 | hists__new_col_len(hists, HISTC_SYMBOL, symlen); |
| 78 | 86 | hists__set_unres_dso_col_len(hists, HISTC_DSO); |
| @@ -91,12 +99,10 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) · 12 unmodified lines | ||
| 91 | 99 | hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen); |
| 92 | 100 | |
| 93 | 101 | if (h->branch_info) { |
| 94 | − /* | |
| 95 | − * +4 accounts for '[x] ' priv level info | |
| 96 | − * +2 account of 0x prefix on raw addresses | |
| 97 | − */ | |
| 98 | 102 | if (h->branch_info->from.sym) { |
| 99 | 103 | symlen = (int)h->branch_info->from.sym->namelen + 4; |
| 104 | + if (verbose) | |
| 105 | + symlen += BITS_PER_LONG / 4 + 2 + 3; | |
| 100 | 106 | hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen); |
| 101 | 107 | |
| 102 | 108 | symlen = dso__name_len(h->branch_info->from.map->dso); |
| @@ -109,6 +115,8 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) · 6 unmodified lines | ||
| 109 | 115 | |
| 110 | 116 | if (h->branch_info->to.sym) { |
| 111 | 117 | symlen = (int)h->branch_info->to.sym->namelen + 4; |
| 118 | + if (verbose) | |
| 119 | + symlen += BITS_PER_LONG / 4 + 2 + 3; | |
| 112 | 120 | hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen); |
| 113 | 121 | |
| 114 | 122 | symlen = dso__name_len(h->branch_info->to.map->dso); |
| @@ -121,10 +129,6 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) · 6 unmodified lines | ||
| 121 | 129 | } |
| 122 | 130 | |
| 123 | 131 | if (h->mem_info) { |
| 124 | − /* | |
| 125 | − * +4 accounts for '[x] ' priv level info | |
| 126 | − * +2 account of 0x prefix on raw addresses | |
| 127 | − */ | |
| 128 | 132 | if (h->mem_info->daddr.sym) { |
| 129 | 133 | symlen = (int)h->mem_info->daddr.sym->namelen + 4 |
| 130 | 134 | + unresolved_col_width + 2; |
| @@ -236,8 +240,7 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) · 105 unmodified lines | ||
| 236 | 240 | return he->stat.period == 0; |
| 237 | 241 | } |
| 238 | 242 | |
| 239 | −static void __hists__decay_entries(struct hists *hists, bool zap_user, | |
| 240 | − bool zap_kernel, bool threaded) | |
| 243 | +void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel) | |
| 241 | 244 | { |
| 242 | 245 | struct rb_node *next = rb_first(&hists->entries); |
| 243 | 246 | struct hist_entry *n; |
| @@ -256,7 +259,7 @@ static void __hists__decay_entries(struct hists *hists, bool zap_user, · 12 unmodified lines | ||
| 256 | 259 | !n->used) { |
| 257 | 260 | rb_erase(&n->rb_node, &hists->entries); |
| 258 | 261 | |
| 259 | − if (sort__need_collapse || threaded) | |
| 262 | + if (sort__need_collapse) | |
| 260 | 263 | rb_erase(&n->rb_node_in, &hists->entries_collapsed); |
| 261 | 264 | |
| 262 | 265 | hist_entry__free(n); |
| @@ -265,17 +268,6 @@ static void __hists__decay_entries(struct hists *hists, bool zap_user, · 2 unmodified lines | ||
| 265 | 268 | } |
| 266 | 269 | } |
| 267 | 270 | |
| 268 | −void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel) | |
| 269 | −{ | |
| 270 | − return __hists__decay_entries(hists, zap_user, zap_kernel, false); | |
| 271 | −} | |
| 272 | − | |
| 273 | −void hists__decay_entries_threaded(struct hists *hists, | |
| 274 | − bool zap_user, bool zap_kernel) | |
| 275 | −{ | |
| 276 | − return __hists__decay_entries(hists, zap_user, zap_kernel, true); | |
| 277 | −} | |
| 278 | − | |
| 279 | 271 | /* |
| 280 | 272 | * histogram, sorted on item, collects periods |
| 281 | 273 | */ |
| @@ -292,6 +284,20 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) · 10 unmodified lines | ||
| 292 | 284 | he->ms.map->referenced = true; |
| 293 | 285 | |
| 294 | 286 | if (he->branch_info) { |
| 287 | + /* | |
| 288 | + * This branch info is (a part of) allocated from | |
| 289 | + * machine__resolve_bstack() and will be freed after | |
| 290 | + * adding new entries. So we need to save a copy. | |
| 291 | + */ | |
| 292 | + he->branch_info = malloc(sizeof(*he->branch_info)); | |
| 293 | + if (he->branch_info == NULL) { | |
| 294 | + free(he); | |
| 295 | + return NULL; | |
| 296 | + } | |
| 297 | + | |
| 298 | + memcpy(he->branch_info, template->branch_info, | |
| 299 | + sizeof(*he->branch_info)); | |
| 300 | + | |
| 295 | 301 | if (he->branch_info->from.map) |
| 296 | 302 | he->branch_info->from.map->referenced = true; |
| 297 | 303 | if (he->branch_info->to.map) |
| @@ -341,8 +347,6 @@ static struct hist_entry *add_hist_entry(struct hists *hists, · 43 unmodified lines | ||
| 341 | 347 | struct hist_entry *he; |
| 342 | 348 | int cmp; |
| 343 | 349 | |
| 344 | − pthread_mutex_lock(&hists->lock); | |
| 345 | − | |
| 346 | 350 | p = &hists->entries_in->rb_node; |
| 347 | 351 | |
| 348 | 352 | while (*p != NULL) { |
| @@ -360,6 +364,12 @@ static struct hist_entry *add_hist_entry(struct hists *hists, · 11 unmodified lines | ||
| 360 | 364 | if (!cmp) { |
| 361 | 365 | he_stat__add_period(&he->stat, period, weight); |
| 362 | 366 | |
| 367 | + /* | |
| 368 | + * This mem info was allocated from machine__resolve_mem | |
| 369 | + * and will not be used anymore. | |
| 370 | + */ | |
| 371 | + free(entry->mem_info); | |
| 372 | + | |
| 363 | 373 | /* If the map of an existing hist_entry has |
| 364 | 374 | * become out-of-date due to an exec() or |
| 365 | 375 | * similar, update it. Otherwise we will |
| @@ -382,14 +392,12 @@ static struct hist_entry *add_hist_entry(struct hists *hists, · 16 unmodified lines | ||
| 382 | 392 | |
| 383 | 393 | he = hist_entry__new(entry); |
| 384 | 394 | if (!he) |
| 385 | − goto out_unlock; | |
| 395 | + return NULL; | |
| 386 | 396 | |
| 387 | 397 | rb_link_node(&he->rb_node_in, parent, p); |
| 388 | 398 | rb_insert_color(&he->rb_node_in, hists->entries_in); |
| 389 | 399 | out: |
| 390 | 400 | hist_entry__add_cpumode_period(he, al->cpumode, period); |
| 391 | −out_unlock: | |
| 392 | − pthread_mutex_unlock(&hists->lock); | |
| 393 | 401 | return he; |
| 394 | 402 | } |
| 395 | 403 | |
| @@ -589,13 +597,13 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he) · 193 unmodified lines | ||
| 589 | 597 | hists__filter_entry_by_symbol(hists, he); |
| 590 | 598 | } |
| 591 | 599 | |
| 592 | −static void __hists__collapse_resort(struct hists *hists, bool threaded) | |
| 600 | +void hists__collapse_resort(struct hists *hists) | |
| 593 | 601 | { |
| 594 | 602 | struct rb_root *root; |
| 595 | 603 | struct rb_node *next; |
| 596 | 604 | struct hist_entry *n; |
| 597 | 605 | |
| 598 | − if (!sort__need_collapse && !threaded) | |
| 606 | + if (!sort__need_collapse) | |
| 599 | 607 | return; |
| 600 | 608 | |
| 601 | 609 | root = hists__get_rotate_entries_in(hists); |
| @@ -617,16 +625,6 @@ static void __hists__collapse_resort(struct hists *hists, bool threaded) · 15 unmodified lines | ||
| 617 | 625 | } |
| 618 | 626 | } |
| 619 | 627 | |
| 620 | −void hists__collapse_resort(struct hists *hists) | |
| 621 | −{ | |
| 622 | − return __hists__collapse_resort(hists, false); | |
| 623 | −} | |
| 624 | − | |
| 625 | −void hists__collapse_resort_threaded(struct hists *hists) | |
| 626 | −{ | |
| 627 | − return __hists__collapse_resort(hists, true); | |
| 628 | −} | |
| 629 | − | |
| 630 | 628 | /* |
| 631 | 629 | * reverse the map, sort on period. |
| 632 | 630 | */ |
| @@ -713,7 +711,7 @@ static void __hists__insert_output_entry(struct rb_root *entries, · 80 unmodified lines | ||
| 713 | 711 | rb_insert_color(&he->rb_node, entries); |
| 714 | 712 | } |
| 715 | 713 | |
| 716 | −static void __hists__output_resort(struct hists *hists, bool threaded) | |
| 714 | +void hists__output_resort(struct hists *hists) | |
| 717 | 715 | { |
| 718 | 716 | struct rb_root *root; |
| 719 | 717 | struct rb_node *next; |
| @@ -722,7 +720,7 @@ static void __hists__output_resort(struct hists *hists, bool threaded) · 2 unmodified lines | ||
| 722 | 720 | |
| 723 | 721 | min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100); |
| 724 | 722 | |
| 725 | − if (sort__need_collapse || threaded) | |
| 723 | + if (sort__need_collapse) | |
| 726 | 724 | root = &hists->entries_collapsed; |
| 727 | 725 | else |
| 728 | 726 | root = hists->entries_in; |
| @@ -743,16 +741,6 @@ static void __hists__output_resort(struct hists *hists, bool threaded) · 14 unmodified lines | ||
| 743 | 741 | } |
| 744 | 742 | } |
| 745 | 743 | |
| 746 | −void hists__output_resort(struct hists *hists) | |
| 747 | −{ | |
| 748 | − return __hists__output_resort(hists, false); | |
| 749 | −} | |
| 750 | − | |
| 751 | −void hists__output_resort_threaded(struct hists *hists) | |
| 752 | −{ | |
| 753 | − return __hists__output_resort(hists, true); | |
| 754 | −} | |
| 755 | − | |
| 756 | 744 | static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h, |
| 757 | 745 | enum hist_filter filter) |
| 758 | 746 | { |
| @@ -43,12 +43,12 @@ enum hist_column { · 42 unmodified lines | ||
| 43 | 43 | HISTC_COMM, |
| 44 | 44 | HISTC_PARENT, |
| 45 | 45 | HISTC_CPU, |
| 46 | + HISTC_SRCLINE, | |
| 46 | 47 | HISTC_MISPREDICT, |
| 47 | 48 | HISTC_SYMBOL_FROM, |
| 48 | 49 | HISTC_SYMBOL_TO, |
| 49 | 50 | HISTC_DSO_FROM, |
| 50 | 51 | HISTC_DSO_TO, |
| 51 | − HISTC_SRCLINE, | |
| 52 | 52 | HISTC_LOCAL_WEIGHT, |
| 53 | 53 | HISTC_GLOBAL_WEIGHT, |
| 54 | 54 | HISTC_MEM_DADDR_SYMBOL, |
| @@ -104,13 +104,9 @@ struct hist_entry *__hists__add_mem_entry(struct hists *self, · 49 unmodified lines | ||
| 104 | 104 | u64 weight); |
| 105 | 105 | |
| 106 | 106 | void hists__output_resort(struct hists *self); |
| 107 | −void hists__output_resort_threaded(struct hists *hists); | |
| 108 | 107 | void hists__collapse_resort(struct hists *self); |
| 109 | −void hists__collapse_resort_threaded(struct hists *hists); | |
| 110 | 108 | |
| 111 | 109 | void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); |
| 112 | −void hists__decay_entries_threaded(struct hists *hists, bool zap_user, | |
| 113 | − bool zap_kernel); | |
| 114 | 110 | void hists__output_recalc_col_len(struct hists *hists, int max_rows); |
| 115 | 111 | |
| 116 | 112 | void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h); |
| @@ -119,7 +115,7 @@ void events_stats__inc(struct events_stats *stats, u32 type); · 2 unmodified lines | ||
| 119 | 115 | size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); |
| 120 | 116 | |
| 121 | 117 | size_t hists__fprintf(struct hists *self, bool show_header, int max_rows, |
| 122 | − int max_cols, FILE *fp); | |
| 118 | + int max_cols, float min_pcnt, FILE *fp); | |
| 123 | 119 | |
| 124 | 120 | int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); |
| 125 | 121 | int hist_entry__annotate(struct hist_entry *self, size_t privsize); |
| @@ -199,6 +195,7 @@ int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, · 73 unmodified lines | ||
| 199 | 195 | |
| 200 | 196 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, |
| 201 | 197 | struct hist_browser_timer *hbt, |
| 198 | + float min_pcnt, | |
| 202 | 199 | struct perf_session_env *env); |
| 203 | 200 | int script_browse(const char *script_opt); |
| 204 | 201 | #else |
| @@ -206,6 +203,7 @@ static inline · 1 unmodified line | ||
| 206 | 203 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, |
| 207 | 204 | const char *help __maybe_unused, |
| 208 | 205 | struct hist_browser_timer *hbt __maybe_unused, |
| 206 | + float min_pcnt __maybe_unused, | |
| 209 | 207 | struct perf_session_env *env __maybe_unused) |
| 210 | 208 | { |
| 211 | 209 | return 0; |
| @@ -233,12 +231,14 @@ static inline int script_browse(const char *script_opt __maybe_unused) · 21 unmodified lines | ||
| 233 | 231 | |
| 234 | 232 | #ifdef GTK2_SUPPORT |
| 235 | 233 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help, |
| 236 | − struct hist_browser_timer *hbt __maybe_unused); | |
| 234 | + struct hist_browser_timer *hbt __maybe_unused, | |
| 235 | + float min_pcnt); | |
| 237 | 236 | #else |
| 238 | 237 | static inline |
| 239 | 238 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, |
| 240 | 239 | const char *help __maybe_unused, |
| 241 | − struct hist_browser_timer *hbt __maybe_unused) | |
| 240 | + struct hist_browser_timer *hbt __maybe_unused, | |
| 241 | + float min_pcnt __maybe_unused) | |
| 242 | 242 | { |
| 243 | 243 | return 0; |
| 244 | 244 | } |
| @@ -21,6 +21,7 @@ const char *map_type__name[MAP__NR_TYPES] = { · 20 unmodified lines | ||
| 21 | 21 | static inline int is_anon_memory(const char *filename) |
| 22 | 22 | { |
| 23 | 23 | return !strcmp(filename, "//anon") || |
| 24 | + !strcmp(filename, "/dev/zero (deleted)") || | |
| 24 | 25 | !strcmp(filename, "/anon_hugepage (deleted)"); |
| 25 | 26 | } |
| 26 | 27 | |
| @@ -37,7 +37,6 @@ struct perf_session { · 36 unmodified lines | ||
| 37 | 37 | int fd; |
| 38 | 38 | bool fd_pipe; |
| 39 | 39 | bool repipe; |
| 40 | − int cwdlen; | |
| 41 | 40 | char *cwd; |
| 42 | 41 | struct ordered_samples ordered_samples; |
| 43 | 42 | char filename[1]; |
| @@ -18,8 +18,9 @@ class install_lib(_install_lib): · 17 unmodified lines | ||
| 18 | 18 | self.build_dir = build_lib |
| 19 | 19 | |
| 20 | 20 | |
| 21 | −cflags = ['-fno-strict-aliasing', '-Wno-write-strings'] | |
| 22 | −cflags += getenv('CFLAGS', '').split() | |
| 21 | +cflags = getenv('CFLAGS', '').split() | |
| 22 | +# switch off several checks (need to be at the end of cflags list) | |
| 23 | +cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter' ] | |
| 23 | 24 | |
| 24 | 25 | build_lib = getenv('PYTHON_EXTBUILD_LIB') |
| 25 | 26 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') |
| @@ -1,5 +1,6 @@ | ||
| 1 | 1 | #include "sort.h" |
| 2 | 2 | #include "hist.h" |
| 3 | +#include "symbol.h" | |
| 3 | 4 | |
| 4 | 5 | regex_t parent_regex; |
| 5 | 6 | const char default_parent_pattern[] = "^sys_|^do_page_fault"; |
| @@ -9,7 +10,7 @@ const char *sort_order = default_sort_order; · 3 unmodified lines | ||
| 9 | 10 | int sort__need_collapse = 0; |
| 10 | 11 | int sort__has_parent = 0; |
| 11 | 12 | int sort__has_sym = 0; |
| 12 | −int sort__branch_mode = -1; /* -1 = means not set */ | |
| 13 | +enum sort_mode sort__mode = SORT_MODE__NORMAL; | |
| 13 | 14 | |
| 14 | 15 | enum sort_type sort__first_dimension; |
| 15 | 16 | |
| @@ -194,7 +195,7 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, · 178 unmodified lines | ||
| 194 | 195 | if (verbose) { |
| 195 | 196 | char o = map ? dso__symtab_origin(map->dso) : '!'; |
| 196 | 197 | ret += repsep_snprintf(bf, size, "%-#*llx %c ", |
| 197 | − BITS_PER_LONG / 4, ip, o); | |
| 198 | + BITS_PER_LONG / 4 + 2, ip, o); | |
| 198 | 199 | } |
| 199 | 200 | |
| 200 | 201 | ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level); |
| @@ -871,14 +872,6 @@ static struct sort_dimension common_sort_dimensions[] = { · 670 unmodified lines | ||
| 871 | 872 | DIM(SORT_PARENT, "parent", sort_parent), |
| 872 | 873 | DIM(SORT_CPU, "cpu", sort_cpu), |
| 873 | 874 | DIM(SORT_SRCLINE, "srcline", sort_srcline), |
| 874 | − DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), | |
| 875 | − DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), | |
| 876 | − DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym), | |
| 877 | − DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso), | |
| 878 | − DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked), | |
| 879 | − DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb), | |
| 880 | − DIM(SORT_MEM_LVL, "mem", sort_mem_lvl), | |
| 881 | − DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop), | |
| 882 | 875 | }; |
| 883 | 876 | |
| 884 | 877 | #undef DIM |
| @@ -895,6 +888,36 @@ static struct sort_dimension bstack_sort_dimensions[] = { · 10 unmodified lines | ||
| 895 | 888 | |
| 896 | 889 | #undef DIM |
| 897 | 890 | |
| 891 | +#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) } | |
| 892 | + | |
| 893 | +static struct sort_dimension memory_sort_dimensions[] = { | |
| 894 | + DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), | |
| 895 | + DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), | |
| 896 | + DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym), | |
| 897 | + DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso), | |
| 898 | + DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked), | |
| 899 | + DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb), | |
| 900 | + DIM(SORT_MEM_LVL, "mem", sort_mem_lvl), | |
| 901 | + DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop), | |
| 902 | +}; | |
| 903 | + | |
| 904 | +#undef DIM | |
| 905 | + | |
| 906 | +static void __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx) | |
| 907 | +{ | |
| 908 | + if (sd->taken) | |
| 909 | + return; | |
| 910 | + | |
| 911 | + if (sd->entry->se_collapse) | |
| 912 | + sort__need_collapse = 1; | |
| 913 | + | |
| 914 | + if (list_empty(&hist_entry__sort_list)) | |
| 915 | + sort__first_dimension = idx; | |
| 916 | + | |
| 917 | + list_add_tail(&sd->entry->list, &hist_entry__sort_list); | |
| 918 | + sd->taken = 1; | |
| 919 | +} | |
| 920 | + | |
| 898 | 921 | int sort_dimension__add(const char *tok) |
| 899 | 922 | { |
| 900 | 923 | unsigned int i; |
| @@ -915,25 +938,11 @@ int sort_dimension__add(const char *tok) · 14 unmodified lines | ||
| 915 | 938 | return -EINVAL; |
| 916 | 939 | } |
| 917 | 940 | sort__has_parent = 1; |
| 918 | − } else if (sd->entry == &sort_sym || | |
| 919 | − sd->entry == &sort_sym_from || | |
| 920 | − sd->entry == &sort_sym_to || | |
| 921 | − sd->entry == &sort_mem_daddr_sym) { | |
| 941 | + } else if (sd->entry == &sort_sym) { | |
| 922 | 942 | sort__has_sym = 1; |
| 923 | 943 | } |
| 924 | 944 | |
| 925 | − if (sd->taken) | |
| 926 | − return 0; | |
| 927 | − | |
| 928 | − if (sd->entry->se_collapse) | |
| 929 | − sort__need_collapse = 1; | |
| 930 | − | |
| 931 | − if (list_empty(&hist_entry__sort_list)) | |
| 932 | − sort__first_dimension = i; | |
| 933 | − | |
| 934 | − list_add_tail(&sd->entry->list, &hist_entry__sort_list); | |
| 935 | − sd->taken = 1; | |
| 936 | − | |
| 945 | + __sort_dimension__add(sd, i); | |
| 937 | 946 | return 0; |
| 938 | 947 | } |
| 939 | 948 | |
| @@ -943,24 +952,29 @@ int sort_dimension__add(const char *tok) · 3 unmodified lines | ||
| 943 | 952 | if (strncasecmp(tok, sd->name, strlen(tok))) |
| 944 | 953 | continue; |
| 945 | 954 | |
| 946 | − if (sort__branch_mode != 1) | |
| 955 | + if (sort__mode != SORT_MODE__BRANCH) | |
| 947 | 956 | return -EINVAL; |
| 948 | 957 | |
| 949 | 958 | if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) |
| 950 | 959 | sort__has_sym = 1; |
| 951 | 960 | |
| 952 | − if (sd->taken) | |
| 953 | − return 0; | |
| 961 | + __sort_dimension__add(sd, i + __SORT_BRANCH_STACK); | |
| 962 | + return 0; | |
| 963 | + } | |
| 954 | 964 | |
| 955 | − if (sd->entry->se_collapse) | |
| 956 | − sort__need_collapse = 1; | |
| 965 | + for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) { | |
| 966 | + struct sort_dimension *sd = &memory_sort_dimensions[i]; | |
| 957 | 967 | |
| 958 | − if (list_empty(&hist_entry__sort_list)) | |
| 959 | − sort__first_dimension = i + __SORT_BRANCH_STACK; | |
| 968 | + if (strncasecmp(tok, sd->name, strlen(tok))) | |
| 969 | + continue; | |
| 960 | 970 | |
| 961 | − list_add_tail(&sd->entry->list, &hist_entry__sort_list); | |
| 962 | − sd->taken = 1; | |
| 971 | + if (sort__mode != SORT_MODE__MEMORY) | |
| 972 | + return -EINVAL; | |
| 973 | + | |
| 974 | + if (sd->entry == &sort_mem_daddr_sym) | |
| 975 | + sort__has_sym = 1; | |
| 963 | 976 | |
| 977 | + __sort_dimension__add(sd, i + __SORT_MEMORY_MODE); | |
| 964 | 978 | return 0; |
| 965 | 979 | } |
| 966 | 980 | |
| @@ -993,8 +1007,9 @@ int setup_sorting(void) · 26 unmodified lines | ||
| 993 | 1007 | return ret; |
| 994 | 1008 | } |
| 995 | 1009 | |
| 996 | −void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, | |
| 997 | − const char *list_name, FILE *fp) | |
| 1010 | +static void sort_entry__setup_elide(struct sort_entry *self, | |
| 1011 | + struct strlist *list, | |
| 1012 | + const char *list_name, FILE *fp) | |
| 998 | 1013 | { |
| 999 | 1014 | if (list && strlist__nr_entries(list) == 1) { |
| 1000 | 1015 | if (fp != NULL) |
| @@ -1003,3 +1018,42 @@ void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, · 2 unmodified lines | ||
| 1003 | 1018 | self->elide = true; |
| 1004 | 1019 | } |
| 1005 | 1020 | } |
| 1021 | + | |
| 1022 | +void sort__setup_elide(FILE *output) | |
| 1023 | +{ | |
| 1024 | + sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, | |
| 1025 | + "dso", output); | |
| 1026 | + sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, | |
| 1027 | + "comm", output); | |
| 1028 | + sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, | |
| 1029 | + "symbol", output); | |
| 1030 | + | |
| 1031 | + if (sort__mode == SORT_MODE__BRANCH) { | |
| 1032 | + sort_entry__setup_elide(&sort_dso_from, | |
| 1033 | + symbol_conf.dso_from_list, | |
| 1034 | + "dso_from", output); | |
| 1035 | + sort_entry__setup_elide(&sort_dso_to, | |
| 1036 | + symbol_conf.dso_to_list, | |
| 1037 | + "dso_to", output); | |
| 1038 | + sort_entry__setup_elide(&sort_sym_from, | |
| 1039 | + symbol_conf.sym_from_list, | |
| 1040 | + "sym_from", output); | |
| 1041 | + sort_entry__setup_elide(&sort_sym_to, | |
| 1042 | + symbol_conf.sym_to_list, | |
| 1043 | + "sym_to", output); | |
| 1044 | + } else if (sort__mode == SORT_MODE__MEMORY) { | |
| 1045 | + sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, | |
| 1046 | + "symbol_daddr", output); | |
| 1047 | + sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, | |
| 1048 | + "dso_daddr", output); | |
| 1049 | + sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, | |
| 1050 | + "mem", output); | |
| 1051 | + sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, | |
| 1052 | + "local_weight", output); | |
| 1053 | + sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, | |
| 1054 | + "tlb", output); | |
| 1055 | + sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, | |
| 1056 | + "snoop", output); | |
| 1057 | + } | |
| 1058 | + | |
| 1059 | +} | |
| @@ -32,7 +32,7 @@ extern const char default_sort_order[]; · 31 unmodified lines | ||
| 32 | 32 | extern int sort__need_collapse; |
| 33 | 33 | extern int sort__has_parent; |
| 34 | 34 | extern int sort__has_sym; |
| 35 | −extern int sort__branch_mode; | |
| 35 | +extern enum sort_mode sort__mode; | |
| 36 | 36 | extern struct sort_entry sort_comm; |
| 37 | 37 | extern struct sort_entry sort_dso; |
| 38 | 38 | extern struct sort_entry sort_sym; |
| @@ -117,12 +117,18 @@ static inline struct hist_entry *hist_entry__next_pair(struct hist_entry *he) · 78 unmodified lines | ||
| 117 | 117 | return NULL; |
| 118 | 118 | } |
| 119 | 119 | |
| 120 | −static inline void hist_entry__add_pair(struct hist_entry *he, | |
| 121 | − struct hist_entry *pair) | |
| 120 | +static inline void hist_entry__add_pair(struct hist_entry *pair, | |
| 121 | + struct hist_entry *he) | |
| 122 | 122 | { |
| 123 | − list_add_tail(&he->pairs.head, &pair->pairs.node); | |
| 123 | + list_add_tail(&pair->pairs.node, &he->pairs.head); | |
| 124 | 124 | } |
| 125 | 125 | |
| 126 | +enum sort_mode { | |
| 127 | + SORT_MODE__NORMAL, | |
| 128 | + SORT_MODE__BRANCH, | |
| 129 | + SORT_MODE__MEMORY, | |
| 130 | +}; | |
| 131 | + | |
| 126 | 132 | enum sort_type { |
| 127 | 133 | /* common sort keys */ |
| 128 | 134 | SORT_PID, |
| @@ -132,14 +138,6 @@ enum sort_type { · 3 unmodified lines | ||
| 132 | 138 | SORT_PARENT, |
| 133 | 139 | SORT_CPU, |
| 134 | 140 | SORT_SRCLINE, |
| 135 | − SORT_LOCAL_WEIGHT, | |
| 136 | − SORT_GLOBAL_WEIGHT, | |
| 137 | − SORT_MEM_DADDR_SYMBOL, | |
| 138 | − SORT_MEM_DADDR_DSO, | |
| 139 | − SORT_MEM_LOCKED, | |
| 140 | − SORT_MEM_TLB, | |
| 141 | − SORT_MEM_LVL, | |
| 142 | − SORT_MEM_SNOOP, | |
| 143 | 141 | |
| 144 | 142 | /* branch stack specific sort keys */ |
| 145 | 143 | __SORT_BRANCH_STACK, |
| @@ -148,6 +146,17 @@ enum sort_type { · 2 unmodified lines | ||
| 148 | 146 | SORT_SYM_FROM, |
| 149 | 147 | SORT_SYM_TO, |
| 150 | 148 | SORT_MISPREDICT, |
| 149 | + | |
| 150 | + /* memory mode specific sort keys */ | |
| 151 | + __SORT_MEMORY_MODE, | |
| 152 | + SORT_LOCAL_WEIGHT = __SORT_MEMORY_MODE, | |
| 153 | + SORT_GLOBAL_WEIGHT, | |
| 154 | + SORT_MEM_DADDR_SYMBOL, | |
| 155 | + SORT_MEM_DADDR_DSO, | |
| 156 | + SORT_MEM_LOCKED, | |
| 157 | + SORT_MEM_TLB, | |
| 158 | + SORT_MEM_LVL, | |
| 159 | + SORT_MEM_SNOOP, | |
| 151 | 160 | }; |
| 152 | 161 | |
| 153 | 162 | /* |
| @@ -172,7 +181,6 @@ extern struct list_head hist_entry__sort_list; · 18 unmodified lines | ||
| 172 | 181 | |
| 173 | 182 | int setup_sorting(void); |
| 174 | 183 | extern int sort_dimension__add(const char *); |
| 175 | −void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, | |
| 176 | − const char *list_name, FILE *fp); | |
| 184 | +void sort__setup_elide(FILE *fp); | |
| 177 | 185 | |
| 178 | 186 | #endif /* __PERF_SORT_H */ |
| @@ -37,7 +37,7 @@ double stddev_stats(struct stats *stats) · 36 unmodified lines | ||
| 37 | 37 | { |
| 38 | 38 | double variance, variance_mean; |
| 39 | 39 | |
| 40 | − if (!stats->n) | |
| 40 | + if (stats->n < 2) | |
| 41 | 41 | return 0.0; |
| 42 | 42 | |
| 43 | 43 | variance = stats->M2 / (stats->n - 1); |
| @@ -14,6 +14,7 @@ struct thread *thread__new(pid_t pid) · 13 unmodified lines | ||
| 14 | 14 | if (self != NULL) { |
| 15 | 15 | map_groups__init(&self->mg); |
| 16 | 16 | self->pid = pid; |
| 17 | + self->ppid = -1; | |
| 17 | 18 | self->comm = malloc(32); |
| 18 | 19 | if (self->comm) |
| 19 | 20 | snprintf(self->comm, 32, ":%d", self->pid); |
| @@ -82,5 +83,8 @@ int thread__fork(struct thread *self, struct thread *parent) · 62 unmodified lines | ||
| 82 | 83 | for (i = 0; i < MAP__NR_TYPES; ++i) |
| 83 | 84 | if (map_groups__clone(&self->mg, &parent->mg, i) < 0) |
| 84 | 85 | return -ENOMEM; |
| 86 | + | |
| 87 | + self->ppid = parent->pid; | |
| 88 | + | |
| 85 | 89 | return 0; |
| 86 | 90 | } |
| @@ -13,6 +13,7 @@ struct thread { · 12 unmodified lines | ||
| 13 | 13 | }; |
| 14 | 14 | struct map_groups mg; |
| 15 | 15 | pid_t pid; |
| 16 | + pid_t ppid; | |
| 16 | 17 | char shortname[3]; |
| 17 | 18 | bool comm_set; |
| 18 | 19 | char *comm; |
| @@ -23,20 +23,31 @@ · 22 unmodified lines | ||
| 23 | 23 | |
| 24 | 24 | size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) |
| 25 | 25 | { |
| 26 | − float samples_per_sec = top->samples / top->delay_secs; | |
| 27 | − float ksamples_per_sec = top->kernel_samples / top->delay_secs; | |
| 28 | − float esamples_percent = (100.0 * top->exact_samples) / top->samples; | |
| 26 | + float samples_per_sec; | |
| 27 | + float ksamples_per_sec; | |
| 28 | + float esamples_percent; | |
| 29 | 29 | struct perf_record_opts *opts = &top->record_opts; |
| 30 | 30 | struct perf_target *target = &opts->target; |
| 31 | 31 | size_t ret = 0; |
| 32 | 32 | |
| 33 | + if (top->samples) { | |
| 34 | + samples_per_sec = top->samples / top->delay_secs; | |
| 35 | + ksamples_per_sec = top->kernel_samples / top->delay_secs; | |
| 36 | + esamples_percent = (100.0 * top->exact_samples) / top->samples; | |
| 37 | + } else { | |
| 38 | + samples_per_sec = ksamples_per_sec = esamples_percent = 0.0; | |
| 39 | + } | |
| 40 | + | |
| 33 | 41 | if (!perf_guest) { |
| 42 | + float ksamples_percent = 0.0; | |
| 43 | + | |
| 44 | + if (samples_per_sec) | |
| 45 | + ksamples_percent = (100.0 * ksamples_per_sec) / | |
| 46 | + samples_per_sec; | |
| 34 | 47 | ret = SNPRINTF(bf, size, |
| 35 | 48 | " PerfTop:%8.0f irqs/sec kernel:%4.1f%%" |
| 36 | 49 | " exact: %4.1f%% [", samples_per_sec, |
| 37 | − 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) / | |
| 38 | − samples_per_sec)), | |
| 39 | − esamples_percent); | |
| 50 | + ksamples_percent, esamples_percent); | |
| 40 | 51 | } else { |
| 41 | 52 | float us_samples_per_sec = top->us_samples / top->delay_secs; |
| 42 | 53 | float guest_kernel_samples_per_sec = top->guest_kernel_samples / top->delay_secs; |
| @@ -26,7 +26,6 @@ struct perf_top { · 25 unmodified lines | ||
| 26 | 26 | int print_entries, count_filter, delay_secs; |
| 27 | 27 | bool hide_kernel_symbols, hide_user_symbols, zero; |
| 28 | 28 | bool use_tui, use_stdio; |
| 29 | − bool sort_has_symbols; | |
| 30 | 29 | bool kptr_restrict_warned; |
| 31 | 30 | bool vmlinux_warned; |
| 32 | 31 | bool dump_symtab; |
| @@ -37,6 +36,7 @@ struct perf_top { · 4 unmodified lines | ||
| 37 | 36 | int realtime_prio; |
| 38 | 37 | int sym_pcnt_filter; |
| 39 | 38 | const char *sym_filter; |
| 39 | + float min_percent; | |
| 40 | 40 | }; |
| 41 | 41 | |
| 42 | 42 | size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); |
| @@ -221,8 +221,8 @@ extern unsigned char sane_ctype[256]; · 220 unmodified lines | ||
| 221 | 221 | #define isalpha(x) sane_istest(x,GIT_ALPHA) |
| 222 | 222 | #define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) |
| 223 | 223 | #define isprint(x) sane_istest(x,GIT_PRINT) |
| 224 | −#define islower(x) (sane_istest(x,GIT_ALPHA) && sane_istest(x,0x20)) | |
| 225 | −#define isupper(x) (sane_istest(x,GIT_ALPHA) && !sane_istest(x,0x20)) | |
| 224 | +#define islower(x) (sane_istest(x,GIT_ALPHA) && (x & 0x20)) | |
| 225 | +#define isupper(x) (sane_istest(x,GIT_ALPHA) && !(x & 0x20)) | |
| 226 | 226 | #define tolower(x) sane_case((unsigned char)(x), 0x20) |
| 227 | 227 | #define toupper(x) sane_case((unsigned char)(x), 0) |
| 228 | 228 | |