diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-03 15:40:46 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-03 15:40:46 -0400 |
| commit | 7447d56217e215e50317f308aee1ed293ac4f749 (patch) | |
| tree | 903832ecb206ae83160992c6aec40c624821941f /tools/perf | |
| parent | 892ad5acca0b2ddb514fae63fa4686bf726d2471 (diff) | |
| parent | 23acd3e1a0a377cf3730ccb753aa1fdc50378396 (diff) | |
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar:
"Most of the changes are for tooling, the main changes in this cycle were:
- Improve Intel-PT hardware tracing support, both on the kernel and
on the tooling side: PTWRITE instruction support, power events for
C-state tracing, etc. (Adrian Hunter)
- Add support to measure SMI cost to the x86 architecture, with
tooling support in 'perf stat' (Kan Liang)
- Support function filtering in 'perf ftrace', plus related
improvements (Namhyung Kim)
- Allow adding and removing fields to the default 'perf script'
columns, using + or - as field prefixes to do so (Andi Kleen)
- Allow resolving the DSO name with 'perf script -F brstack{sym,off},dso'
(Mark Santaniello)
- Add perf tooling unwind support for PowerPC (Paolo Bonzini)
- ... and various other improvements as well"
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (84 commits)
perf auxtrace: Add CPU filter support
perf intel-pt: Do not use TSC packets for calculating CPU cycles to TSC
perf intel-pt: Update documentation to include new ptwrite and power events
perf intel-pt: Add example script for power events and PTWRITE
perf intel-pt: Synthesize new power and "ptwrite" events
perf intel-pt: Move code in intel_pt_synth_events() to simplify attr setting
perf intel-pt: Factor out intel_pt_set_event_name()
perf intel-pt: Tidy messages into called function intel_pt_synth_event()
perf intel-pt: Tidy Intel PT evsel lookup into separate function
perf intel-pt: Join needlessly wrapped lines
perf intel-pt: Remove unused instructions_sample_period
perf intel-pt: Factor out common code synthesizing event samples
perf script: Add synthesized Intel PT power and ptwrite events
perf/x86/intel: Constify the 'lbr_desc[]' array and make a function static
perf script: Add 'synth' field for synthesized event payloads
perf auxtrace: Add itrace option to output power events
perf auxtrace: Add itrace option to output ptwrite events
tools include: Add byte-swapping macros to kernel.h
perf script: Add 'synth' event type for synthesized events
x86/insn: perf tools: Add new ptwrite instruction
...
Diffstat (limited to 'tools/perf')
79 files changed, 2350 insertions, 600 deletions
diff --git a/tools/perf/Documentation/intel-pt.txt b/tools/perf/Documentation/intel-pt.txt index b0b3007d3c9c..4b6cdbf8f935 100644 --- a/tools/perf/Documentation/intel-pt.txt +++ b/tools/perf/Documentation/intel-pt.txt | |||
| @@ -108,6 +108,9 @@ approach is available to export the data to a postgresql database. Refer to | |||
| 108 | script export-to-postgresql.py for more details, and to script | 108 | script export-to-postgresql.py for more details, and to script |
| 109 | call-graph-from-postgresql.py for an example of using the database. | 109 | call-graph-from-postgresql.py for an example of using the database. |
| 110 | 110 | ||
| 111 | There is also script intel-pt-events.py which provides an example of how to | ||
| 112 | unpack the raw data for power events and PTWRITE. | ||
| 113 | |||
| 111 | As mentioned above, it is easy to capture too much data. One way to limit the | 114 | As mentioned above, it is easy to capture too much data. One way to limit the |
| 112 | data captured is to use 'snapshot' mode which is explained further below. | 115 | data captured is to use 'snapshot' mode which is explained further below. |
| 113 | Refer to 'new snapshot option' and 'Intel PT modes of operation' further below. | 116 | Refer to 'new snapshot option' and 'Intel PT modes of operation' further below. |
| @@ -364,6 +367,42 @@ cyc_thresh Specifies how frequently CYC packets are produced - see cyc | |||
| 364 | 367 | ||
| 365 | CYC packets are not requested by default. | 368 | CYC packets are not requested by default. |
| 366 | 369 | ||
| 370 | pt Specifies pass-through which enables the 'branch' config term. | ||
| 371 | |||
| 372 | The default config selects 'pt' if it is available, so a user will | ||
| 373 | never need to specify this term. | ||
| 374 | |||
| 375 | branch Enable branch tracing. Branch tracing is enabled by default so to | ||
| 376 | disable branch tracing use 'branch=0'. | ||
| 377 | |||
| 378 | The default config selects 'branch' if it is available. | ||
| 379 | |||
| 380 | ptw Enable PTWRITE packets which are produced when a ptwrite instruction | ||
| 381 | is executed. | ||
| 382 | |||
| 383 | Support for this feature is indicated by: | ||
| 384 | |||
| 385 | /sys/bus/event_source/devices/intel_pt/caps/ptwrite | ||
| 386 | |||
| 387 | which contains "1" if the feature is supported and | ||
| 388 | "0" otherwise. | ||
| 389 | |||
| 390 | fup_on_ptw Enable a FUP packet to follow the PTWRITE packet. The FUP packet | ||
| 391 | provides the address of the ptwrite instruction. In the absence of | ||
| 392 | fup_on_ptw, the decoder will use the address of the previous branch | ||
| 393 | if branch tracing is enabled, otherwise the address will be zero. | ||
| 394 | Note that fup_on_ptw will work even when branch tracing is disabled. | ||
| 395 | |||
| 396 | pwr_evt Enable power events. The power events provide information about | ||
| 397 | changes to the CPU C-state. | ||
| 398 | |||
| 399 | Support for this feature is indicated by: | ||
| 400 | |||
| 401 | /sys/bus/event_source/devices/intel_pt/caps/power_event_trace | ||
| 402 | |||
| 403 | which contains "1" if the feature is supported and | ||
| 404 | "0" otherwise. | ||
| 405 | |||
| 367 | 406 | ||
| 368 | new snapshot option | 407 | new snapshot option |
| 369 | ------------------- | 408 | ------------------- |
| @@ -674,13 +713,15 @@ Having no option is the same as | |||
| 674 | 713 | ||
| 675 | which, in turn, is the same as | 714 | which, in turn, is the same as |
| 676 | 715 | ||
| 677 | --itrace=ibxe | 716 | --itrace=ibxwpe |
| 678 | 717 | ||
| 679 | The letters are: | 718 | The letters are: |
| 680 | 719 | ||
| 681 | i synthesize "instructions" events | 720 | i synthesize "instructions" events |
| 682 | b synthesize "branches" events | 721 | b synthesize "branches" events |
| 683 | x synthesize "transactions" events | 722 | x synthesize "transactions" events |
| 723 | w synthesize "ptwrite" events | ||
| 724 | p synthesize "power" events | ||
| 684 | c synthesize branches events (calls only) | 725 | c synthesize branches events (calls only) |
| 685 | r synthesize branches events (returns only) | 726 | r synthesize branches events (returns only) |
| 686 | e synthesize tracing error events | 727 | e synthesize tracing error events |
| @@ -699,7 +740,40 @@ and "r" can be combined to get calls and returns. | |||
| 699 | 'flags' field can be used in perf script to determine whether the event is a | 740 | 'flags' field can be used in perf script to determine whether the event is a |
| 700 | tranasaction start, commit or abort. | 741 | tranasaction start, commit or abort. |
| 701 | 742 | ||
| 702 | Error events are new. They show where the decoder lost the trace. Error events | 743 | Note that "instructions", "branches" and "transactions" events depend on code |
| 744 | flow packets which can be disabled by using the config term "branch=0". Refer | ||
| 745 | to the config terms section above. | ||
| 746 | |||
| 747 | "ptwrite" events record the payload of the ptwrite instruction and whether | ||
| 748 | "fup_on_ptw" was used. "ptwrite" events depend on PTWRITE packets which are | ||
| 749 | recorded only if the "ptw" config term was used. Refer to the config terms | ||
| 750 | section above. perf script "synth" field displays "ptwrite" information like | ||
| 751 | this: "ip: 0 payload: 0x123456789abcdef0" where "ip" is 1 if "fup_on_ptw" was | ||
| 752 | used. | ||
| 753 | |||
| 754 | "Power" events correspond to power event packets and CBR (core-to-bus ratio) | ||
| 755 | packets. While CBR packets are always recorded when tracing is enabled, power | ||
| 756 | event packets are recorded only if the "pwr_evt" config term was used. Refer to | ||
| 757 | the config terms section above. The power events record information about | ||
| 758 | C-state changes, whereas CBR is indicative of CPU frequency. perf script | ||
| 759 | "event,synth" fields display information like this: | ||
| 760 | cbr: cbr: 22 freq: 2189 MHz (200%) | ||
| 761 | mwait: hints: 0x60 extensions: 0x1 | ||
| 762 | pwre: hw: 0 cstate: 2 sub-cstate: 0 | ||
| 763 | exstop: ip: 1 | ||
| 764 | pwrx: deepest cstate: 2 last cstate: 2 wake reason: 0x4 | ||
| 765 | Where: | ||
| 766 | "cbr" includes the frequency and the percentage of maximum non-turbo | ||
| 767 | "mwait" shows mwait hints and extensions | ||
| 768 | "pwre" shows C-state transitions (to a C-state deeper than C0) and | ||
| 769 | whether initiated by hardware | ||
| 770 | "exstop" indicates execution stopped and whether the IP was recorded | ||
| 771 | exactly, | ||
| 772 | "pwrx" indicates return to C0 | ||
| 773 | For more details refer to the Intel 64 and IA-32 Architectures Software | ||
| 774 | Developer Manuals. | ||
| 775 | |||
| 776 | Error events show where the decoder lost the trace. Error events | ||
| 703 | are quite important. Users must know if what they are seeing is a complete | 777 | are quite important. Users must know if what they are seeing is a complete |
| 704 | picture or not. | 778 | picture or not. |
| 705 | 779 | ||
diff --git a/tools/perf/Documentation/itrace.txt b/tools/perf/Documentation/itrace.txt index e2a4c5e0dbe5..a3abe04c779d 100644 --- a/tools/perf/Documentation/itrace.txt +++ b/tools/perf/Documentation/itrace.txt | |||
| @@ -3,13 +3,15 @@ | |||
| 3 | c synthesize branches events (calls only) | 3 | c synthesize branches events (calls only) |
| 4 | r synthesize branches events (returns only) | 4 | r synthesize branches events (returns only) |
| 5 | x synthesize transactions events | 5 | x synthesize transactions events |
| 6 | w synthesize ptwrite events | ||
| 7 | p synthesize power events | ||
| 6 | e synthesize error events | 8 | e synthesize error events |
| 7 | d create a debug log | 9 | d create a debug log |
| 8 | g synthesize a call chain (use with i or x) | 10 | g synthesize a call chain (use with i or x) |
| 9 | l synthesize last branch entries (use with i or x) | 11 | l synthesize last branch entries (use with i or x) |
| 10 | s skip initial number of events | 12 | s skip initial number of events |
| 11 | 13 | ||
| 12 | The default is all events i.e. the same as --itrace=ibxe | 14 | The default is all events i.e. the same as --itrace=ibxwpe |
| 13 | 15 | ||
| 14 | In addition, the period (default 100000) for instructions events | 16 | In addition, the period (default 100000) for instructions events |
| 15 | can be specified in units of: | 17 | can be specified in units of: |
| @@ -26,8 +28,8 @@ | |||
| 26 | Also the number of last branch entries (default 64, max. 1024) for | 28 | Also the number of last branch entries (default 64, max. 1024) for |
| 27 | instructions or transactions events can be specified. | 29 | instructions or transactions events can be specified. |
| 28 | 30 | ||
| 29 | It is also possible to skip events generated (instructions, branches, transactions) | 31 | It is also possible to skip events generated (instructions, branches, transactions, |
| 30 | at the beginning. This is useful to ignore initialization code. | 32 | ptwrite, power) at the beginning. This is useful to ignore initialization code. |
| 31 | 33 | ||
| 32 | --itrace=i0nss1000000 | 34 | --itrace=i0nss1000000 |
| 33 | 35 | ||
diff --git a/tools/perf/Documentation/perf-ftrace.txt b/tools/perf/Documentation/perf-ftrace.txt index 6e6a8b22c859..721a447f046e 100644 --- a/tools/perf/Documentation/perf-ftrace.txt +++ b/tools/perf/Documentation/perf-ftrace.txt | |||
| @@ -48,6 +48,39 @@ OPTIONS | |||
| 48 | Ranges of CPUs are specified with -: 0-2. | 48 | Ranges of CPUs are specified with -: 0-2. |
| 49 | Default is to trace on all online CPUs. | 49 | Default is to trace on all online CPUs. |
| 50 | 50 | ||
| 51 | -T:: | ||
| 52 | --trace-funcs=:: | ||
| 53 | Only trace functions given by the argument. Multiple functions | ||
| 54 | can be given by using this option more than once. The function | ||
| 55 | argument also can be a glob pattern. It will be passed to | ||
| 56 | 'set_ftrace_filter' in tracefs. | ||
| 57 | |||
| 58 | -N:: | ||
| 59 | --notrace-funcs=:: | ||
| 60 | Do not trace functions given by the argument. Like -T option, | ||
| 61 | this can be used more than once to specify multiple functions | ||
| 62 | (or glob patterns). It will be passed to 'set_ftrace_notrace' | ||
| 63 | in tracefs. | ||
| 64 | |||
| 65 | -G:: | ||
| 66 | --graph-funcs=:: | ||
| 67 | Set graph filter on the given function (or a glob pattern). | ||
| 68 | This is useful for the function_graph tracer only and enables | ||
| 69 | tracing for functions executed from the given function. | ||
| 70 | This can be used more than once to specify multiple functions. | ||
| 71 | It will be passed to 'set_graph_function' in tracefs. | ||
| 72 | |||
| 73 | -g:: | ||
| 74 | --nograph-funcs=:: | ||
| 75 | Set graph notrace filter on the given function (or a glob pattern). | ||
| 76 | Like -G option, this is useful for the function_graph tracer only | ||
| 77 | and disables tracing for function executed from the given function. | ||
| 78 | This can be used more than once to specify multiple functions. | ||
| 79 | It will be passed to 'set_graph_notrace' in tracefs. | ||
| 80 | |||
| 81 | -D:: | ||
| 82 | --graph-depth=:: | ||
| 83 | Set max depth for function graph tracer to follow | ||
| 51 | 84 | ||
| 52 | SEE ALSO | 85 | SEE ALSO |
| 53 | -------- | 86 | -------- |
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index 3517e204a2b3..5ee8796be96e 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt | |||
| @@ -116,8 +116,9 @@ OPTIONS | |||
| 116 | --fields:: | 116 | --fields:: |
| 117 | Comma separated list of fields to print. Options are: | 117 | Comma separated list of fields to print. Options are: |
| 118 | comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff, | 118 | comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff, |
| 119 | srcline, period, iregs, brstack, brstacksym, flags, bpf-output, brstackinsn, | 119 | srcline, period, iregs, brstack, brstacksym, flags, bpf-output, brstackinsn, brstackoff, |
| 120 | callindent, insn, insnlen. Field list can be prepended with the type, trace, sw or hw, | 120 | callindent, insn, insnlen, synth. |
| 121 | Field list can be prepended with the type, trace, sw or hw, | ||
| 121 | to indicate to which event type the field list applies. | 122 | to indicate to which event type the field list applies. |
| 122 | e.g., -F sw:comm,tid,time,ip,sym and -F trace:time,cpu,trace | 123 | e.g., -F sw:comm,tid,time,ip,sym and -F trace:time,cpu,trace |
| 123 | 124 | ||
| @@ -130,6 +131,14 @@ OPTIONS | |||
| 130 | i.e., the specified fields apply to all event types if the type string | 131 | i.e., the specified fields apply to all event types if the type string |
| 131 | is not given. | 132 | is not given. |
| 132 | 133 | ||
| 134 | In addition to overriding fields, it is also possible to add or remove | ||
| 135 | fields from the defaults. For example | ||
| 136 | |||
| 137 | -F -cpu,+insn | ||
| 138 | |||
| 139 | removes the cpu field and adds the insn field. Adding/removing fields | ||
| 140 | cannot be mixed with normal overriding. | ||
| 141 | |||
| 133 | The arguments are processed in the order received. A later usage can | 142 | The arguments are processed in the order received. A later usage can |
| 134 | reset a prior request. e.g.: | 143 | reset a prior request. e.g.: |
| 135 | 144 | ||
| @@ -185,6 +194,9 @@ OPTIONS | |||
| 185 | instruction bytes and the instruction length of the current | 194 | instruction bytes and the instruction length of the current |
| 186 | instruction. | 195 | instruction. |
| 187 | 196 | ||
| 197 | The synth field is used by synthesized events which may be created when | ||
| 198 | Instruction Trace decoding. | ||
| 199 | |||
| 188 | Finally, a user may not set fields to none for all event types. | 200 | Finally, a user may not set fields to none for all event types. |
| 189 | i.e., -F "" is not allowed. | 201 | i.e., -F "" is not allowed. |
| 190 | 202 | ||
| @@ -203,6 +215,8 @@ OPTIONS | |||
| 203 | is printed. This is the full execution path leading to the sample. This is only supported when the | 215 | is printed. This is the full execution path leading to the sample. This is only supported when the |
| 204 | sample was recorded with perf record -b or -j any. | 216 | sample was recorded with perf record -b or -j any. |
| 205 | 217 | ||
| 218 | The brstackoff field will print an offset into a specific dso/binary. | ||
| 219 | |||
| 206 | -k:: | 220 | -k:: |
| 207 | --vmlinux=<file>:: | 221 | --vmlinux=<file>:: |
| 208 | vmlinux pathname | 222 | vmlinux pathname |
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index bd0e4417f2be..698076313606 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt | |||
| @@ -239,6 +239,20 @@ taskset. | |||
| 239 | --no-merge:: | 239 | --no-merge:: |
| 240 | Do not merge results from same PMUs. | 240 | Do not merge results from same PMUs. |
| 241 | 241 | ||
| 242 | --smi-cost:: | ||
| 243 | Measure SMI cost if msr/aperf/ and msr/smi/ events are supported. | ||
| 244 | |||
| 245 | During the measurement, the /sys/device/cpu/freeze_on_smi will be set to | ||
| 246 | freeze core counters on SMI. | ||
| 247 | The aperf counter will not be effected by the setting. | ||
| 248 | The cost of SMI can be measured by (aperf - unhalted core cycles). | ||
| 249 | |||
| 250 | In practice, the percentages of SMI cycles is very useful for performance | ||
| 251 | oriented analysis. --metric_only will be applied by default. | ||
| 252 | The output is SMI cycles%, equals to (aperf - unhalted core cycles) / aperf | ||
| 253 | |||
| 254 | Users who wants to get the actual value can apply --no-metric-only. | ||
| 255 | |||
| 242 | EXAMPLES | 256 | EXAMPLES |
| 243 | -------- | 257 | -------- |
| 244 | 258 | ||
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 1f4fbc9a3292..bdf0e87f9b29 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config | |||
| @@ -61,7 +61,7 @@ endif | |||
| 61 | # Disable it on all other architectures in case libdw unwind | 61 | # Disable it on all other architectures in case libdw unwind |
| 62 | # support is detected in system. Add supported architectures | 62 | # support is detected in system. Add supported architectures |
| 63 | # to the check. | 63 | # to the check. |
| 64 | ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm)) | 64 | ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc)) |
| 65 | NO_LIBDW_DWARF_UNWIND := 1 | 65 | NO_LIBDW_DWARF_UNWIND := 1 |
| 66 | endif | 66 | endif |
| 67 | 67 | ||
diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index 29361d9b635a..7ce3d1a25133 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | 17 | ||
| 18 | #include <api/fs/fs.h> | 18 | #include <api/fs/fs.h> |
| 19 | #include <linux/bitops.h> | 19 | #include <linux/bitops.h> |
| 20 | #include <linux/compiler.h> | ||
| 20 | #include <linux/coresight-pmu.h> | 21 | #include <linux/coresight-pmu.h> |
| 21 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
| 22 | #include <linux/log2.h> | 23 | #include <linux/log2.h> |
| @@ -202,19 +203,18 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, | |||
| 202 | pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME, | 203 | pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME, |
| 203 | opts->auxtrace_snapshot_size); | 204 | opts->auxtrace_snapshot_size); |
| 204 | 205 | ||
| 205 | if (cs_etm_evsel) { | 206 | /* |
| 206 | /* | 207 | * To obtain the auxtrace buffer file descriptor, the auxtrace |
| 207 | * To obtain the auxtrace buffer file descriptor, the auxtrace | 208 | * event must come first. |
| 208 | * event must come first. | 209 | */ |
| 209 | */ | 210 | perf_evlist__to_front(evlist, cs_etm_evsel); |
| 210 | perf_evlist__to_front(evlist, cs_etm_evsel); | 211 | |
| 211 | /* | 212 | /* |
| 212 | * In the case of per-cpu mmaps, we need the CPU on the | 213 | * In the case of per-cpu mmaps, we need the CPU on the |
| 213 | * AUX event. | 214 | * AUX event. |
| 214 | */ | 215 | */ |
| 215 | if (!cpu_map__empty(cpus)) | 216 | if (!cpu_map__empty(cpus)) |
| 216 | perf_evsel__set_sample_bit(cs_etm_evsel, CPU); | 217 | perf_evsel__set_sample_bit(cs_etm_evsel, CPU); |
| 217 | } | ||
| 218 | 218 | ||
| 219 | /* Add dummy event to keep tracking */ | 219 | /* Add dummy event to keep tracking */ |
| 220 | if (opts->full_auxtrace) { | 220 | if (opts->full_auxtrace) { |
| @@ -583,8 +583,7 @@ static FILE *cs_device__open_file(const char *name) | |||
| 583 | 583 | ||
| 584 | } | 584 | } |
| 585 | 585 | ||
| 586 | static __attribute__((format(printf, 2, 3))) | 586 | static int __printf(2, 3) cs_device__print_file(const char *name, const char *fmt, ...) |
| 587 | int cs_device__print_file(const char *name, const char *fmt, ...) | ||
| 588 | { | 587 | { |
| 589 | va_list args; | 588 | va_list args; |
| 590 | FILE *file; | 589 | FILE *file; |
diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build index 90ad64b231cd..2e6595310420 100644 --- a/tools/perf/arch/powerpc/util/Build +++ b/tools/perf/arch/powerpc/util/Build | |||
| @@ -5,4 +5,6 @@ libperf-y += perf_regs.o | |||
| 5 | 5 | ||
| 6 | libperf-$(CONFIG_DWARF) += dwarf-regs.o | 6 | libperf-$(CONFIG_DWARF) += dwarf-regs.o |
| 7 | libperf-$(CONFIG_DWARF) += skip-callchain-idx.o | 7 | libperf-$(CONFIG_DWARF) += skip-callchain-idx.o |
| 8 | |||
| 8 | libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o | 9 | libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o |
| 10 | libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o | ||
diff --git a/tools/perf/arch/powerpc/util/unwind-libdw.c b/tools/perf/arch/powerpc/util/unwind-libdw.c new file mode 100644 index 000000000000..3a24b3c43273 --- /dev/null +++ b/tools/perf/arch/powerpc/util/unwind-libdw.c | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | #include <elfutils/libdwfl.h> | ||
| 2 | #include "../../util/unwind-libdw.h" | ||
| 3 | #include "../../util/perf_regs.h" | ||
| 4 | #include "../../util/event.h" | ||
| 5 | |||
| 6 | /* See backends/ppc_initreg.c and backends/ppc_regs.c in elfutils. */ | ||
| 7 | static const int special_regs[3][2] = { | ||
| 8 | { 65, PERF_REG_POWERPC_LINK }, | ||
| 9 | { 101, PERF_REG_POWERPC_XER }, | ||
| 10 | { 109, PERF_REG_POWERPC_CTR }, | ||
| 11 | }; | ||
| 12 | |||
| 13 | bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg) | ||
| 14 | { | ||
| 15 | struct unwind_info *ui = arg; | ||
| 16 | struct regs_dump *user_regs = &ui->sample->user_regs; | ||
| 17 | Dwarf_Word dwarf_regs[32], dwarf_nip; | ||
| 18 | size_t i; | ||
| 19 | |||
| 20 | #define REG(r) ({ \ | ||
| 21 | Dwarf_Word val = 0; \ | ||
| 22 | perf_reg_value(&val, user_regs, PERF_REG_POWERPC_##r); \ | ||
| 23 | val; \ | ||
| 24 | }) | ||
| 25 | |||
| 26 | dwarf_regs[0] = REG(R0); | ||
| 27 | dwarf_regs[1] = REG(R1); | ||
| 28 | dwarf_regs[2] = REG(R2); | ||
| 29 | dwarf_regs[3] = REG(R3); | ||
| 30 | dwarf_regs[4] = REG(R4); | ||
| 31 | dwarf_regs[5] = REG(R5); | ||
| 32 | dwarf_regs[6] = REG(R6); | ||
| 33 | dwarf_regs[7] = REG(R7); | ||
| 34 | dwarf_regs[8] = REG(R8); | ||
| 35 | dwarf_regs[9] = REG(R9); | ||
| 36 | dwarf_regs[10] = REG(R10); | ||
| 37 | dwarf_regs[11] = REG(R11); | ||
| 38 | dwarf_regs[12] = REG(R12); | ||
| 39 | dwarf_regs[13] = REG(R13); | ||
| 40 | dwarf_regs[14] = REG(R14); | ||
| 41 | dwarf_regs[15] = REG(R15); | ||
| 42 | dwarf_regs[16] = REG(R16); | ||
| 43 | dwarf_regs[17] = REG(R17); | ||
| 44 | dwarf_regs[18] = REG(R18); | ||
| 45 | dwarf_regs[19] = REG(R19); | ||
| 46 | dwarf_regs[20] = REG(R20); | ||
| 47 | dwarf_regs[21] = REG(R21); | ||
| 48 | dwarf_regs[22] = REG(R22); | ||
| 49 | dwarf_regs[23] = REG(R23); | ||
| 50 | dwarf_regs[24] = REG(R24); | ||
| 51 | dwarf_regs[25] = REG(R25); | ||
| 52 | dwarf_regs[26] = REG(R26); | ||
| 53 | dwarf_regs[27] = REG(R27); | ||
| 54 | dwarf_regs[28] = REG(R28); | ||
| 55 | dwarf_regs[29] = REG(R29); | ||
| 56 | dwarf_regs[30] = REG(R30); | ||
| 57 | dwarf_regs[31] = REG(R31); | ||
| 58 | if (!dwfl_thread_state_registers(thread, 0, 32, dwarf_regs)) | ||
| 59 | return false; | ||
| 60 | |||
| 61 | dwarf_nip = REG(NIP); | ||
| 62 | dwfl_thread_state_register_pc(thread, dwarf_nip); | ||
| 63 | for (i = 0; i < ARRAY_SIZE(special_regs); i++) { | ||
| 64 | Dwarf_Word val = 0; | ||
| 65 | perf_reg_value(&val, user_regs, special_regs[i][1]); | ||
| 66 | if (!dwfl_thread_state_registers(thread, | ||
| 67 | special_regs[i][0], 1, | ||
| 68 | &val)) | ||
| 69 | return false; | ||
| 70 | } | ||
| 71 | |||
| 72 | return true; | ||
| 73 | } | ||
diff --git a/tools/perf/arch/x86/tests/insn-x86-dat-32.c b/tools/perf/arch/x86/tests/insn-x86-dat-32.c index 0f196eec9f48..3cbf6fad169f 100644 --- a/tools/perf/arch/x86/tests/insn-x86-dat-32.c +++ b/tools/perf/arch/x86/tests/insn-x86-dat-32.c | |||
| @@ -1664,3 +1664,15 @@ | |||
| 1664 | "0f c7 1d 78 56 34 12 \txrstors 0x12345678",}, | 1664 | "0f c7 1d 78 56 34 12 \txrstors 0x12345678",}, |
| 1665 | {{0x0f, 0xc7, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", | 1665 | {{0x0f, 0xc7, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", |
| 1666 | "0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%eax,%ecx,8)",}, | 1666 | "0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%eax,%ecx,8)",}, |
| 1667 | {{0xf3, 0x0f, 0xae, 0x20, }, 4, 0, "", "", | ||
| 1668 | "f3 0f ae 20 \tptwritel (%eax)",}, | ||
| 1669 | {{0xf3, 0x0f, 0xae, 0x25, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", | ||
| 1670 | "f3 0f ae 25 78 56 34 12 \tptwritel 0x12345678",}, | ||
| 1671 | {{0xf3, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", | ||
| 1672 | "f3 0f ae a4 c8 78 56 34 12 \tptwritel 0x12345678(%eax,%ecx,8)",}, | ||
| 1673 | {{0xf3, 0x0f, 0xae, 0x20, }, 4, 0, "", "", | ||
| 1674 | "f3 0f ae 20 \tptwritel (%eax)",}, | ||
| 1675 | {{0xf3, 0x0f, 0xae, 0x25, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", | ||
| 1676 | "f3 0f ae 25 78 56 34 12 \tptwritel 0x12345678",}, | ||
| 1677 | {{0xf3, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", | ||
| 1678 | "f3 0f ae a4 c8 78 56 34 12 \tptwritel 0x12345678(%eax,%ecx,8)",}, | ||
diff --git a/tools/perf/arch/x86/tests/insn-x86-dat-64.c b/tools/perf/arch/x86/tests/insn-x86-dat-64.c index af25bc8240d0..aa512fa944dd 100644 --- a/tools/perf/arch/x86/tests/insn-x86-dat-64.c +++ b/tools/perf/arch/x86/tests/insn-x86-dat-64.c | |||
| @@ -1696,3 +1696,33 @@ | |||
| 1696 | "0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%rax,%rcx,8)",}, | 1696 | "0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%rax,%rcx,8)",}, |
| 1697 | {{0x41, 0x0f, 0xc7, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", | 1697 | {{0x41, 0x0f, 0xc7, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", |
| 1698 | "41 0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%r8,%rcx,8)",}, | 1698 | "41 0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%r8,%rcx,8)",}, |
| 1699 | {{0xf3, 0x0f, 0xae, 0x20, }, 4, 0, "", "", | ||
| 1700 | "f3 0f ae 20 \tptwritel (%rax)",}, | ||
| 1701 | {{0xf3, 0x41, 0x0f, 0xae, 0x20, }, 5, 0, "", "", | ||
| 1702 | "f3 41 0f ae 20 \tptwritel (%r8)",}, | ||
| 1703 | {{0xf3, 0x0f, 0xae, 0x24, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", | ||
| 1704 | "f3 0f ae 24 25 78 56 34 12 \tptwritel 0x12345678",}, | ||
| 1705 | {{0xf3, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", | ||
| 1706 | "f3 0f ae a4 c8 78 56 34 12 \tptwritel 0x12345678(%rax,%rcx,8)",}, | ||
| 1707 | {{0xf3, 0x41, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", | ||
| 1708 | "f3 41 0f ae a4 c8 78 56 34 12 \tptwritel 0x12345678(%r8,%rcx,8)",}, | ||
| 1709 | {{0xf3, 0x0f, 0xae, 0x20, }, 4, 0, "", "", | ||
| 1710 | "f3 0f ae 20 \tptwritel (%rax)",}, | ||
| 1711 | {{0xf3, 0x41, 0x0f, 0xae, 0x20, }, 5, 0, "", "", | ||
| 1712 | "f3 41 0f ae 20 \tptwritel (%r8)",}, | ||
| 1713 | {{0xf3, 0x0f, 0xae, 0x24, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", | ||
| 1714 | "f3 0f ae 24 25 78 56 34 12 \tptwritel 0x12345678",}, | ||
| 1715 | {{0xf3, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", | ||
| 1716 | "f3 0f ae a4 c8 78 56 34 12 \tptwritel 0x12345678(%rax,%rcx,8)",}, | ||
| 1717 | {{0xf3, 0x41, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", | ||
| 1718 | "f3 41 0f ae a4 c8 78 56 34 12 \tptwritel 0x12345678(%r8,%rcx,8)",}, | ||
| 1719 | {{0xf3, 0x48, 0x0f, 0xae, 0x20, }, 5, 0, "", "", | ||
| 1720 | "f3 48 0f ae 20 \tptwriteq (%rax)",}, | ||
| 1721 | {{0xf3, 0x49, 0x0f, 0xae, 0x20, }, 5, 0, "", "", | ||
| 1722 | "f3 49 0f ae 20 \tptwriteq (%r8)",}, | ||
| 1723 | {{0xf3, 0x48, 0x0f, 0xae, 0x24, 0x25, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", | ||
| 1724 | "f3 48 0f ae 24 25 78 56 34 12 \tptwriteq 0x12345678",}, | ||
| 1725 | {{0xf3, 0x48, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", | ||
| 1726 | "f3 48 0f ae a4 c8 78 56 34 12 \tptwriteq 0x12345678(%rax,%rcx,8)",}, | ||
| 1727 | {{0xf3, 0x49, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", | ||
| 1728 | "f3 49 0f ae a4 c8 78 56 34 12 \tptwriteq 0x12345678(%r8,%rcx,8)",}, | ||
diff --git a/tools/perf/arch/x86/tests/insn-x86-dat-src.c b/tools/perf/arch/x86/tests/insn-x86-dat-src.c index 979487dae8d4..6cdb65d25b79 100644 --- a/tools/perf/arch/x86/tests/insn-x86-dat-src.c +++ b/tools/perf/arch/x86/tests/insn-x86-dat-src.c | |||
| @@ -1343,6 +1343,26 @@ int main(void) | |||
| 1343 | asm volatile("xrstors 0x12345678(%rax,%rcx,8)"); | 1343 | asm volatile("xrstors 0x12345678(%rax,%rcx,8)"); |
| 1344 | asm volatile("xrstors 0x12345678(%r8,%rcx,8)"); | 1344 | asm volatile("xrstors 0x12345678(%r8,%rcx,8)"); |
| 1345 | 1345 | ||
| 1346 | /* ptwrite */ | ||
| 1347 | |||
| 1348 | asm volatile("ptwrite (%rax)"); | ||
| 1349 | asm volatile("ptwrite (%r8)"); | ||
| 1350 | asm volatile("ptwrite (0x12345678)"); | ||
| 1351 | asm volatile("ptwrite 0x12345678(%rax,%rcx,8)"); | ||
| 1352 | asm volatile("ptwrite 0x12345678(%r8,%rcx,8)"); | ||
| 1353 | |||
| 1354 | asm volatile("ptwritel (%rax)"); | ||
| 1355 | asm volatile("ptwritel (%r8)"); | ||
| 1356 | asm volatile("ptwritel (0x12345678)"); | ||
| 1357 | asm volatile("ptwritel 0x12345678(%rax,%rcx,8)"); | ||
| 1358 | asm volatile("ptwritel 0x12345678(%r8,%rcx,8)"); | ||
| 1359 | |||
| 1360 | asm volatile("ptwriteq (%rax)"); | ||
| 1361 | asm volatile("ptwriteq (%r8)"); | ||
| 1362 | asm volatile("ptwriteq (0x12345678)"); | ||
| 1363 | asm volatile("ptwriteq 0x12345678(%rax,%rcx,8)"); | ||
| 1364 | asm volatile("ptwriteq 0x12345678(%r8,%rcx,8)"); | ||
| 1365 | |||
| 1346 | #else /* #ifdef __x86_64__ */ | 1366 | #else /* #ifdef __x86_64__ */ |
| 1347 | 1367 | ||
| 1348 | /* bound r32, mem (same op code as EVEX prefix) */ | 1368 | /* bound r32, mem (same op code as EVEX prefix) */ |
| @@ -2653,6 +2673,16 @@ int main(void) | |||
| 2653 | asm volatile("xrstors (0x12345678)"); | 2673 | asm volatile("xrstors (0x12345678)"); |
| 2654 | asm volatile("xrstors 0x12345678(%eax,%ecx,8)"); | 2674 | asm volatile("xrstors 0x12345678(%eax,%ecx,8)"); |
| 2655 | 2675 | ||
| 2676 | /* ptwrite */ | ||
| 2677 | |||
| 2678 | asm volatile("ptwrite (%eax)"); | ||
| 2679 | asm volatile("ptwrite (0x12345678)"); | ||
| 2680 | asm volatile("ptwrite 0x12345678(%eax,%ecx,8)"); | ||
| 2681 | |||
| 2682 | asm volatile("ptwritel (%eax)"); | ||
| 2683 | asm volatile("ptwritel (0x12345678)"); | ||
| 2684 | asm volatile("ptwritel 0x12345678(%eax,%ecx,8)"); | ||
| 2685 | |||
| 2656 | #endif /* #ifndef __x86_64__ */ | 2686 | #endif /* #ifndef __x86_64__ */ |
| 2657 | 2687 | ||
| 2658 | /* Following line is a marker for the awk script - do not change */ | 2688 | /* Following line is a marker for the awk script - do not change */ |
diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c index af2bce7a2cd6..781df40b2966 100644 --- a/tools/perf/arch/x86/util/intel-bts.c +++ b/tools/perf/arch/x86/util/intel-bts.c | |||
| @@ -35,10 +35,6 @@ | |||
| 35 | #define KiB_MASK(x) (KiB(x) - 1) | 35 | #define KiB_MASK(x) (KiB(x) - 1) |
| 36 | #define MiB_MASK(x) (MiB(x) - 1) | 36 | #define MiB_MASK(x) (MiB(x) - 1) |
| 37 | 37 | ||
| 38 | #define INTEL_BTS_DFLT_SAMPLE_SIZE KiB(4) | ||
| 39 | |||
| 40 | #define INTEL_BTS_MAX_SAMPLE_SIZE KiB(60) | ||
| 41 | |||
| 42 | struct intel_bts_snapshot_ref { | 38 | struct intel_bts_snapshot_ref { |
| 43 | void *ref_buf; | 39 | void *ref_buf; |
| 44 | size_t ref_offset; | 40 | size_t ref_offset; |
diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index f630de0206a1..9535be57033f 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c | |||
| @@ -40,10 +40,6 @@ | |||
| 40 | #define KiB_MASK(x) (KiB(x) - 1) | 40 | #define KiB_MASK(x) (KiB(x) - 1) |
| 41 | #define MiB_MASK(x) (MiB(x) - 1) | 41 | #define MiB_MASK(x) (MiB(x) - 1) |
| 42 | 42 | ||
| 43 | #define INTEL_PT_DEFAULT_SAMPLE_SIZE KiB(4) | ||
| 44 | |||
| 45 | #define INTEL_PT_MAX_SAMPLE_SIZE KiB(60) | ||
| 46 | |||
| 47 | #define INTEL_PT_PSB_PERIOD_NEAR 256 | 43 | #define INTEL_PT_PSB_PERIOD_NEAR 256 |
| 48 | 44 | ||
| 49 | struct intel_pt_snapshot_ref { | 45 | struct intel_pt_snapshot_ref { |
| @@ -196,6 +192,7 @@ static u64 intel_pt_default_config(struct perf_pmu *intel_pt_pmu) | |||
| 196 | int psb_cyc, psb_periods, psb_period; | 192 | int psb_cyc, psb_periods, psb_period; |
| 197 | int pos = 0; | 193 | int pos = 0; |
| 198 | u64 config; | 194 | u64 config; |
| 195 | char c; | ||
| 199 | 196 | ||
| 200 | pos += scnprintf(buf + pos, sizeof(buf) - pos, "tsc"); | 197 | pos += scnprintf(buf + pos, sizeof(buf) - pos, "tsc"); |
| 201 | 198 | ||
| @@ -229,6 +226,10 @@ static u64 intel_pt_default_config(struct perf_pmu *intel_pt_pmu) | |||
| 229 | } | 226 | } |
| 230 | } | 227 | } |
| 231 | 228 | ||
| 229 | if (perf_pmu__scan_file(intel_pt_pmu, "format/pt", "%c", &c) == 1 && | ||
| 230 | perf_pmu__scan_file(intel_pt_pmu, "format/branch", "%c", &c) == 1) | ||
| 231 | pos += scnprintf(buf + pos, sizeof(buf) - pos, ",pt,branch"); | ||
| 232 | |||
| 232 | pr_debug2("%s default config: %s\n", intel_pt_pmu->name, buf); | 233 | pr_debug2("%s default config: %s\n", intel_pt_pmu->name, buf); |
| 233 | 234 | ||
| 234 | intel_pt_parse_terms(&intel_pt_pmu->format, buf, &config); | 235 | intel_pt_parse_terms(&intel_pt_pmu->format, buf, &config); |
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c index 27de0c8c5c19..469d65b21122 100644 --- a/tools/perf/bench/numa.c +++ b/tools/perf/bench/numa.c | |||
| @@ -700,7 +700,7 @@ static inline uint32_t lfsr_32(uint32_t lfsr) | |||
| 700 | * kernel (KSM, zero page, etc.) cannot optimize away RAM | 700 | * kernel (KSM, zero page, etc.) cannot optimize away RAM |
| 701 | * accesses: | 701 | * accesses: |
| 702 | */ | 702 | */ |
| 703 | static inline u64 access_data(u64 *data __attribute__((unused)), u64 val) | 703 | static inline u64 access_data(u64 *data, u64 val) |
| 704 | { | 704 | { |
| 705 | if (g->p.data_reads) | 705 | if (g->p.data_reads) |
| 706 | val += *data; | 706 | val += *data; |
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 620a467ee304..475999e48f66 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c | |||
| @@ -1725,10 +1725,10 @@ static int c2c_hists__init_sort(struct perf_hpp_list *hpp_list, char *name) | |||
| 1725 | tok; tok = strtok_r(NULL, ", ", &tmp)) { \ | 1725 | tok; tok = strtok_r(NULL, ", ", &tmp)) { \ |
| 1726 | ret = _fn(hpp_list, tok); \ | 1726 | ret = _fn(hpp_list, tok); \ |
| 1727 | if (ret == -EINVAL) { \ | 1727 | if (ret == -EINVAL) { \ |
| 1728 | error("Invalid --fields key: `%s'", tok); \ | 1728 | pr_err("Invalid --fields key: `%s'", tok); \ |
| 1729 | break; \ | 1729 | break; \ |
| 1730 | } else if (ret == -ESRCH) { \ | 1730 | } else if (ret == -ESRCH) { \ |
| 1731 | error("Unknown --fields key: `%s'", tok); \ | 1731 | pr_err("Unknown --fields key: `%s'", tok); \ |
| 1732 | break; \ | 1732 | break; \ |
| 1733 | } \ | 1733 | } \ |
| 1734 | } \ | 1734 | } \ |
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c index 80668fa7556e..ece45582a48d 100644 --- a/tools/perf/builtin-config.c +++ b/tools/perf/builtin-config.c | |||
| @@ -156,7 +156,7 @@ static int parse_config_arg(char *arg, char **var, char **value) | |||
| 156 | 156 | ||
| 157 | int cmd_config(int argc, const char **argv) | 157 | int cmd_config(int argc, const char **argv) |
| 158 | { | 158 | { |
| 159 | int i, ret = 0; | 159 | int i, ret = -1; |
| 160 | struct perf_config_set *set; | 160 | struct perf_config_set *set; |
| 161 | char *user_config = mkpath("%s/.perfconfig", getenv("HOME")); | 161 | char *user_config = mkpath("%s/.perfconfig", getenv("HOME")); |
| 162 | const char *config_filename; | 162 | const char *config_filename; |
| @@ -186,10 +186,8 @@ int cmd_config(int argc, const char **argv) | |||
| 186 | * because of reinitializing with options config file location. | 186 | * because of reinitializing with options config file location. |
| 187 | */ | 187 | */ |
| 188 | set = perf_config_set__new(); | 188 | set = perf_config_set__new(); |
| 189 | if (!set) { | 189 | if (!set) |
| 190 | ret = -1; | ||
| 191 | goto out_err; | 190 | goto out_err; |
| 192 | } | ||
| 193 | 191 | ||
| 194 | switch (actions) { | 192 | switch (actions) { |
| 195 | case ACTION_LIST: | 193 | case ACTION_LIST: |
| @@ -197,41 +195,54 @@ int cmd_config(int argc, const char **argv) | |||
| 197 | pr_err("Error: takes no arguments\n"); | 195 | pr_err("Error: takes no arguments\n"); |
| 198 | parse_options_usage(config_usage, config_options, "l", 1); | 196 | parse_options_usage(config_usage, config_options, "l", 1); |
| 199 | } else { | 197 | } else { |
| 200 | ret = show_config(set); | 198 | if (show_config(set) < 0) { |
| 201 | if (ret < 0) | ||
| 202 | pr_err("Nothing configured, " | 199 | pr_err("Nothing configured, " |
| 203 | "please check your %s \n", config_filename); | 200 | "please check your %s \n", config_filename); |
| 201 | goto out_err; | ||
| 202 | } | ||
| 204 | } | 203 | } |
| 205 | break; | 204 | break; |
| 206 | default: | 205 | default: |
| 207 | if (argc) { | 206 | if (!argc) { |
| 208 | for (i = 0; argv[i]; i++) { | 207 | usage_with_options(config_usage, config_options); |
| 209 | char *var, *value; | 208 | break; |
| 210 | char *arg = strdup(argv[i]); | 209 | } |
| 211 | |||
| 212 | if (!arg) { | ||
| 213 | pr_err("%s: strdup failed\n", __func__); | ||
| 214 | ret = -1; | ||
| 215 | break; | ||
| 216 | } | ||
| 217 | 210 | ||
| 218 | if (parse_config_arg(arg, &var, &value) < 0) { | 211 | for (i = 0; argv[i]; i++) { |
| 219 | free(arg); | 212 | char *var, *value; |
| 220 | ret = -1; | 213 | char *arg = strdup(argv[i]); |
| 221 | break; | 214 | |
| 222 | } | 215 | if (!arg) { |
| 216 | pr_err("%s: strdup failed\n", __func__); | ||
| 217 | goto out_err; | ||
| 218 | } | ||
| 223 | 219 | ||
| 224 | if (value == NULL) | 220 | if (parse_config_arg(arg, &var, &value) < 0) { |
| 225 | ret = show_spec_config(set, var); | ||
| 226 | else | ||
| 227 | ret = set_config(set, config_filename, var, value); | ||
| 228 | free(arg); | 221 | free(arg); |
| 222 | goto out_err; | ||
| 229 | } | 223 | } |
| 230 | } else | 224 | |
| 231 | usage_with_options(config_usage, config_options); | 225 | if (value == NULL) { |
| 226 | if (show_spec_config(set, var) < 0) { | ||
| 227 | pr_err("%s is not configured: %s\n", | ||
| 228 | var, config_filename); | ||
| 229 | free(arg); | ||
| 230 | goto out_err; | ||
| 231 | } | ||
| 232 | } else { | ||
| 233 | if (set_config(set, config_filename, var, value) < 0) { | ||
| 234 | pr_err("Failed to set '%s=%s' on %s\n", | ||
| 235 | var, value, config_filename); | ||
| 236 | free(arg); | ||
| 237 | goto out_err; | ||
| 238 | } | ||
| 239 | } | ||
| 240 | free(arg); | ||
| 241 | } | ||
| 232 | } | 242 | } |
| 233 | 243 | ||
| 234 | perf_config_set__delete(set); | 244 | ret = 0; |
| 235 | out_err: | 245 | out_err: |
| 246 | perf_config_set__delete(set); | ||
| 236 | return ret; | 247 | return ret; |
| 237 | } | 248 | } |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index eec5df80f5a3..0cd4cf6a344b 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
| @@ -1302,7 +1302,10 @@ static int diff__config(const char *var, const char *value, | |||
| 1302 | void *cb __maybe_unused) | 1302 | void *cb __maybe_unused) |
| 1303 | { | 1303 | { |
| 1304 | if (!strcmp(var, "diff.order")) { | 1304 | if (!strcmp(var, "diff.order")) { |
| 1305 | sort_compute = perf_config_int(var, value); | 1305 | int ret; |
| 1306 | if (perf_config_int(&ret, var, value) < 0) | ||
| 1307 | return -1; | ||
| 1308 | sort_compute = ret; | ||
| 1306 | return 0; | 1309 | return 0; |
| 1307 | } | 1310 | } |
| 1308 | if (!strcmp(var, "diff.compute")) { | 1311 | if (!strcmp(var, "diff.compute")) { |
diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index 9e0b35cd0eea..dd26c62c9893 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c | |||
| @@ -28,9 +28,19 @@ | |||
| 28 | #define DEFAULT_TRACER "function_graph" | 28 | #define DEFAULT_TRACER "function_graph" |
| 29 | 29 | ||
| 30 | struct perf_ftrace { | 30 | struct perf_ftrace { |
| 31 | struct perf_evlist *evlist; | 31 | struct perf_evlist *evlist; |
| 32 | struct target target; | 32 | struct target target; |
| 33 | const char *tracer; | 33 | const char *tracer; |
| 34 | struct list_head filters; | ||
| 35 | struct list_head notrace; | ||
| 36 | struct list_head graph_funcs; | ||
| 37 | struct list_head nograph_funcs; | ||
| 38 | int graph_depth; | ||
| 39 | }; | ||
| 40 | |||
| 41 | struct filter_entry { | ||
| 42 | struct list_head list; | ||
| 43 | char name[]; | ||
| 34 | }; | 44 | }; |
| 35 | 45 | ||
| 36 | static bool done; | 46 | static bool done; |
| @@ -61,6 +71,7 @@ static int __write_tracing_file(const char *name, const char *val, bool append) | |||
| 61 | int fd, ret = -1; | 71 | int fd, ret = -1; |
| 62 | ssize_t size = strlen(val); | 72 | ssize_t size = strlen(val); |
| 63 | int flags = O_WRONLY; | 73 | int flags = O_WRONLY; |
| 74 | char errbuf[512]; | ||
| 64 | 75 | ||
| 65 | file = get_tracing_file(name); | 76 | file = get_tracing_file(name); |
| 66 | if (!file) { | 77 | if (!file) { |
| @@ -75,14 +86,16 @@ static int __write_tracing_file(const char *name, const char *val, bool append) | |||
| 75 | 86 | ||
| 76 | fd = open(file, flags); | 87 | fd = open(file, flags); |
| 77 | if (fd < 0) { | 88 | if (fd < 0) { |
| 78 | pr_debug("cannot open tracing file: %s\n", name); | 89 | pr_debug("cannot open tracing file: %s: %s\n", |
| 90 | name, str_error_r(errno, errbuf, sizeof(errbuf))); | ||
| 79 | goto out; | 91 | goto out; |
| 80 | } | 92 | } |
| 81 | 93 | ||
| 82 | if (write(fd, val, size) == size) | 94 | if (write(fd, val, size) == size) |
| 83 | ret = 0; | 95 | ret = 0; |
| 84 | else | 96 | else |
| 85 | pr_debug("write '%s' to tracing/%s failed\n", val, name); | 97 | pr_debug("write '%s' to tracing/%s failed: %s\n", |
| 98 | val, name, str_error_r(errno, errbuf, sizeof(errbuf))); | ||
| 86 | 99 | ||
| 87 | close(fd); | 100 | close(fd); |
| 88 | out: | 101 | out: |
| @@ -101,6 +114,7 @@ static int append_tracing_file(const char *name, const char *val) | |||
| 101 | } | 114 | } |
| 102 | 115 | ||
| 103 | static int reset_tracing_cpu(void); | 116 | static int reset_tracing_cpu(void); |
| 117 | static void reset_tracing_filters(void); | ||
| 104 | 118 | ||
| 105 | static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused) | 119 | static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused) |
| 106 | { | 120 | { |
| @@ -116,6 +130,10 @@ static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused) | |||
| 116 | if (reset_tracing_cpu() < 0) | 130 | if (reset_tracing_cpu() < 0) |
| 117 | return -1; | 131 | return -1; |
| 118 | 132 | ||
| 133 | if (write_tracing_file("max_graph_depth", "0") < 0) | ||
| 134 | return -1; | ||
| 135 | |||
| 136 | reset_tracing_filters(); | ||
| 119 | return 0; | 137 | return 0; |
| 120 | } | 138 | } |
| 121 | 139 | ||
| @@ -181,6 +199,68 @@ static int reset_tracing_cpu(void) | |||
| 181 | return ret; | 199 | return ret; |
| 182 | } | 200 | } |
| 183 | 201 | ||
| 202 | static int __set_tracing_filter(const char *filter_file, struct list_head *funcs) | ||
| 203 | { | ||
| 204 | struct filter_entry *pos; | ||
| 205 | |||
| 206 | list_for_each_entry(pos, funcs, list) { | ||
| 207 | if (append_tracing_file(filter_file, pos->name) < 0) | ||
| 208 | return -1; | ||
| 209 | } | ||
| 210 | |||
| 211 | return 0; | ||
| 212 | } | ||
| 213 | |||
| 214 | static int set_tracing_filters(struct perf_ftrace *ftrace) | ||
| 215 | { | ||
| 216 | int ret; | ||
| 217 | |||
| 218 | ret = __set_tracing_filter("set_ftrace_filter", &ftrace->filters); | ||
| 219 | if (ret < 0) | ||
| 220 | return ret; | ||
| 221 | |||
| 222 | ret = __set_tracing_filter("set_ftrace_notrace", &ftrace->notrace); | ||
| 223 | if (ret < 0) | ||
| 224 | return ret; | ||
| 225 | |||
| 226 | ret = __set_tracing_filter("set_graph_function", &ftrace->graph_funcs); | ||
| 227 | if (ret < 0) | ||
| 228 | return ret; | ||
| 229 | |||
| 230 | /* old kernels do not have this filter */ | ||
| 231 | __set_tracing_filter("set_graph_notrace", &ftrace->nograph_funcs); | ||
| 232 | |||
| 233 | return ret; | ||
| 234 | } | ||
| 235 | |||
| 236 | static void reset_tracing_filters(void) | ||
| 237 | { | ||
| 238 | write_tracing_file("set_ftrace_filter", " "); | ||
| 239 | write_tracing_file("set_ftrace_notrace", " "); | ||
| 240 | write_tracing_file("set_graph_function", " "); | ||
| 241 | write_tracing_file("set_graph_notrace", " "); | ||
| 242 | } | ||
| 243 | |||
| 244 | static int set_tracing_depth(struct perf_ftrace *ftrace) | ||
| 245 | { | ||
| 246 | char buf[16]; | ||
| 247 | |||
| 248 | if (ftrace->graph_depth == 0) | ||
| 249 | return 0; | ||
| 250 | |||
| 251 | if (ftrace->graph_depth < 0) { | ||
| 252 | pr_err("invalid graph depth: %d\n", ftrace->graph_depth); | ||
| 253 | return -1; | ||
| 254 | } | ||
| 255 | |||
| 256 | snprintf(buf, sizeof(buf), "%d", ftrace->graph_depth); | ||
| 257 | |||
| 258 | if (write_tracing_file("max_graph_depth", buf) < 0) | ||
| 259 | return -1; | ||
| 260 | |||
| 261 | return 0; | ||
| 262 | } | ||
| 263 | |||
| 184 | static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) | 264 | static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) |
| 185 | { | 265 | { |
| 186 | char *trace_file; | 266 | char *trace_file; |
| @@ -223,11 +303,23 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) | |||
| 223 | goto out_reset; | 303 | goto out_reset; |
| 224 | } | 304 | } |
| 225 | 305 | ||
| 306 | if (set_tracing_filters(ftrace) < 0) { | ||
| 307 | pr_err("failed to set tracing filters\n"); | ||
| 308 | goto out_reset; | ||
| 309 | } | ||
| 310 | |||
| 311 | if (set_tracing_depth(ftrace) < 0) { | ||
| 312 | pr_err("failed to set graph depth\n"); | ||
| 313 | goto out_reset; | ||
| 314 | } | ||
| 315 | |||
| 226 | if (write_tracing_file("current_tracer", ftrace->tracer) < 0) { | 316 | if (write_tracing_file("current_tracer", ftrace->tracer) < 0) { |
| 227 | pr_err("failed to set current_tracer to %s\n", ftrace->tracer); | 317 | pr_err("failed to set current_tracer to %s\n", ftrace->tracer); |
| 228 | goto out_reset; | 318 | goto out_reset; |
| 229 | } | 319 | } |
| 230 | 320 | ||
| 321 | setup_pager(); | ||
| 322 | |||
| 231 | trace_file = get_tracing_file("trace_pipe"); | 323 | trace_file = get_tracing_file("trace_pipe"); |
| 232 | if (!trace_file) { | 324 | if (!trace_file) { |
| 233 | pr_err("failed to open trace_pipe\n"); | 325 | pr_err("failed to open trace_pipe\n"); |
| @@ -251,8 +343,6 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) | |||
| 251 | goto out_close_fd; | 343 | goto out_close_fd; |
| 252 | } | 344 | } |
| 253 | 345 | ||
| 254 | setup_pager(); | ||
| 255 | |||
| 256 | perf_evlist__start_workload(ftrace->evlist); | 346 | perf_evlist__start_workload(ftrace->evlist); |
| 257 | 347 | ||
| 258 | while (!done) { | 348 | while (!done) { |
| @@ -307,6 +397,32 @@ static int perf_ftrace_config(const char *var, const char *value, void *cb) | |||
| 307 | return -1; | 397 | return -1; |
| 308 | } | 398 | } |
| 309 | 399 | ||
| 400 | static int parse_filter_func(const struct option *opt, const char *str, | ||
| 401 | int unset __maybe_unused) | ||
| 402 | { | ||
| 403 | struct list_head *head = opt->value; | ||
| 404 | struct filter_entry *entry; | ||
| 405 | |||
| 406 | entry = malloc(sizeof(*entry) + strlen(str) + 1); | ||
| 407 | if (entry == NULL) | ||
| 408 | return -ENOMEM; | ||
| 409 | |||
| 410 | strcpy(entry->name, str); | ||
| 411 | list_add_tail(&entry->list, head); | ||
| 412 | |||
| 413 | return 0; | ||
| 414 | } | ||
| 415 | |||
| 416 | static void delete_filter_func(struct list_head *head) | ||
| 417 | { | ||
| 418 | struct filter_entry *pos, *tmp; | ||
| 419 | |||
| 420 | list_for_each_entry_safe(pos, tmp, head, list) { | ||
| 421 | list_del(&pos->list); | ||
| 422 | free(pos); | ||
| 423 | } | ||
| 424 | } | ||
| 425 | |||
| 310 | int cmd_ftrace(int argc, const char **argv) | 426 | int cmd_ftrace(int argc, const char **argv) |
| 311 | { | 427 | { |
| 312 | int ret; | 428 | int ret; |
| @@ -330,9 +446,24 @@ int cmd_ftrace(int argc, const char **argv) | |||
| 330 | "system-wide collection from all CPUs"), | 446 | "system-wide collection from all CPUs"), |
| 331 | OPT_STRING('C', "cpu", &ftrace.target.cpu_list, "cpu", | 447 | OPT_STRING('C', "cpu", &ftrace.target.cpu_list, "cpu", |
| 332 | "list of cpus to monitor"), | 448 | "list of cpus to monitor"), |
| 449 | OPT_CALLBACK('T', "trace-funcs", &ftrace.filters, "func", | ||
| 450 | "trace given functions only", parse_filter_func), | ||
| 451 | OPT_CALLBACK('N', "notrace-funcs", &ftrace.notrace, "func", | ||
| 452 | "do not trace given functions", parse_filter_func), | ||
| 453 | OPT_CALLBACK('G', "graph-funcs", &ftrace.graph_funcs, "func", | ||
| 454 | "Set graph filter on given functions", parse_filter_func), | ||
| 455 | OPT_CALLBACK('g', "nograph-funcs", &ftrace.nograph_funcs, "func", | ||
| 456 | "Set nograph filter on given functions", parse_filter_func), | ||
| 457 | OPT_INTEGER('D', "graph-depth", &ftrace.graph_depth, | ||
| 458 | "Max depth for function graph tracer"), | ||
| 333 | OPT_END() | 459 | OPT_END() |
| 334 | }; | 460 | }; |
| 335 | 461 | ||
| 462 | INIT_LIST_HEAD(&ftrace.filters); | ||
| 463 | INIT_LIST_HEAD(&ftrace.notrace); | ||
| 464 | INIT_LIST_HEAD(&ftrace.graph_funcs); | ||
| 465 | INIT_LIST_HEAD(&ftrace.nograph_funcs); | ||
| 466 | |||
| 336 | ret = perf_config(perf_ftrace_config, &ftrace); | 467 | ret = perf_config(perf_ftrace_config, &ftrace); |
| 337 | if (ret < 0) | 468 | if (ret < 0) |
| 338 | return -1; | 469 | return -1; |
| @@ -348,12 +479,14 @@ int cmd_ftrace(int argc, const char **argv) | |||
| 348 | 479 | ||
| 349 | target__strerror(&ftrace.target, ret, errbuf, 512); | 480 | target__strerror(&ftrace.target, ret, errbuf, 512); |
| 350 | pr_err("%s\n", errbuf); | 481 | pr_err("%s\n", errbuf); |
| 351 | return -EINVAL; | 482 | goto out_delete_filters; |
| 352 | } | 483 | } |
| 353 | 484 | ||
| 354 | ftrace.evlist = perf_evlist__new(); | 485 | ftrace.evlist = perf_evlist__new(); |
| 355 | if (ftrace.evlist == NULL) | 486 | if (ftrace.evlist == NULL) { |
| 356 | return -ENOMEM; | 487 | ret = -ENOMEM; |
| 488 | goto out_delete_filters; | ||
| 489 | } | ||
| 357 | 490 | ||
| 358 | ret = perf_evlist__create_maps(ftrace.evlist, &ftrace.target); | 491 | ret = perf_evlist__create_maps(ftrace.evlist, &ftrace.target); |
| 359 | if (ret < 0) | 492 | if (ret < 0) |
| @@ -364,5 +497,11 @@ int cmd_ftrace(int argc, const char **argv) | |||
| 364 | out_delete_evlist: | 497 | out_delete_evlist: |
| 365 | perf_evlist__delete(ftrace.evlist); | 498 | perf_evlist__delete(ftrace.evlist); |
| 366 | 499 | ||
| 500 | out_delete_filters: | ||
| 501 | delete_filter_func(&ftrace.filters); | ||
| 502 | delete_filter_func(&ftrace.notrace); | ||
| 503 | delete_filter_func(&ftrace.graph_funcs); | ||
| 504 | delete_filter_func(&ftrace.nograph_funcs); | ||
| 505 | |||
| 367 | return ret; | 506 | return ret; |
| 368 | } | 507 | } |
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 492f8e14ab09..530a7f2fa0f3 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c | |||
| @@ -108,10 +108,14 @@ out: | |||
| 108 | return ret; | 108 | return ret; |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | static void exec_woman_emacs(const char *path, const char *page) | 111 | static void exec_failed(const char *cmd) |
| 112 | { | 112 | { |
| 113 | char sbuf[STRERR_BUFSIZE]; | 113 | char sbuf[STRERR_BUFSIZE]; |
| 114 | pr_warning("failed to exec '%s': %s", cmd, str_error_r(errno, sbuf, sizeof(sbuf))); | ||
| 115 | } | ||
| 114 | 116 | ||
| 117 | static void exec_woman_emacs(const char *path, const char *page) | ||
| 118 | { | ||
| 115 | if (!check_emacsclient_version()) { | 119 | if (!check_emacsclient_version()) { |
| 116 | /* This works only with emacsclient version >= 22. */ | 120 | /* This works only with emacsclient version >= 22. */ |
| 117 | char *man_page; | 121 | char *man_page; |
| @@ -122,8 +126,7 @@ static void exec_woman_emacs(const char *path, const char *page) | |||
| 122 | execlp(path, "emacsclient", "-e", man_page, NULL); | 126 | execlp(path, "emacsclient", "-e", man_page, NULL); |
| 123 | free(man_page); | 127 | free(man_page); |
| 124 | } | 128 | } |
| 125 | warning("failed to exec '%s': %s", path, | 129 | exec_failed(path); |
| 126 | str_error_r(errno, sbuf, sizeof(sbuf))); | ||
| 127 | } | 130 | } |
| 128 | } | 131 | } |
| 129 | 132 | ||
| @@ -134,7 +137,6 @@ static void exec_man_konqueror(const char *path, const char *page) | |||
| 134 | if (display && *display) { | 137 | if (display && *display) { |
| 135 | char *man_page; | 138 | char *man_page; |
| 136 | const char *filename = "kfmclient"; | 139 | const char *filename = "kfmclient"; |
| 137 | char sbuf[STRERR_BUFSIZE]; | ||
| 138 | 140 | ||
| 139 | /* It's simpler to launch konqueror using kfmclient. */ | 141 | /* It's simpler to launch konqueror using kfmclient. */ |
| 140 | if (path) { | 142 | if (path) { |
| @@ -155,33 +157,27 @@ static void exec_man_konqueror(const char *path, const char *page) | |||
| 155 | execlp(path, filename, "newTab", man_page, NULL); | 157 | execlp(path, filename, "newTab", man_page, NULL); |
| 156 | free(man_page); | 158 | free(man_page); |
| 157 | } | 159 | } |
| 158 | warning("failed to exec '%s': %s", path, | 160 | exec_failed(path); |
| 159 | str_error_r(errno, sbuf, sizeof(sbuf))); | ||
| 160 | } | 161 | } |
| 161 | } | 162 | } |
| 162 | 163 | ||
| 163 | static void exec_man_man(const char *path, const char *page) | 164 | static void exec_man_man(const char *path, const char *page) |
| 164 | { | 165 | { |
| 165 | char sbuf[STRERR_BUFSIZE]; | ||
| 166 | |||
| 167 | if (!path) | 166 | if (!path) |
| 168 | path = "man"; | 167 | path = "man"; |
| 169 | execlp(path, "man", page, NULL); | 168 | execlp(path, "man", page, NULL); |
| 170 | warning("failed to exec '%s': %s", path, | 169 | exec_failed(path); |
| 171 | str_error_r(errno, sbuf, sizeof(sbuf))); | ||
| 172 | } | 170 | } |
| 173 | 171 | ||
| 174 | static void exec_man_cmd(const char *cmd, const char *page) | 172 | static void exec_man_cmd(const char *cmd, const char *page) |
| 175 | { | 173 | { |
| 176 | char sbuf[STRERR_BUFSIZE]; | ||
| 177 | char *shell_cmd; | 174 | char *shell_cmd; |
| 178 | 175 | ||
| 179 | if (asprintf(&shell_cmd, "%s %s", cmd, page) > 0) { | 176 | if (asprintf(&shell_cmd, "%s %s", cmd, page) > 0) { |
| 180 | execl("/bin/sh", "sh", "-c", shell_cmd, NULL); | 177 | execl("/bin/sh", "sh", "-c", shell_cmd, NULL); |
| 181 | free(shell_cmd); | 178 | free(shell_cmd); |
| 182 | } | 179 | } |
| 183 | warning("failed to exec '%s': %s", cmd, | 180 | exec_failed(cmd); |
| 184 | str_error_r(errno, sbuf, sizeof(sbuf))); | ||
| 185 | } | 181 | } |
| 186 | 182 | ||
| 187 | static void add_man_viewer(const char *name) | 183 | static void add_man_viewer(const char *name) |
| @@ -214,6 +210,12 @@ static void do_add_man_viewer_info(const char *name, | |||
| 214 | man_viewer_info_list = new; | 210 | man_viewer_info_list = new; |
| 215 | } | 211 | } |
| 216 | 212 | ||
| 213 | static void unsupported_man_viewer(const char *name, const char *var) | ||
| 214 | { | ||
| 215 | pr_warning("'%s': path for unsupported man viewer.\n" | ||
| 216 | "Please consider using 'man.<tool>.%s' instead.", name, var); | ||
| 217 | } | ||
| 218 | |||
| 217 | static int add_man_viewer_path(const char *name, | 219 | static int add_man_viewer_path(const char *name, |
| 218 | size_t len, | 220 | size_t len, |
| 219 | const char *value) | 221 | const char *value) |
| @@ -221,9 +223,7 @@ static int add_man_viewer_path(const char *name, | |||
| 221 | if (supported_man_viewer(name, len)) | 223 | if (supported_man_viewer(name, len)) |
| 222 | do_add_man_viewer_info(name, len, value); | 224 | do_add_man_viewer_info(name, len, value); |
| 223 | else | 225 | else |
| 224 | warning("'%s': path for unsupported man viewer.\n" | 226 | unsupported_man_viewer(name, "cmd"); |
| 225 | "Please consider using 'man.<tool>.cmd' instead.", | ||
| 226 | name); | ||
| 227 | 227 | ||
| 228 | return 0; | 228 | return 0; |
| 229 | } | 229 | } |
| @@ -233,9 +233,7 @@ static int add_man_viewer_cmd(const char *name, | |||
| 233 | const char *value) | 233 | const char *value) |
| 234 | { | 234 | { |
| 235 | if (supported_man_viewer(name, len)) | 235 | if (supported_man_viewer(name, len)) |
| 236 | warning("'%s': cmd for supported man viewer.\n" | 236 | unsupported_man_viewer(name, "path"); |
| 237 | "Please consider using 'man.<tool>.path' instead.", | ||
| 238 | name); | ||
| 239 | else | 237 | else |
| 240 | do_add_man_viewer_info(name, len, value); | 238 | do_add_man_viewer_info(name, len, value); |
| 241 | 239 | ||
| @@ -247,8 +245,10 @@ static int add_man_viewer_info(const char *var, const char *value) | |||
| 247 | const char *name = var + 4; | 245 | const char *name = var + 4; |
| 248 | const char *subkey = strrchr(name, '.'); | 246 | const char *subkey = strrchr(name, '.'); |
| 249 | 247 | ||
| 250 | if (!subkey) | 248 | if (!subkey) { |
| 251 | return error("Config with no key for man viewer: %s", name); | 249 | pr_err("Config with no key for man viewer: %s", name); |
| 250 | return -1; | ||
| 251 | } | ||
| 252 | 252 | ||
| 253 | if (!strcmp(subkey, ".path")) { | 253 | if (!strcmp(subkey, ".path")) { |
| 254 | if (!value) | 254 | if (!value) |
| @@ -261,7 +261,7 @@ static int add_man_viewer_info(const char *var, const char *value) | |||
| 261 | return add_man_viewer_cmd(name, subkey - name, value); | 261 | return add_man_viewer_cmd(name, subkey - name, value); |
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | warning("'%s': unsupported man viewer sub key.", subkey); | 264 | pr_warning("'%s': unsupported man viewer sub key.", subkey); |
| 265 | return 0; | 265 | return 0; |
| 266 | } | 266 | } |
| 267 | 267 | ||
| @@ -332,7 +332,7 @@ static void setup_man_path(void) | |||
| 332 | setenv("MANPATH", new_path, 1); | 332 | setenv("MANPATH", new_path, 1); |
| 333 | free(new_path); | 333 | free(new_path); |
| 334 | } else { | 334 | } else { |
| 335 | error("Unable to setup man path"); | 335 | pr_err("Unable to setup man path"); |
| 336 | } | 336 | } |
| 337 | } | 337 | } |
| 338 | 338 | ||
| @@ -349,7 +349,7 @@ static void exec_viewer(const char *name, const char *page) | |||
| 349 | else if (info) | 349 | else if (info) |
| 350 | exec_man_cmd(info, page); | 350 | exec_man_cmd(info, page); |
| 351 | else | 351 | else |
| 352 | warning("'%s': unknown man viewer.", name); | 352 | pr_warning("'%s': unknown man viewer.", name); |
| 353 | } | 353 | } |
| 354 | 354 | ||
| 355 | static int show_man_page(const char *perf_cmd) | 355 | static int show_man_page(const char *perf_cmd) |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 9409c9464667..0a8a1c45af87 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
| @@ -1715,7 +1715,7 @@ static int setup_slab_sorting(struct list_head *sort_list, const char *arg) | |||
| 1715 | if (!tok) | 1715 | if (!tok) |
| 1716 | break; | 1716 | break; |
| 1717 | if (slab_sort_dimension__add(tok, sort_list) < 0) { | 1717 | if (slab_sort_dimension__add(tok, sort_list) < 0) { |
| 1718 | error("Unknown slab --sort key: '%s'", tok); | 1718 | pr_err("Unknown slab --sort key: '%s'", tok); |
| 1719 | free(str); | 1719 | free(str); |
| 1720 | return -1; | 1720 | return -1; |
| 1721 | } | 1721 | } |
| @@ -1741,7 +1741,7 @@ static int setup_page_sorting(struct list_head *sort_list, const char *arg) | |||
| 1741 | if (!tok) | 1741 | if (!tok) |
| 1742 | break; | 1742 | break; |
| 1743 | if (page_sort_dimension__add(tok, sort_list) < 0) { | 1743 | if (page_sort_dimension__add(tok, sort_list) < 0) { |
| 1744 | error("Unknown page --sort key: '%s'", tok); | 1744 | pr_err("Unknown page --sort key: '%s'", tok); |
| 1745 | free(str); | 1745 | free(str); |
| 1746 | return -1; | 1746 | return -1; |
| 1747 | } | 1747 | } |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ee7d0a82ccd0..17a14bcce34a 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
| @@ -453,7 +453,7 @@ try_again: | |||
| 453 | } | 453 | } |
| 454 | 454 | ||
| 455 | if (perf_evlist__apply_filters(evlist, &pos)) { | 455 | if (perf_evlist__apply_filters(evlist, &pos)) { |
| 456 | error("failed to set filter \"%s\" on event %s with %d (%s)\n", | 456 | pr_err("failed to set filter \"%s\" on event %s with %d (%s)\n", |
| 457 | pos->filter, perf_evsel__name(pos), errno, | 457 | pos->filter, perf_evsel__name(pos), errno, |
| 458 | str_error_r(errno, msg, sizeof(msg))); | 458 | str_error_r(errno, msg, sizeof(msg))); |
| 459 | rc = -1; | 459 | rc = -1; |
| @@ -461,7 +461,7 @@ try_again: | |||
| 461 | } | 461 | } |
| 462 | 462 | ||
| 463 | if (perf_evlist__apply_drv_configs(evlist, &pos, &err_term)) { | 463 | if (perf_evlist__apply_drv_configs(evlist, &pos, &err_term)) { |
| 464 | error("failed to set config \"%s\" on event %s with %d (%s)\n", | 464 | pr_err("failed to set config \"%s\" on event %s with %d (%s)\n", |
| 465 | err_term->val.drv_cfg, perf_evsel__name(pos), errno, | 465 | err_term->val.drv_cfg, perf_evsel__name(pos), errno, |
| 466 | str_error_r(errno, msg, sizeof(msg))); | 466 | str_error_r(errno, msg, sizeof(msg))); |
| 467 | rc = -1; | 467 | rc = -1; |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 22478ff2b706..79a33eb1a10d 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -94,10 +94,9 @@ static int report__config(const char *var, const char *value, void *cb) | |||
| 94 | symbol_conf.cumulate_callchain = perf_config_bool(var, value); | 94 | symbol_conf.cumulate_callchain = perf_config_bool(var, value); |
| 95 | return 0; | 95 | return 0; |
| 96 | } | 96 | } |
| 97 | if (!strcmp(var, "report.queue-size")) { | 97 | if (!strcmp(var, "report.queue-size")) |
| 98 | rep->queue_size = perf_config_u64(var, value); | 98 | return perf_config_u64(&rep->queue_size, var, value); |
| 99 | return 0; | 99 | |
| 100 | } | ||
| 101 | if (!strcmp(var, "report.sort_order")) { | 100 | if (!strcmp(var, "report.sort_order")) { |
| 102 | default_sort_order = strdup(value); | 101 | default_sort_order = strdup(value); |
| 103 | return 0; | 102 | return 0; |
| @@ -558,6 +557,7 @@ static int __cmd_report(struct report *rep) | |||
| 558 | ui__error("failed to set cpu bitmap\n"); | 557 | ui__error("failed to set cpu bitmap\n"); |
| 559 | return ret; | 558 | return ret; |
| 560 | } | 559 | } |
| 560 | session->itrace_synth_opts->cpu_bitmap = rep->cpu_bitmap; | ||
| 561 | } | 561 | } |
| 562 | 562 | ||
| 563 | if (rep->show_threads) { | 563 | if (rep->show_threads) { |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 39996c53995a..322b4def8411 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
| @@ -2066,7 +2066,7 @@ static void save_task_callchain(struct perf_sched *sched, | |||
| 2066 | if (thread__resolve_callchain(thread, cursor, evsel, sample, | 2066 | if (thread__resolve_callchain(thread, cursor, evsel, sample, |
| 2067 | NULL, NULL, sched->max_stack + 2) != 0) { | 2067 | NULL, NULL, sched->max_stack + 2) != 0) { |
| 2068 | if (verbose > 0) | 2068 | if (verbose > 0) |
| 2069 | error("Failed to resolve callchain. Skipping\n"); | 2069 | pr_err("Failed to resolve callchain. Skipping\n"); |
| 2070 | 2070 | ||
| 2071 | return; | 2071 | return; |
| 2072 | } | 2072 | } |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 4761b0d7fcb5..83cdc0a61fd6 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
| @@ -85,6 +85,8 @@ enum perf_output_field { | |||
| 85 | PERF_OUTPUT_INSN = 1U << 21, | 85 | PERF_OUTPUT_INSN = 1U << 21, |
| 86 | PERF_OUTPUT_INSNLEN = 1U << 22, | 86 | PERF_OUTPUT_INSNLEN = 1U << 22, |
| 87 | PERF_OUTPUT_BRSTACKINSN = 1U << 23, | 87 | PERF_OUTPUT_BRSTACKINSN = 1U << 23, |
| 88 | PERF_OUTPUT_BRSTACKOFF = 1U << 24, | ||
| 89 | PERF_OUTPUT_SYNTH = 1U << 25, | ||
| 88 | }; | 90 | }; |
| 89 | 91 | ||
| 90 | struct output_option { | 92 | struct output_option { |
| @@ -115,6 +117,13 @@ struct output_option { | |||
| 115 | {.str = "insn", .field = PERF_OUTPUT_INSN}, | 117 | {.str = "insn", .field = PERF_OUTPUT_INSN}, |
| 116 | {.str = "insnlen", .field = PERF_OUTPUT_INSNLEN}, | 118 | {.str = "insnlen", .field = PERF_OUTPUT_INSNLEN}, |
| 117 | {.str = "brstackinsn", .field = PERF_OUTPUT_BRSTACKINSN}, | 119 | {.str = "brstackinsn", .field = PERF_OUTPUT_BRSTACKINSN}, |
| 120 | {.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF}, | ||
| 121 | {.str = "synth", .field = PERF_OUTPUT_SYNTH}, | ||
| 122 | }; | ||
| 123 | |||
| 124 | enum { | ||
| 125 | OUTPUT_TYPE_SYNTH = PERF_TYPE_MAX, | ||
| 126 | OUTPUT_TYPE_MAX | ||
| 118 | }; | 127 | }; |
| 119 | 128 | ||
| 120 | /* default set to maintain compatibility with current format */ | 129 | /* default set to maintain compatibility with current format */ |
| @@ -124,7 +133,7 @@ static struct { | |||
| 124 | unsigned int print_ip_opts; | 133 | unsigned int print_ip_opts; |
| 125 | u64 fields; | 134 | u64 fields; |
| 126 | u64 invalid_fields; | 135 | u64 invalid_fields; |
| 127 | } output[PERF_TYPE_MAX] = { | 136 | } output[OUTPUT_TYPE_MAX] = { |
| 128 | 137 | ||
| 129 | [PERF_TYPE_HARDWARE] = { | 138 | [PERF_TYPE_HARDWARE] = { |
| 130 | .user_set = false, | 139 | .user_set = false, |
| @@ -182,12 +191,44 @@ static struct { | |||
| 182 | 191 | ||
| 183 | .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, | 192 | .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, |
| 184 | }, | 193 | }, |
| 194 | |||
| 195 | [OUTPUT_TYPE_SYNTH] = { | ||
| 196 | .user_set = false, | ||
| 197 | |||
| 198 | .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | | ||
| 199 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | | ||
| 200 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | | ||
| 201 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | | ||
| 202 | PERF_OUTPUT_SYNTH, | ||
| 203 | |||
| 204 | .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, | ||
| 205 | }, | ||
| 185 | }; | 206 | }; |
| 186 | 207 | ||
| 208 | static inline int output_type(unsigned int type) | ||
| 209 | { | ||
| 210 | switch (type) { | ||
| 211 | case PERF_TYPE_SYNTH: | ||
| 212 | return OUTPUT_TYPE_SYNTH; | ||
| 213 | default: | ||
| 214 | return type; | ||
| 215 | } | ||
| 216 | } | ||
| 217 | |||
| 218 | static inline unsigned int attr_type(unsigned int type) | ||
| 219 | { | ||
| 220 | switch (type) { | ||
| 221 | case OUTPUT_TYPE_SYNTH: | ||
| 222 | return PERF_TYPE_SYNTH; | ||
| 223 | default: | ||
| 224 | return type; | ||
| 225 | } | ||
| 226 | } | ||
| 227 | |||
| 187 | static bool output_set_by_user(void) | 228 | static bool output_set_by_user(void) |
| 188 | { | 229 | { |
| 189 | int j; | 230 | int j; |
| 190 | for (j = 0; j < PERF_TYPE_MAX; ++j) { | 231 | for (j = 0; j < OUTPUT_TYPE_MAX; ++j) { |
| 191 | if (output[j].user_set) | 232 | if (output[j].user_set) |
| 192 | return true; | 233 | return true; |
| 193 | } | 234 | } |
| @@ -208,7 +249,7 @@ static const char *output_field2str(enum perf_output_field field) | |||
| 208 | return str; | 249 | return str; |
| 209 | } | 250 | } |
| 210 | 251 | ||
| 211 | #define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x) | 252 | #define PRINT_FIELD(x) (output[output_type(attr->type)].fields & PERF_OUTPUT_##x) |
| 212 | 253 | ||
| 213 | static int perf_evsel__do_check_stype(struct perf_evsel *evsel, | 254 | static int perf_evsel__do_check_stype(struct perf_evsel *evsel, |
| 214 | u64 sample_type, const char *sample_msg, | 255 | u64 sample_type, const char *sample_msg, |
| @@ -216,7 +257,7 @@ static int perf_evsel__do_check_stype(struct perf_evsel *evsel, | |||
| 216 | bool allow_user_set) | 257 | bool allow_user_set) |
| 217 | { | 258 | { |
| 218 | struct perf_event_attr *attr = &evsel->attr; | 259 | struct perf_event_attr *attr = &evsel->attr; |
| 219 | int type = attr->type; | 260 | int type = output_type(attr->type); |
| 220 | const char *evname; | 261 | const char *evname; |
| 221 | 262 | ||
| 222 | if (attr->sample_type & sample_type) | 263 | if (attr->sample_type & sample_type) |
| @@ -298,10 +339,10 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
| 298 | "selected.\n"); | 339 | "selected.\n"); |
| 299 | return -EINVAL; | 340 | return -EINVAL; |
| 300 | } | 341 | } |
| 301 | if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { | 342 | if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR) && |
| 302 | pr_err("Display of DSO requested but neither sample IP nor " | 343 | !PRINT_FIELD(BRSTACK) && !PRINT_FIELD(BRSTACKSYM) && !PRINT_FIELD(BRSTACKOFF)) { |
| 303 | "sample address\nis selected. Hence, no addresses to convert " | 344 | pr_err("Display of DSO requested but no address to convert. Select\n" |
| 304 | "to DSO.\n"); | 345 | "sample IP, sample address, brstack, brstacksym, or brstackoff.\n"); |
| 305 | return -EINVAL; | 346 | return -EINVAL; |
| 306 | } | 347 | } |
| 307 | if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) { | 348 | if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) { |
| @@ -346,7 +387,7 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
| 346 | 387 | ||
| 347 | static void set_print_ip_opts(struct perf_event_attr *attr) | 388 | static void set_print_ip_opts(struct perf_event_attr *attr) |
| 348 | { | 389 | { |
| 349 | unsigned int type = attr->type; | 390 | unsigned int type = output_type(attr->type); |
| 350 | 391 | ||
| 351 | output[type].print_ip_opts = 0; | 392 | output[type].print_ip_opts = 0; |
| 352 | if (PRINT_FIELD(IP)) | 393 | if (PRINT_FIELD(IP)) |
| @@ -374,16 +415,17 @@ static int perf_session__check_output_opt(struct perf_session *session) | |||
| 374 | unsigned int j; | 415 | unsigned int j; |
| 375 | struct perf_evsel *evsel; | 416 | struct perf_evsel *evsel; |
| 376 | 417 | ||
| 377 | for (j = 0; j < PERF_TYPE_MAX; ++j) { | 418 | for (j = 0; j < OUTPUT_TYPE_MAX; ++j) { |
| 378 | evsel = perf_session__find_first_evtype(session, j); | 419 | evsel = perf_session__find_first_evtype(session, attr_type(j)); |
| 379 | 420 | ||
| 380 | /* | 421 | /* |
| 381 | * even if fields is set to 0 (ie., show nothing) event must | 422 | * even if fields is set to 0 (ie., show nothing) event must |
| 382 | * exist if user explicitly includes it on the command line | 423 | * exist if user explicitly includes it on the command line |
| 383 | */ | 424 | */ |
| 384 | if (!evsel && output[j].user_set && !output[j].wildcard_set) { | 425 | if (!evsel && output[j].user_set && !output[j].wildcard_set && |
| 426 | j != OUTPUT_TYPE_SYNTH) { | ||
| 385 | pr_err("%s events do not exist. " | 427 | pr_err("%s events do not exist. " |
| 386 | "Remove corresponding -f option to proceed.\n", | 428 | "Remove corresponding -F option to proceed.\n", |
| 387 | event_type(j)); | 429 | event_type(j)); |
| 388 | return -1; | 430 | return -1; |
| 389 | } | 431 | } |
| @@ -514,18 +556,43 @@ mispred_str(struct branch_entry *br) | |||
| 514 | return br->flags.predicted ? 'P' : 'M'; | 556 | return br->flags.predicted ? 'P' : 'M'; |
| 515 | } | 557 | } |
| 516 | 558 | ||
| 517 | static void print_sample_brstack(struct perf_sample *sample) | 559 | static void print_sample_brstack(struct perf_sample *sample, |
| 560 | struct thread *thread, | ||
| 561 | struct perf_event_attr *attr) | ||
| 518 | { | 562 | { |
| 519 | struct branch_stack *br = sample->branch_stack; | 563 | struct branch_stack *br = sample->branch_stack; |
| 520 | u64 i; | 564 | struct addr_location alf, alt; |
| 565 | u64 i, from, to; | ||
| 521 | 566 | ||
| 522 | if (!(br && br->nr)) | 567 | if (!(br && br->nr)) |
| 523 | return; | 568 | return; |
| 524 | 569 | ||
| 525 | for (i = 0; i < br->nr; i++) { | 570 | for (i = 0; i < br->nr; i++) { |
| 526 | printf(" 0x%"PRIx64"/0x%"PRIx64"/%c/%c/%c/%d ", | 571 | from = br->entries[i].from; |
| 527 | br->entries[i].from, | 572 | to = br->entries[i].to; |
| 528 | br->entries[i].to, | 573 | |
| 574 | if (PRINT_FIELD(DSO)) { | ||
| 575 | memset(&alf, 0, sizeof(alf)); | ||
| 576 | memset(&alt, 0, sizeof(alt)); | ||
| 577 | thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, from, &alf); | ||
| 578 | thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt); | ||
| 579 | } | ||
| 580 | |||
| 581 | printf("0x%"PRIx64, from); | ||
| 582 | if (PRINT_FIELD(DSO)) { | ||
| 583 | printf("("); | ||
| 584 | map__fprintf_dsoname(alf.map, stdout); | ||
| 585 | printf(")"); | ||
| 586 | } | ||
| 587 | |||
| 588 | printf("/0x%"PRIx64, to); | ||
| 589 | if (PRINT_FIELD(DSO)) { | ||
| 590 | printf("("); | ||
| 591 | map__fprintf_dsoname(alt.map, stdout); | ||
| 592 | printf(")"); | ||
| 593 | } | ||
| 594 | |||
| 595 | printf("/%c/%c/%c/%d ", | ||
| 529 | mispred_str( br->entries + i), | 596 | mispred_str( br->entries + i), |
| 530 | br->entries[i].flags.in_tx? 'X' : '-', | 597 | br->entries[i].flags.in_tx? 'X' : '-', |
| 531 | br->entries[i].flags.abort? 'A' : '-', | 598 | br->entries[i].flags.abort? 'A' : '-', |
| @@ -534,7 +601,8 @@ static void print_sample_brstack(struct perf_sample *sample) | |||
| 534 | } | 601 | } |
| 535 | 602 | ||
| 536 | static void print_sample_brstacksym(struct perf_sample *sample, | 603 | static void print_sample_brstacksym(struct perf_sample *sample, |
| 537 | struct thread *thread) | 604 | struct thread *thread, |
| 605 | struct perf_event_attr *attr) | ||
| 538 | { | 606 | { |
| 539 | struct branch_stack *br = sample->branch_stack; | 607 | struct branch_stack *br = sample->branch_stack; |
| 540 | struct addr_location alf, alt; | 608 | struct addr_location alf, alt; |
| @@ -559,8 +627,18 @@ static void print_sample_brstacksym(struct perf_sample *sample, | |||
| 559 | alt.sym = map__find_symbol(alt.map, alt.addr); | 627 | alt.sym = map__find_symbol(alt.map, alt.addr); |
| 560 | 628 | ||
| 561 | symbol__fprintf_symname_offs(alf.sym, &alf, stdout); | 629 | symbol__fprintf_symname_offs(alf.sym, &alf, stdout); |
| 630 | if (PRINT_FIELD(DSO)) { | ||
| 631 | printf("("); | ||
| 632 | map__fprintf_dsoname(alf.map, stdout); | ||
| 633 | printf(")"); | ||
| 634 | } | ||
| 562 | putchar('/'); | 635 | putchar('/'); |
| 563 | symbol__fprintf_symname_offs(alt.sym, &alt, stdout); | 636 | symbol__fprintf_symname_offs(alt.sym, &alt, stdout); |
| 637 | if (PRINT_FIELD(DSO)) { | ||
| 638 | printf("("); | ||
| 639 | map__fprintf_dsoname(alt.map, stdout); | ||
| 640 | printf(")"); | ||
| 641 | } | ||
| 564 | printf("/%c/%c/%c/%d ", | 642 | printf("/%c/%c/%c/%d ", |
| 565 | mispred_str( br->entries + i), | 643 | mispred_str( br->entries + i), |
| 566 | br->entries[i].flags.in_tx? 'X' : '-', | 644 | br->entries[i].flags.in_tx? 'X' : '-', |
| @@ -569,6 +647,51 @@ static void print_sample_brstacksym(struct perf_sample *sample, | |||
| 569 | } | 647 | } |
| 570 | } | 648 | } |
| 571 | 649 | ||
| 650 | static void print_sample_brstackoff(struct perf_sample *sample, | ||
| 651 | struct thread *thread, | ||
| 652 | struct perf_event_attr *attr) | ||
| 653 | { | ||
| 654 | struct branch_stack *br = sample->branch_stack; | ||
| 655 | struct addr_location alf, alt; | ||
| 656 | u64 i, from, to; | ||
| 657 | |||
| 658 | if (!(br && br->nr)) | ||
| 659 | return; | ||
| 660 | |||
| 661 | for (i = 0; i < br->nr; i++) { | ||
| 662 | |||
| 663 | memset(&alf, 0, sizeof(alf)); | ||
| 664 | memset(&alt, 0, sizeof(alt)); | ||
| 665 | from = br->entries[i].from; | ||
| 666 | to = br->entries[i].to; | ||
| 667 | |||
| 668 | thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, from, &alf); | ||
| 669 | if (alf.map && !alf.map->dso->adjust_symbols) | ||
| 670 | from = map__map_ip(alf.map, from); | ||
| 671 | |||
| 672 | thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt); | ||
| 673 | if (alt.map && !alt.map->dso->adjust_symbols) | ||
| 674 | to = map__map_ip(alt.map, to); | ||
| 675 | |||
| 676 | printf("0x%"PRIx64, from); | ||
| 677 | if (PRINT_FIELD(DSO)) { | ||
| 678 | printf("("); | ||
| 679 | map__fprintf_dsoname(alf.map, stdout); | ||
| 680 | printf(")"); | ||
| 681 | } | ||
| 682 | printf("/0x%"PRIx64, to); | ||
| 683 | if (PRINT_FIELD(DSO)) { | ||
| 684 | printf("("); | ||
| 685 | map__fprintf_dsoname(alt.map, stdout); | ||
| 686 | printf(")"); | ||
| 687 | } | ||
| 688 | printf("/%c/%c/%c/%d ", | ||
| 689 | mispred_str(br->entries + i), | ||
| 690 | br->entries[i].flags.in_tx ? 'X' : '-', | ||
| 691 | br->entries[i].flags.abort ? 'A' : '-', | ||
| 692 | br->entries[i].flags.cycles); | ||
| 693 | } | ||
| 694 | } | ||
| 572 | #define MAXBB 16384UL | 695 | #define MAXBB 16384UL |
| 573 | 696 | ||
| 574 | static int grab_bb(u8 *buffer, u64 start, u64 end, | 697 | static int grab_bb(u8 *buffer, u64 start, u64 end, |
| @@ -906,6 +1029,7 @@ static void print_sample_bts(struct perf_sample *sample, | |||
| 906 | struct machine *machine) | 1029 | struct machine *machine) |
| 907 | { | 1030 | { |
| 908 | struct perf_event_attr *attr = &evsel->attr; | 1031 | struct perf_event_attr *attr = &evsel->attr; |
| 1032 | unsigned int type = output_type(attr->type); | ||
| 909 | bool print_srcline_last = false; | 1033 | bool print_srcline_last = false; |
| 910 | 1034 | ||
| 911 | if (PRINT_FIELD(CALLINDENT)) | 1035 | if (PRINT_FIELD(CALLINDENT)) |
| @@ -913,7 +1037,7 @@ static void print_sample_bts(struct perf_sample *sample, | |||
| 913 | 1037 | ||
| 914 | /* print branch_from information */ | 1038 | /* print branch_from information */ |
| 915 | if (PRINT_FIELD(IP)) { | 1039 | if (PRINT_FIELD(IP)) { |
| 916 | unsigned int print_opts = output[attr->type].print_ip_opts; | 1040 | unsigned int print_opts = output[type].print_ip_opts; |
| 917 | struct callchain_cursor *cursor = NULL; | 1041 | struct callchain_cursor *cursor = NULL; |
| 918 | 1042 | ||
| 919 | if (symbol_conf.use_callchain && sample->callchain && | 1043 | if (symbol_conf.use_callchain && sample->callchain && |
| @@ -936,7 +1060,7 @@ static void print_sample_bts(struct perf_sample *sample, | |||
| 936 | /* print branch_to information */ | 1060 | /* print branch_to information */ |
| 937 | if (PRINT_FIELD(ADDR) || | 1061 | if (PRINT_FIELD(ADDR) || |
| 938 | ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && | 1062 | ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && |
| 939 | !output[attr->type].user_set)) { | 1063 | !output[type].user_set)) { |
| 940 | printf(" => "); | 1064 | printf(" => "); |
| 941 | print_sample_addr(sample, thread, attr); | 1065 | print_sample_addr(sample, thread, attr); |
| 942 | } | 1066 | } |
| @@ -1079,6 +1203,127 @@ static void print_sample_bpf_output(struct perf_sample *sample) | |||
| 1079 | (char *)(sample->raw_data)); | 1203 | (char *)(sample->raw_data)); |
| 1080 | } | 1204 | } |
| 1081 | 1205 | ||
| 1206 | static void print_sample_spacing(int len, int spacing) | ||
| 1207 | { | ||
| 1208 | if (len > 0 && len < spacing) | ||
| 1209 | printf("%*s", spacing - len, ""); | ||
| 1210 | } | ||
| 1211 | |||
| 1212 | static void print_sample_pt_spacing(int len) | ||
| 1213 | { | ||
| 1214 | print_sample_spacing(len, 34); | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | static void print_sample_synth_ptwrite(struct perf_sample *sample) | ||
| 1218 | { | ||
| 1219 | struct perf_synth_intel_ptwrite *data = perf_sample__synth_ptr(sample); | ||
| 1220 | int len; | ||
| 1221 | |||
| 1222 | if (perf_sample__bad_synth_size(sample, *data)) | ||
| 1223 | return; | ||
| 1224 | |||
| 1225 | len = printf(" IP: %u payload: %#" PRIx64 " ", | ||
| 1226 | data->ip, le64_to_cpu(data->payload)); | ||
| 1227 | print_sample_pt_spacing(len); | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | static void print_sample_synth_mwait(struct perf_sample *sample) | ||
| 1231 | { | ||
| 1232 | struct perf_synth_intel_mwait *data = perf_sample__synth_ptr(sample); | ||
| 1233 | int len; | ||
| 1234 | |||
| 1235 | if (perf_sample__bad_synth_size(sample, *data)) | ||
| 1236 | return; | ||
| 1237 | |||
| 1238 | len = printf(" hints: %#x extensions: %#x ", | ||
| 1239 | data->hints, data->extensions); | ||
| 1240 | print_sample_pt_spacing(len); | ||
| 1241 | } | ||
| 1242 | |||
| 1243 | static void print_sample_synth_pwre(struct perf_sample *sample) | ||
| 1244 | { | ||
| 1245 | struct perf_synth_intel_pwre *data = perf_sample__synth_ptr(sample); | ||
| 1246 | int len; | ||
| 1247 | |||
| 1248 | if (perf_sample__bad_synth_size(sample, *data)) | ||
| 1249 | return; | ||
| 1250 | |||
| 1251 | len = printf(" hw: %u cstate: %u sub-cstate: %u ", | ||
| 1252 | data->hw, data->cstate, data->subcstate); | ||
| 1253 | print_sample_pt_spacing(len); | ||
| 1254 | } | ||
| 1255 | |||
| 1256 | static void print_sample_synth_exstop(struct perf_sample *sample) | ||
| 1257 | { | ||
| 1258 | struct perf_synth_intel_exstop *data = perf_sample__synth_ptr(sample); | ||
| 1259 | int len; | ||
| 1260 | |||
| 1261 | if (perf_sample__bad_synth_size(sample, *data)) | ||
| 1262 | return; | ||
| 1263 | |||
| 1264 | len = printf(" IP: %u ", data->ip); | ||
| 1265 | print_sample_pt_spacing(len); | ||
| 1266 | } | ||
| 1267 | |||
| 1268 | static void print_sample_synth_pwrx(struct perf_sample *sample) | ||
| 1269 | { | ||
| 1270 | struct perf_synth_intel_pwrx *data = perf_sample__synth_ptr(sample); | ||
| 1271 | int len; | ||
| 1272 | |||
| 1273 | if (perf_sample__bad_synth_size(sample, *data)) | ||
| 1274 | return; | ||
| 1275 | |||
| 1276 | len = printf(" deepest cstate: %u last cstate: %u wake reason: %#x ", | ||
| 1277 | data->deepest_cstate, data->last_cstate, | ||
| 1278 | data->wake_reason); | ||
| 1279 | print_sample_pt_spacing(len); | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | static void print_sample_synth_cbr(struct perf_sample *sample) | ||
| 1283 | { | ||
| 1284 | struct perf_synth_intel_cbr *data = perf_sample__synth_ptr(sample); | ||
| 1285 | unsigned int percent, freq; | ||
| 1286 | int len; | ||
| 1287 | |||
| 1288 | if (perf_sample__bad_synth_size(sample, *data)) | ||
| 1289 | return; | ||
| 1290 | |||
| 1291 | freq = (le32_to_cpu(data->freq) + 500) / 1000; | ||
| 1292 | len = printf(" cbr: %2u freq: %4u MHz ", data->cbr, freq); | ||
| 1293 | if (data->max_nonturbo) { | ||
| 1294 | percent = (5 + (1000 * data->cbr) / data->max_nonturbo) / 10; | ||
| 1295 | len += printf("(%3u%%) ", percent); | ||
| 1296 | } | ||
| 1297 | print_sample_pt_spacing(len); | ||
| 1298 | } | ||
| 1299 | |||
| 1300 | static void print_sample_synth(struct perf_sample *sample, | ||
| 1301 | struct perf_evsel *evsel) | ||
| 1302 | { | ||
| 1303 | switch (evsel->attr.config) { | ||
| 1304 | case PERF_SYNTH_INTEL_PTWRITE: | ||
| 1305 | print_sample_synth_ptwrite(sample); | ||
| 1306 | break; | ||
| 1307 | case PERF_SYNTH_INTEL_MWAIT: | ||
| 1308 | print_sample_synth_mwait(sample); | ||
| 1309 | break; | ||
| 1310 | case PERF_SYNTH_INTEL_PWRE: | ||
| 1311 | print_sample_synth_pwre(sample); | ||
| 1312 | break; | ||
| 1313 | case PERF_SYNTH_INTEL_EXSTOP: | ||
| 1314 | print_sample_synth_exstop(sample); | ||
| 1315 | break; | ||
| 1316 | case PERF_SYNTH_INTEL_PWRX: | ||
| 1317 | print_sample_synth_pwrx(sample); | ||
| 1318 | break; | ||
| 1319 | case PERF_SYNTH_INTEL_CBR: | ||
| 1320 | print_sample_synth_cbr(sample); | ||
| 1321 | break; | ||
| 1322 | default: | ||
| 1323 | break; | ||
| 1324 | } | ||
| 1325 | } | ||
| 1326 | |||
| 1082 | struct perf_script { | 1327 | struct perf_script { |
| 1083 | struct perf_tool tool; | 1328 | struct perf_tool tool; |
| 1084 | struct perf_session *session; | 1329 | struct perf_session *session; |
| @@ -1132,8 +1377,9 @@ static void process_event(struct perf_script *script, | |||
| 1132 | { | 1377 | { |
| 1133 | struct thread *thread = al->thread; | 1378 | struct thread *thread = al->thread; |
| 1134 | struct perf_event_attr *attr = &evsel->attr; | 1379 | struct perf_event_attr *attr = &evsel->attr; |
| 1380 | unsigned int type = output_type(attr->type); | ||
| 1135 | 1381 | ||
| 1136 | if (output[attr->type].fields == 0) | 1382 | if (output[type].fields == 0) |
| 1137 | return; | 1383 | return; |
| 1138 | 1384 | ||
| 1139 | print_sample_start(sample, thread, evsel); | 1385 | print_sample_start(sample, thread, evsel); |
| @@ -1162,6 +1408,10 @@ static void process_event(struct perf_script *script, | |||
| 1162 | if (PRINT_FIELD(TRACE)) | 1408 | if (PRINT_FIELD(TRACE)) |
| 1163 | event_format__print(evsel->tp_format, sample->cpu, | 1409 | event_format__print(evsel->tp_format, sample->cpu, |
| 1164 | sample->raw_data, sample->raw_size); | 1410 | sample->raw_data, sample->raw_size); |
| 1411 | |||
| 1412 | if (attr->type == PERF_TYPE_SYNTH && PRINT_FIELD(SYNTH)) | ||
| 1413 | print_sample_synth(sample, evsel); | ||
| 1414 | |||
| 1165 | if (PRINT_FIELD(ADDR)) | 1415 | if (PRINT_FIELD(ADDR)) |
| 1166 | print_sample_addr(sample, thread, attr); | 1416 | print_sample_addr(sample, thread, attr); |
| 1167 | 1417 | ||
| @@ -1180,16 +1430,18 @@ static void process_event(struct perf_script *script, | |||
| 1180 | cursor = &callchain_cursor; | 1430 | cursor = &callchain_cursor; |
| 1181 | 1431 | ||
| 1182 | putchar(cursor ? '\n' : ' '); | 1432 | putchar(cursor ? '\n' : ' '); |
| 1183 | sample__fprintf_sym(sample, al, 0, output[attr->type].print_ip_opts, cursor, stdout); | 1433 | sample__fprintf_sym(sample, al, 0, output[type].print_ip_opts, cursor, stdout); |
| 1184 | } | 1434 | } |
| 1185 | 1435 | ||
| 1186 | if (PRINT_FIELD(IREGS)) | 1436 | if (PRINT_FIELD(IREGS)) |
| 1187 | print_sample_iregs(sample, attr); | 1437 | print_sample_iregs(sample, attr); |
| 1188 | 1438 | ||
| 1189 | if (PRINT_FIELD(BRSTACK)) | 1439 | if (PRINT_FIELD(BRSTACK)) |
| 1190 | print_sample_brstack(sample); | 1440 | print_sample_brstack(sample, thread, attr); |
| 1191 | else if (PRINT_FIELD(BRSTACKSYM)) | 1441 | else if (PRINT_FIELD(BRSTACKSYM)) |
| 1192 | print_sample_brstacksym(sample, thread); | 1442 | print_sample_brstacksym(sample, thread, attr); |
| 1443 | else if (PRINT_FIELD(BRSTACKOFF)) | ||
| 1444 | print_sample_brstackoff(sample, thread, attr); | ||
| 1193 | 1445 | ||
| 1194 | if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) | 1446 | if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) |
| 1195 | print_sample_bpf_output(sample); | 1447 | print_sample_bpf_output(sample); |
| @@ -1325,7 +1577,8 @@ static int process_attr(struct perf_tool *tool, union perf_event *event, | |||
| 1325 | evlist = *pevlist; | 1577 | evlist = *pevlist; |
| 1326 | evsel = perf_evlist__last(*pevlist); | 1578 | evsel = perf_evlist__last(*pevlist); |
| 1327 | 1579 | ||
| 1328 | if (evsel->attr.type >= PERF_TYPE_MAX) | 1580 | if (evsel->attr.type >= PERF_TYPE_MAX && |
| 1581 | evsel->attr.type != PERF_TYPE_SYNTH) | ||
| 1329 | return 0; | 1582 | return 0; |
| 1330 | 1583 | ||
| 1331 | evlist__for_each_entry(evlist, pos) { | 1584 | evlist__for_each_entry(evlist, pos) { |
| @@ -1727,6 +1980,7 @@ static int parse_output_fields(const struct option *opt __maybe_unused, | |||
| 1727 | int rc = 0; | 1980 | int rc = 0; |
| 1728 | char *str = strdup(arg); | 1981 | char *str = strdup(arg); |
| 1729 | int type = -1; | 1982 | int type = -1; |
| 1983 | enum { DEFAULT, SET, ADD, REMOVE } change = DEFAULT; | ||
| 1730 | 1984 | ||
| 1731 | if (!str) | 1985 | if (!str) |
| 1732 | return -ENOMEM; | 1986 | return -ENOMEM; |
| @@ -1749,6 +2003,8 @@ static int parse_output_fields(const struct option *opt __maybe_unused, | |||
| 1749 | type = PERF_TYPE_RAW; | 2003 | type = PERF_TYPE_RAW; |
| 1750 | else if (!strcmp(str, "break")) | 2004 | else if (!strcmp(str, "break")) |
| 1751 | type = PERF_TYPE_BREAKPOINT; | 2005 | type = PERF_TYPE_BREAKPOINT; |
| 2006 | else if (!strcmp(str, "synth")) | ||
| 2007 | type = OUTPUT_TYPE_SYNTH; | ||
| 1752 | else { | 2008 | else { |
| 1753 | fprintf(stderr, "Invalid event type in field string.\n"); | 2009 | fprintf(stderr, "Invalid event type in field string.\n"); |
| 1754 | rc = -EINVAL; | 2010 | rc = -EINVAL; |
| @@ -1772,23 +2028,44 @@ static int parse_output_fields(const struct option *opt __maybe_unused, | |||
| 1772 | goto out; | 2028 | goto out; |
| 1773 | } | 2029 | } |
| 1774 | 2030 | ||
| 2031 | /* Don't override defaults for +- */ | ||
| 2032 | if (strchr(str, '+') || strchr(str, '-')) | ||
| 2033 | goto parse; | ||
| 2034 | |||
| 1775 | if (output_set_by_user()) | 2035 | if (output_set_by_user()) |
| 1776 | pr_warning("Overriding previous field request for all events.\n"); | 2036 | pr_warning("Overriding previous field request for all events.\n"); |
| 1777 | 2037 | ||
| 1778 | for (j = 0; j < PERF_TYPE_MAX; ++j) { | 2038 | for (j = 0; j < OUTPUT_TYPE_MAX; ++j) { |
| 1779 | output[j].fields = 0; | 2039 | output[j].fields = 0; |
| 1780 | output[j].user_set = true; | 2040 | output[j].user_set = true; |
| 1781 | output[j].wildcard_set = true; | 2041 | output[j].wildcard_set = true; |
| 1782 | } | 2042 | } |
| 1783 | } | 2043 | } |
| 1784 | 2044 | ||
| 2045 | parse: | ||
| 1785 | for (tok = strtok_r(tok, ",", &strtok_saveptr); tok; tok = strtok_r(NULL, ",", &strtok_saveptr)) { | 2046 | for (tok = strtok_r(tok, ",", &strtok_saveptr); tok; tok = strtok_r(NULL, ",", &strtok_saveptr)) { |
| 2047 | if (*tok == '+') { | ||
| 2048 | if (change == SET) | ||
| 2049 | goto out_badmix; | ||
| 2050 | change = ADD; | ||
| 2051 | tok++; | ||
| 2052 | } else if (*tok == '-') { | ||
| 2053 | if (change == SET) | ||
| 2054 | goto out_badmix; | ||
| 2055 | change = REMOVE; | ||
| 2056 | tok++; | ||
| 2057 | } else { | ||
| 2058 | if (change != SET && change != DEFAULT) | ||
| 2059 | goto out_badmix; | ||
| 2060 | change = SET; | ||
| 2061 | } | ||
| 2062 | |||
| 1786 | for (i = 0; i < imax; ++i) { | 2063 | for (i = 0; i < imax; ++i) { |
| 1787 | if (strcmp(tok, all_output_options[i].str) == 0) | 2064 | if (strcmp(tok, all_output_options[i].str) == 0) |
| 1788 | break; | 2065 | break; |
| 1789 | } | 2066 | } |
| 1790 | if (i == imax && strcmp(tok, "flags") == 0) { | 2067 | if (i == imax && strcmp(tok, "flags") == 0) { |
| 1791 | print_flags = true; | 2068 | print_flags = change == REMOVE ? false : true; |
| 1792 | continue; | 2069 | continue; |
| 1793 | } | 2070 | } |
| 1794 | if (i == imax) { | 2071 | if (i == imax) { |
| @@ -1801,12 +2078,16 @@ static int parse_output_fields(const struct option *opt __maybe_unused, | |||
| 1801 | /* add user option to all events types for | 2078 | /* add user option to all events types for |
| 1802 | * which it is valid | 2079 | * which it is valid |
| 1803 | */ | 2080 | */ |
| 1804 | for (j = 0; j < PERF_TYPE_MAX; ++j) { | 2081 | for (j = 0; j < OUTPUT_TYPE_MAX; ++j) { |
| 1805 | if (output[j].invalid_fields & all_output_options[i].field) { | 2082 | if (output[j].invalid_fields & all_output_options[i].field) { |
| 1806 | pr_warning("\'%s\' not valid for %s events. Ignoring.\n", | 2083 | pr_warning("\'%s\' not valid for %s events. Ignoring.\n", |
| 1807 | all_output_options[i].str, event_type(j)); | 2084 | all_output_options[i].str, event_type(j)); |
| 1808 | } else | 2085 | } else { |
| 1809 | output[j].fields |= all_output_options[i].field; | 2086 | if (change == REMOVE) |
| 2087 | output[j].fields &= ~all_output_options[i].field; | ||
| 2088 | else | ||
| 2089 | output[j].fields |= all_output_options[i].field; | ||
| 2090 | } | ||
| 1810 | } | 2091 | } |
| 1811 | } else { | 2092 | } else { |
| 1812 | if (output[type].invalid_fields & all_output_options[i].field) { | 2093 | if (output[type].invalid_fields & all_output_options[i].field) { |
| @@ -1826,7 +2107,11 @@ static int parse_output_fields(const struct option *opt __maybe_unused, | |||
| 1826 | "Events will not be displayed.\n", event_type(type)); | 2107 | "Events will not be displayed.\n", event_type(type)); |
| 1827 | } | 2108 | } |
| 1828 | } | 2109 | } |
| 2110 | goto out; | ||
| 1829 | 2111 | ||
| 2112 | out_badmix: | ||
| 2113 | fprintf(stderr, "Cannot mix +-field with overridden fields\n"); | ||
| 2114 | rc = -EINVAL; | ||
| 1830 | out: | 2115 | out: |
| 1831 | free(str); | 2116 | free(str); |
| 1832 | return rc; | 2117 | return rc; |
| @@ -2444,10 +2729,11 @@ int cmd_script(int argc, const char **argv) | |||
| 2444 | symbol__config_symfs), | 2729 | symbol__config_symfs), |
| 2445 | OPT_CALLBACK('F', "fields", NULL, "str", | 2730 | OPT_CALLBACK('F', "fields", NULL, "str", |
| 2446 | "comma separated output fields prepend with 'type:'. " | 2731 | "comma separated output fields prepend with 'type:'. " |
| 2447 | "Valid types: hw,sw,trace,raw. " | 2732 | "+field to add and -field to remove." |
| 2733 | "Valid types: hw,sw,trace,raw,synth. " | ||
| 2448 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," | 2734 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," |
| 2449 | "addr,symoff,period,iregs,brstack,brstacksym,flags," | 2735 | "addr,symoff,period,iregs,brstack,brstacksym,flags," |
| 2450 | "bpf-output,callindent,insn,insnlen,brstackinsn", | 2736 | "bpf-output,callindent,insn,insnlen,brstackinsn,synth", |
| 2451 | parse_output_fields), | 2737 | parse_output_fields), |
| 2452 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 2738 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
| 2453 | "system-wide collection from all CPUs"), | 2739 | "system-wide collection from all CPUs"), |
| @@ -2706,6 +2992,7 @@ int cmd_script(int argc, const char **argv) | |||
| 2706 | err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); | 2992 | err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); |
| 2707 | if (err < 0) | 2993 | if (err < 0) |
| 2708 | goto out_delete; | 2994 | goto out_delete; |
| 2995 | itrace_synth_opts.cpu_bitmap = cpu_bitmap; | ||
| 2709 | } | 2996 | } |
| 2710 | 2997 | ||
| 2711 | if (!no_callchain) | 2998 | if (!no_callchain) |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index ad9324d1daf9..48ac53b199fc 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
| @@ -86,6 +86,7 @@ | |||
| 86 | #define DEFAULT_SEPARATOR " " | 86 | #define DEFAULT_SEPARATOR " " |
| 87 | #define CNTR_NOT_SUPPORTED "<not supported>" | 87 | #define CNTR_NOT_SUPPORTED "<not supported>" |
| 88 | #define CNTR_NOT_COUNTED "<not counted>" | 88 | #define CNTR_NOT_COUNTED "<not counted>" |
| 89 | #define FREEZE_ON_SMI_PATH "devices/cpu/freeze_on_smi" | ||
| 89 | 90 | ||
| 90 | static void print_counters(struct timespec *ts, int argc, const char **argv); | 91 | static void print_counters(struct timespec *ts, int argc, const char **argv); |
| 91 | 92 | ||
| @@ -122,6 +123,14 @@ static const char * topdown_attrs[] = { | |||
| 122 | NULL, | 123 | NULL, |
| 123 | }; | 124 | }; |
| 124 | 125 | ||
| 126 | static const char *smi_cost_attrs = { | ||
| 127 | "{" | ||
| 128 | "msr/aperf/," | ||
| 129 | "msr/smi/," | ||
| 130 | "cycles" | ||
| 131 | "}" | ||
| 132 | }; | ||
| 133 | |||
| 125 | static struct perf_evlist *evsel_list; | 134 | static struct perf_evlist *evsel_list; |
| 126 | 135 | ||
| 127 | static struct target target = { | 136 | static struct target target = { |
| @@ -137,6 +146,8 @@ static bool null_run = false; | |||
| 137 | static int detailed_run = 0; | 146 | static int detailed_run = 0; |
| 138 | static bool transaction_run; | 147 | static bool transaction_run; |
| 139 | static bool topdown_run = false; | 148 | static bool topdown_run = false; |
| 149 | static bool smi_cost = false; | ||
| 150 | static bool smi_reset = false; | ||
| 140 | static bool big_num = true; | 151 | static bool big_num = true; |
| 141 | static int big_num_opt = -1; | 152 | static int big_num_opt = -1; |
| 142 | static const char *csv_sep = NULL; | 153 | static const char *csv_sep = NULL; |
| @@ -625,14 +636,14 @@ try_again: | |||
| 625 | } | 636 | } |
| 626 | 637 | ||
| 627 | if (perf_evlist__apply_filters(evsel_list, &counter)) { | 638 | if (perf_evlist__apply_filters(evsel_list, &counter)) { |
| 628 | error("failed to set filter \"%s\" on event %s with %d (%s)\n", | 639 | pr_err("failed to set filter \"%s\" on event %s with %d (%s)\n", |
| 629 | counter->filter, perf_evsel__name(counter), errno, | 640 | counter->filter, perf_evsel__name(counter), errno, |
| 630 | str_error_r(errno, msg, sizeof(msg))); | 641 | str_error_r(errno, msg, sizeof(msg))); |
| 631 | return -1; | 642 | return -1; |
| 632 | } | 643 | } |
| 633 | 644 | ||
| 634 | if (perf_evlist__apply_drv_configs(evsel_list, &counter, &err_term)) { | 645 | if (perf_evlist__apply_drv_configs(evsel_list, &counter, &err_term)) { |
| 635 | error("failed to set config \"%s\" on event %s with %d (%s)\n", | 646 | pr_err("failed to set config \"%s\" on event %s with %d (%s)\n", |
| 636 | err_term->val.drv_cfg, perf_evsel__name(counter), errno, | 647 | err_term->val.drv_cfg, perf_evsel__name(counter), errno, |
| 637 | str_error_r(errno, msg, sizeof(msg))); | 648 | str_error_r(errno, msg, sizeof(msg))); |
| 638 | return -1; | 649 | return -1; |
| @@ -1782,6 +1793,8 @@ static const struct option stat_options[] = { | |||
| 1782 | "Only print computed metrics. No raw values", enable_metric_only), | 1793 | "Only print computed metrics. No raw values", enable_metric_only), |
| 1783 | OPT_BOOLEAN(0, "topdown", &topdown_run, | 1794 | OPT_BOOLEAN(0, "topdown", &topdown_run, |
| 1784 | "measure topdown level 1 statistics"), | 1795 | "measure topdown level 1 statistics"), |
| 1796 | OPT_BOOLEAN(0, "smi-cost", &smi_cost, | ||
| 1797 | "measure SMI cost"), | ||
| 1785 | OPT_END() | 1798 | OPT_END() |
| 1786 | }; | 1799 | }; |
| 1787 | 1800 | ||
| @@ -2160,6 +2173,39 @@ static int add_default_attributes(void) | |||
| 2160 | return 0; | 2173 | return 0; |
| 2161 | } | 2174 | } |
| 2162 | 2175 | ||
| 2176 | if (smi_cost) { | ||
| 2177 | int smi; | ||
| 2178 | |||
| 2179 | if (sysfs__read_int(FREEZE_ON_SMI_PATH, &smi) < 0) { | ||
| 2180 | fprintf(stderr, "freeze_on_smi is not supported.\n"); | ||
| 2181 | return -1; | ||
| 2182 | } | ||
| 2183 | |||
| 2184 | if (!smi) { | ||
| 2185 | if (sysfs__write_int(FREEZE_ON_SMI_PATH, 1) < 0) { | ||
| 2186 | fprintf(stderr, "Failed to set freeze_on_smi.\n"); | ||
| 2187 | return -1; | ||
| 2188 | } | ||
| 2189 | smi_reset = true; | ||
| 2190 | } | ||
| 2191 | |||
| 2192 | if (pmu_have_event("msr", "aperf") && | ||
| 2193 | pmu_have_event("msr", "smi")) { | ||
| 2194 | if (!force_metric_only) | ||
| 2195 | metric_only = true; | ||
| 2196 | err = parse_events(evsel_list, smi_cost_attrs, NULL); | ||
| 2197 | } else { | ||
| 2198 | fprintf(stderr, "To measure SMI cost, it needs " | ||
| 2199 | "msr/aperf/, msr/smi/ and cpu/cycles/ support\n"); | ||
| 2200 | return -1; | ||
| 2201 | } | ||
| 2202 | if (err) { | ||
| 2203 | fprintf(stderr, "Cannot set up SMI cost events\n"); | ||
| 2204 | return -1; | ||
| 2205 | } | ||
| 2206 | return 0; | ||
| 2207 | } | ||
| 2208 | |||
| 2163 | if (topdown_run) { | 2209 | if (topdown_run) { |
| 2164 | char *str = NULL; | 2210 | char *str = NULL; |
| 2165 | bool warn = false; | 2211 | bool warn = false; |
| @@ -2742,6 +2788,9 @@ int cmd_stat(int argc, const char **argv) | |||
| 2742 | perf_stat__exit_aggr_mode(); | 2788 | perf_stat__exit_aggr_mode(); |
| 2743 | perf_evlist__free_stats(evsel_list); | 2789 | perf_evlist__free_stats(evsel_list); |
| 2744 | out: | 2790 | out: |
| 2791 | if (smi_cost && smi_reset) | ||
| 2792 | sysfs__write_int(FREEZE_ON_SMI_PATH, 0); | ||
| 2793 | |||
| 2745 | perf_evlist__delete(evsel_list); | 2794 | perf_evlist__delete(evsel_list); |
| 2746 | return status; | 2795 | return status; |
| 2747 | } | 2796 | } |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 10b6362ca0bf..6052376634c0 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -134,7 +134,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) | |||
| 134 | return err; | 134 | return err; |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | err = symbol__disassemble(sym, map, NULL, 0); | 137 | err = symbol__disassemble(sym, map, NULL, 0, NULL); |
| 138 | if (err == 0) { | 138 | if (err == 0) { |
| 139 | out_assign: | 139 | out_assign: |
| 140 | top->sym_filter_entry = he; | 140 | top->sym_filter_entry = he; |
| @@ -958,7 +958,7 @@ static int __cmd_top(struct perf_top *top) | |||
| 958 | 958 | ||
| 959 | ret = perf_evlist__apply_drv_configs(evlist, &pos, &err_term); | 959 | ret = perf_evlist__apply_drv_configs(evlist, &pos, &err_term); |
| 960 | if (ret) { | 960 | if (ret) { |
| 961 | error("failed to set config \"%s\" on event %s with %d (%s)\n", | 961 | pr_err("failed to set config \"%s\" on event %s with %d (%s)\n", |
| 962 | err_term->val.drv_cfg, perf_evsel__name(pos), errno, | 962 | err_term->val.drv_cfg, perf_evsel__name(pos), errno, |
| 963 | str_error_r(errno, msg, sizeof(msg))); | 963 | str_error_r(errno, msg, sizeof(msg))); |
| 964 | goto out_delete; | 964 | goto out_delete; |
diff --git a/tools/perf/jvmti/jvmti_agent.c b/tools/perf/jvmti/jvmti_agent.c index e9651a9d670e..cf36de7ea255 100644 --- a/tools/perf/jvmti/jvmti_agent.c +++ b/tools/perf/jvmti/jvmti_agent.c | |||
| @@ -304,7 +304,7 @@ jvmti_close(void *agent) | |||
| 304 | FILE *fp = agent; | 304 | FILE *fp = agent; |
| 305 | 305 | ||
| 306 | if (!fp) { | 306 | if (!fp) { |
| 307 | warnx("jvmti: incalid fd in close_agent"); | 307 | warnx("jvmti: invalid fd in close_agent"); |
| 308 | return -1; | 308 | return -1; |
| 309 | } | 309 | } |
| 310 | 310 | ||
diff --git a/tools/perf/jvmti/jvmti_agent.h b/tools/perf/jvmti/jvmti_agent.h index bedf5d0ba9ff..c53a41f48b63 100644 --- a/tools/perf/jvmti/jvmti_agent.h +++ b/tools/perf/jvmti/jvmti_agent.h | |||
| @@ -5,8 +5,6 @@ | |||
| 5 | #include <stdint.h> | 5 | #include <stdint.h> |
| 6 | #include <jvmti.h> | 6 | #include <jvmti.h> |
| 7 | 7 | ||
| 8 | #define __unused __attribute__((unused)) | ||
| 9 | |||
| 10 | #if defined(__cplusplus) | 8 | #if defined(__cplusplus) |
| 11 | extern "C" { | 9 | extern "C" { |
| 12 | #endif | 10 | #endif |
diff --git a/tools/perf/jvmti/libjvmti.c b/tools/perf/jvmti/libjvmti.c index 5612641c69b4..6d710904c837 100644 --- a/tools/perf/jvmti/libjvmti.c +++ b/tools/perf/jvmti/libjvmti.c | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | #include <linux/compiler.h> | ||
| 1 | #include <sys/types.h> | 2 | #include <sys/types.h> |
| 2 | #include <stdio.h> | 3 | #include <stdio.h> |
| 3 | #include <string.h> | 4 | #include <string.h> |
| @@ -238,7 +239,7 @@ code_generated_cb(jvmtiEnv *jvmti, | |||
| 238 | } | 239 | } |
| 239 | 240 | ||
| 240 | JNIEXPORT jint JNICALL | 241 | JNIEXPORT jint JNICALL |
| 241 | Agent_OnLoad(JavaVM *jvm, char *options, void *reserved __unused) | 242 | Agent_OnLoad(JavaVM *jvm, char *options, void *reserved __maybe_unused) |
| 242 | { | 243 | { |
| 243 | jvmtiEventCallbacks cb; | 244 | jvmtiEventCallbacks cb; |
| 244 | jvmtiCapabilities caps1; | 245 | jvmtiCapabilities caps1; |
| @@ -313,7 +314,7 @@ Agent_OnLoad(JavaVM *jvm, char *options, void *reserved __unused) | |||
| 313 | } | 314 | } |
| 314 | 315 | ||
| 315 | JNIEXPORT void JNICALL | 316 | JNIEXPORT void JNICALL |
| 316 | Agent_OnUnload(JavaVM *jvm __unused) | 317 | Agent_OnUnload(JavaVM *jvm __maybe_unused) |
| 317 | { | 318 | { |
| 318 | int ret; | 319 | int ret; |
| 319 | 320 | ||
diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c index baa073f38334..bd0aabb2bd0f 100644 --- a/tools/perf/pmu-events/jevents.c +++ b/tools/perf/pmu-events/jevents.c | |||
| @@ -48,10 +48,6 @@ | |||
| 48 | #include "json.h" | 48 | #include "json.h" |
| 49 | #include "jevents.h" | 49 | #include "jevents.h" |
| 50 | 50 | ||
| 51 | #ifndef __maybe_unused | ||
| 52 | #define __maybe_unused __attribute__((unused)) | ||
| 53 | #endif | ||
| 54 | |||
| 55 | int verbose; | 51 | int verbose; |
| 56 | char *prog; | 52 | char *prog; |
| 57 | 53 | ||
diff --git a/tools/perf/scripts/python/bin/intel-pt-events-record b/tools/perf/scripts/python/bin/intel-pt-events-record new file mode 100644 index 000000000000..10fe2b6977d4 --- /dev/null +++ b/tools/perf/scripts/python/bin/intel-pt-events-record | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | |||
| 3 | # | ||
| 4 | # print Intel PT Power Events and PTWRITE. The intel_pt PMU event needs | ||
| 5 | # to be specified with appropriate config terms. | ||
| 6 | # | ||
| 7 | if ! echo "$@" | grep -q intel_pt ; then | ||
| 8 | echo "Options must include the Intel PT event e.g. -e intel_pt/pwr_evt,ptw/" | ||
| 9 | echo "and for power events it probably needs to be system wide i.e. -a option" | ||
| 10 | echo "For example: -a -e intel_pt/pwr_evt,branch=0/ sleep 1" | ||
| 11 | exit 1 | ||
| 12 | fi | ||
| 13 | perf record $@ | ||
diff --git a/tools/perf/scripts/python/bin/intel-pt-events-report b/tools/perf/scripts/python/bin/intel-pt-events-report new file mode 100644 index 000000000000..9a9c92fcd026 --- /dev/null +++ b/tools/perf/scripts/python/bin/intel-pt-events-report | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | # description: print Intel PT Power Events and PTWRITE | ||
| 3 | perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/intel-pt-events.py \ No newline at end of file | ||
diff --git a/tools/perf/scripts/python/intel-pt-events.py b/tools/perf/scripts/python/intel-pt-events.py new file mode 100644 index 000000000000..b19172d673af --- /dev/null +++ b/tools/perf/scripts/python/intel-pt-events.py | |||
| @@ -0,0 +1,128 @@ | |||
| 1 | # intel-pt-events.py: Print Intel PT Power Events and PTWRITE | ||
| 2 | # Copyright (c) 2017, Intel Corporation. | ||
| 3 | # | ||
| 4 | # This program is free software; you can redistribute it and/or modify it | ||
| 5 | # under the terms and conditions of the GNU General Public License, | ||
| 6 | # version 2, as published by the Free Software Foundation. | ||
| 7 | # | ||
| 8 | # This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | # more details. | ||
| 12 | |||
| 13 | import os | ||
| 14 | import sys | ||
| 15 | import struct | ||
| 16 | |||
| 17 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | ||
| 18 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') | ||
| 19 | |||
| 20 | # These perf imports are not used at present | ||
| 21 | #from perf_trace_context import * | ||
| 22 | #from Core import * | ||
| 23 | |||
| 24 | def trace_begin(): | ||
| 25 | print "Intel PT Power Events and PTWRITE" | ||
| 26 | |||
| 27 | def trace_end(): | ||
| 28 | print "End" | ||
| 29 | |||
| 30 | def trace_unhandled(event_name, context, event_fields_dict): | ||
| 31 | print ' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())]) | ||
| 32 | |||
| 33 | def print_ptwrite(raw_buf): | ||
| 34 | data = struct.unpack_from("<IQ", raw_buf) | ||
| 35 | flags = data[0] | ||
| 36 | payload = data[1] | ||
| 37 | exact_ip = flags & 1 | ||
| 38 | print "IP: %u payload: %#x" % (exact_ip, payload), | ||
| 39 | |||
| 40 | def print_cbr(raw_buf): | ||
| 41 | data = struct.unpack_from("<BBBBII", raw_buf) | ||
| 42 | cbr = data[0] | ||
| 43 | f = (data[4] + 500) / 1000 | ||
| 44 | p = ((cbr * 1000 / data[2]) + 5) / 10 | ||
| 45 | print "%3u freq: %4u MHz (%3u%%)" % (cbr, f, p), | ||
| 46 | |||
| 47 | def print_mwait(raw_buf): | ||
| 48 | data = struct.unpack_from("<IQ", raw_buf) | ||
| 49 | payload = data[1] | ||
| 50 | hints = payload & 0xff | ||
| 51 | extensions = (payload >> 32) & 0x3 | ||
| 52 | print "hints: %#x extensions: %#x" % (hints, extensions), | ||
| 53 | |||
| 54 | def print_pwre(raw_buf): | ||
| 55 | data = struct.unpack_from("<IQ", raw_buf) | ||
| 56 | payload = data[1] | ||
| 57 | hw = (payload >> 7) & 1 | ||
| 58 | cstate = (payload >> 12) & 0xf | ||
| 59 | subcstate = (payload >> 8) & 0xf | ||
| 60 | print "hw: %u cstate: %u sub-cstate: %u" % (hw, cstate, subcstate), | ||
| 61 | |||
| 62 | def print_exstop(raw_buf): | ||
| 63 | data = struct.unpack_from("<I", raw_buf) | ||
| 64 | flags = data[0] | ||
| 65 | exact_ip = flags & 1 | ||
| 66 | print "IP: %u" % (exact_ip), | ||
| 67 | |||
| 68 | def print_pwrx(raw_buf): | ||
| 69 | data = struct.unpack_from("<IQ", raw_buf) | ||
| 70 | payload = data[1] | ||
| 71 | deepest_cstate = payload & 0xf | ||
| 72 | last_cstate = (payload >> 4) & 0xf | ||
| 73 | wake_reason = (payload >> 8) & 0xf | ||
| 74 | print "deepest cstate: %u last cstate: %u wake reason: %#x" % (deepest_cstate, last_cstate, wake_reason), | ||
| 75 | |||
| 76 | def print_common_start(comm, sample, name): | ||
| 77 | ts = sample["time"] | ||
| 78 | cpu = sample["cpu"] | ||
| 79 | pid = sample["pid"] | ||
| 80 | tid = sample["tid"] | ||
| 81 | print "%16s %5u/%-5u [%03u] %9u.%09u %7s:" % (comm, pid, tid, cpu, ts / 1000000000, ts %1000000000, name), | ||
| 82 | |||
| 83 | def print_common_ip(sample, symbol, dso): | ||
| 84 | ip = sample["ip"] | ||
| 85 | print "%16x %s (%s)" % (ip, symbol, dso) | ||
| 86 | |||
| 87 | def process_event(param_dict): | ||
| 88 | event_attr = param_dict["attr"] | ||
| 89 | sample = param_dict["sample"] | ||
| 90 | raw_buf = param_dict["raw_buf"] | ||
| 91 | comm = param_dict["comm"] | ||
| 92 | name = param_dict["ev_name"] | ||
| 93 | |||
| 94 | # Symbol and dso info are not always resolved | ||
| 95 | if (param_dict.has_key("dso")): | ||
| 96 | dso = param_dict["dso"] | ||
| 97 | else: | ||
| 98 | dso = "[unknown]" | ||
| 99 | |||
| 100 | if (param_dict.has_key("symbol")): | ||
| 101 | symbol = param_dict["symbol"] | ||
| 102 | else: | ||
| 103 | symbol = "[unknown]" | ||
| 104 | |||
| 105 | if name == "ptwrite": | ||
| 106 | print_common_start(comm, sample, name) | ||
| 107 | print_ptwrite(raw_buf) | ||
| 108 | print_common_ip(sample, symbol, dso) | ||
| 109 | elif name == "cbr": | ||
| 110 | print_common_start(comm, sample, name) | ||
| 111 | print_cbr(raw_buf) | ||
| 112 | print_common_ip(sample, symbol, dso) | ||
| 113 | elif name == "mwait": | ||
| 114 | print_common_start(comm, sample, name) | ||
| 115 | print_mwait(raw_buf) | ||
| 116 | print_common_ip(sample, symbol, dso) | ||
| 117 | elif name == "pwre": | ||
| 118 | print_common_start(comm, sample, name) | ||
| 119 | print_pwre(raw_buf) | ||
| 120 | print_common_ip(sample, symbol, dso) | ||
| 121 | elif name == "exstop": | ||
| 122 | print_common_start(comm, sample, name) | ||
| 123 | print_exstop(raw_buf) | ||
| 124 | print_common_ip(sample, symbol, dso) | ||
| 125 | elif name == "pwrx": | ||
| 126 | print_common_start(comm, sample, name) | ||
| 127 | print_pwrx(raw_buf) | ||
| 128 | print_common_ip(sample, symbol, dso) | ||
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c index 0dd77494bb58..0e77b2cf61ec 100644 --- a/tools/perf/tests/attr.c +++ b/tools/perf/tests/attr.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | * permissions. All the event text files are stored there. | 18 | * permissions. All the event text files are stored there. |
| 19 | */ | 19 | */ |
| 20 | 20 | ||
| 21 | #include <debug.h> | ||
| 21 | #include <errno.h> | 22 | #include <errno.h> |
| 22 | #include <inttypes.h> | 23 | #include <inttypes.h> |
| 23 | #include <stdlib.h> | 24 | #include <stdlib.h> |
| @@ -29,14 +30,11 @@ | |||
| 29 | #include <sys/stat.h> | 30 | #include <sys/stat.h> |
| 30 | #include <unistd.h> | 31 | #include <unistd.h> |
| 31 | #include "../perf.h" | 32 | #include "../perf.h" |
| 32 | #include "util.h" | ||
| 33 | #include <subcmd/exec-cmd.h> | 33 | #include <subcmd/exec-cmd.h> |
| 34 | #include "tests.h" | 34 | #include "tests.h" |
| 35 | 35 | ||
| 36 | #define ENV "PERF_TEST_ATTR" | 36 | #define ENV "PERF_TEST_ATTR" |
| 37 | 37 | ||
| 38 | extern int verbose; | ||
| 39 | |||
| 40 | static char *dir; | 38 | static char *dir; |
| 41 | 39 | ||
| 42 | void test_attr__init(void) | 40 | void test_attr__init(void) |
| @@ -138,8 +136,10 @@ void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu, | |||
| 138 | { | 136 | { |
| 139 | int errno_saved = errno; | 137 | int errno_saved = errno; |
| 140 | 138 | ||
| 141 | if (store_event(attr, pid, cpu, fd, group_fd, flags)) | 139 | if (store_event(attr, pid, cpu, fd, group_fd, flags)) { |
| 142 | die("test attr FAILED"); | 140 | pr_err("test attr FAILED"); |
| 141 | exit(128); | ||
| 142 | } | ||
| 143 | 143 | ||
| 144 | errno = errno_saved; | 144 | errno = errno_saved; |
| 145 | } | 145 | } |
diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/attr.py index 1091bd47adfd..cdf21a9d0c35 100644 --- a/tools/perf/tests/attr.py +++ b/tools/perf/tests/attr.py | |||
| @@ -16,6 +16,13 @@ class Fail(Exception): | |||
| 16 | def getMsg(self): | 16 | def getMsg(self): |
| 17 | return '\'%s\' - %s' % (self.test.path, self.msg) | 17 | return '\'%s\' - %s' % (self.test.path, self.msg) |
| 18 | 18 | ||
| 19 | class Notest(Exception): | ||
| 20 | def __init__(self, test, arch): | ||
| 21 | self.arch = arch | ||
| 22 | self.test = test | ||
| 23 | def getMsg(self): | ||
| 24 | return '[%s] \'%s\'' % (self.arch, self.test.path) | ||
| 25 | |||
| 19 | class Unsup(Exception): | 26 | class Unsup(Exception): |
| 20 | def __init__(self, test): | 27 | def __init__(self, test): |
| 21 | self.test = test | 28 | self.test = test |
| @@ -112,6 +119,9 @@ class Event(dict): | |||
| 112 | # 'command' - perf command name | 119 | # 'command' - perf command name |
| 113 | # 'args' - special command arguments | 120 | # 'args' - special command arguments |
| 114 | # 'ret' - expected command return value (0 by default) | 121 | # 'ret' - expected command return value (0 by default) |
| 122 | # 'arch' - architecture specific test (optional) | ||
| 123 | # comma separated list, ! at the beginning | ||
| 124 | # negates it. | ||
| 115 | # | 125 | # |
| 116 | # [eventX:base] | 126 | # [eventX:base] |
| 117 | # - one or multiple instances in file | 127 | # - one or multiple instances in file |
| @@ -134,6 +144,12 @@ class Test(object): | |||
| 134 | except: | 144 | except: |
| 135 | self.ret = 0 | 145 | self.ret = 0 |
| 136 | 146 | ||
| 147 | try: | ||
| 148 | self.arch = parser.get('config', 'arch') | ||
| 149 | log.warning("test limitation '%s'" % self.arch) | ||
| 150 | except: | ||
| 151 | self.arch = '' | ||
| 152 | |||
| 137 | self.expect = {} | 153 | self.expect = {} |
| 138 | self.result = {} | 154 | self.result = {} |
| 139 | log.debug(" loading expected events"); | 155 | log.debug(" loading expected events"); |
| @@ -145,6 +161,31 @@ class Test(object): | |||
| 145 | else: | 161 | else: |
| 146 | return True | 162 | return True |
| 147 | 163 | ||
| 164 | def skip_test(self, myarch): | ||
| 165 | # If architecture not set always run test | ||
| 166 | if self.arch == '': | ||
| 167 | # log.warning("test for arch %s is ok" % myarch) | ||
| 168 | return False | ||
| 169 | |||
| 170 | # Allow multiple values in assignment separated by ',' | ||
| 171 | arch_list = self.arch.split(',') | ||
| 172 | |||
| 173 | # Handle negated list such as !s390x,ppc | ||
| 174 | if arch_list[0][0] == '!': | ||
| 175 | arch_list[0] = arch_list[0][1:] | ||
| 176 | log.warning("excluded architecture list %s" % arch_list) | ||
| 177 | for arch_item in arch_list: | ||
| 178 | # log.warning("test for %s arch is %s" % (arch_item, myarch)) | ||
| 179 | if arch_item == myarch: | ||
| 180 | return True | ||
| 181 | return False | ||
| 182 | |||
| 183 | for arch_item in arch_list: | ||
| 184 | # log.warning("test for architecture '%s' current '%s'" % (arch_item, myarch)) | ||
| 185 | if arch_item == myarch: | ||
| 186 | return False | ||
| 187 | return True | ||
| 188 | |||
| 148 | def load_events(self, path, events): | 189 | def load_events(self, path, events): |
| 149 | parser_event = ConfigParser.SafeConfigParser() | 190 | parser_event = ConfigParser.SafeConfigParser() |
| 150 | parser_event.read(path) | 191 | parser_event.read(path) |
| @@ -168,6 +209,11 @@ class Test(object): | |||
| 168 | events[section] = e | 209 | events[section] = e |
| 169 | 210 | ||
| 170 | def run_cmd(self, tempdir): | 211 | def run_cmd(self, tempdir): |
| 212 | junk1, junk2, junk3, junk4, myarch = (os.uname()) | ||
| 213 | |||
| 214 | if self.skip_test(myarch): | ||
| 215 | raise Notest(self, myarch) | ||
| 216 | |||
| 171 | cmd = "PERF_TEST_ATTR=%s %s %s -o %s/perf.data %s" % (tempdir, | 217 | cmd = "PERF_TEST_ATTR=%s %s %s -o %s/perf.data %s" % (tempdir, |
| 172 | self.perf, self.command, tempdir, self.args) | 218 | self.perf, self.command, tempdir, self.args) |
| 173 | ret = os.WEXITSTATUS(os.system(cmd)) | 219 | ret = os.WEXITSTATUS(os.system(cmd)) |
| @@ -265,6 +311,8 @@ def run_tests(options): | |||
| 265 | Test(f, options).run() | 311 | Test(f, options).run() |
| 266 | except Unsup, obj: | 312 | except Unsup, obj: |
| 267 | log.warning("unsupp %s" % obj.getMsg()) | 313 | log.warning("unsupp %s" % obj.getMsg()) |
| 314 | except Notest, obj: | ||
| 315 | log.warning("skipped %s" % obj.getMsg()) | ||
| 268 | 316 | ||
| 269 | def setup_log(verbose): | 317 | def setup_log(verbose): |
| 270 | global log | 318 | global log |
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c index 8ba2c4618fe9..39bbb97cd30a 100644 --- a/tools/perf/tests/bp_signal.c +++ b/tools/perf/tests/bp_signal.c | |||
| @@ -62,8 +62,7 @@ static void __test_function(volatile long *ptr) | |||
| 62 | } | 62 | } |
| 63 | #endif | 63 | #endif |
| 64 | 64 | ||
| 65 | __attribute__ ((noinline)) | 65 | static noinline int test_function(void) |
| 66 | static int test_function(void) | ||
| 67 | { | 66 | { |
| 68 | __test_function(&the_var); | 67 | __test_function(&the_var); |
| 69 | the_var++; | 68 | the_var++; |
diff --git a/tools/perf/tests/bp_signal_overflow.c b/tools/perf/tests/bp_signal_overflow.c index 89f92fa67cc4..3b1ac6f31b15 100644 --- a/tools/perf/tests/bp_signal_overflow.c +++ b/tools/perf/tests/bp_signal_overflow.c | |||
| @@ -28,8 +28,7 @@ | |||
| 28 | 28 | ||
| 29 | static int overflows; | 29 | static int overflows; |
| 30 | 30 | ||
| 31 | __attribute__ ((noinline)) | 31 | static noinline int test_function(void) |
| 32 | static int test_function(void) | ||
| 33 | { | 32 | { |
| 34 | return time(NULL); | 33 | return time(NULL); |
| 35 | } | 34 | } |
diff --git a/tools/perf/tests/bpf-script-test-prologue.c b/tools/perf/tests/bpf-script-test-prologue.c index 7230e62c70fc..b4ebc75e25ae 100644 --- a/tools/perf/tests/bpf-script-test-prologue.c +++ b/tools/perf/tests/bpf-script-test-prologue.c | |||
| @@ -10,6 +10,15 @@ | |||
| 10 | 10 | ||
| 11 | #include <uapi/linux/fs.h> | 11 | #include <uapi/linux/fs.h> |
| 12 | 12 | ||
| 13 | /* | ||
| 14 | * If CONFIG_PROFILE_ALL_BRANCHES is selected, | ||
| 15 | * 'if' is redefined after include kernel header. | ||
| 16 | * Recover 'if' for BPF object code. | ||
| 17 | */ | ||
| 18 | #ifdef if | ||
| 19 | # undef if | ||
| 20 | #endif | ||
| 21 | |||
| 13 | #define FMODE_READ 0x1 | 22 | #define FMODE_READ 0x1 |
| 14 | #define FMODE_WRITE 0x2 | 23 | #define FMODE_WRITE 0x2 |
| 15 | 24 | ||
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c index dfe5c89e2049..3e56d08f7995 100644 --- a/tools/perf/tests/dwarf-unwind.c +++ b/tools/perf/tests/dwarf-unwind.c | |||
| @@ -76,8 +76,7 @@ static int unwind_entry(struct unwind_entry *entry, void *arg) | |||
| 76 | return strcmp((const char *) symbol, funcs[idx]); | 76 | return strcmp((const char *) symbol, funcs[idx]); |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | __attribute__ ((noinline)) | 79 | static noinline int unwind_thread(struct thread *thread) |
| 80 | static int unwind_thread(struct thread *thread) | ||
| 81 | { | 80 | { |
| 82 | struct perf_sample sample; | 81 | struct perf_sample sample; |
| 83 | unsigned long cnt = 0; | 82 | unsigned long cnt = 0; |
| @@ -108,8 +107,7 @@ static int unwind_thread(struct thread *thread) | |||
| 108 | 107 | ||
| 109 | static int global_unwind_retval = -INT_MAX; | 108 | static int global_unwind_retval = -INT_MAX; |
| 110 | 109 | ||
| 111 | __attribute__ ((noinline)) | 110 | static noinline int compare(void *p1, void *p2) |
| 112 | static int compare(void *p1, void *p2) | ||
| 113 | { | 111 | { |
| 114 | /* Any possible value should be 'thread' */ | 112 | /* Any possible value should be 'thread' */ |
| 115 | struct thread *thread = *(struct thread **)p1; | 113 | struct thread *thread = *(struct thread **)p1; |
| @@ -128,8 +126,7 @@ static int compare(void *p1, void *p2) | |||
| 128 | return p1 - p2; | 126 | return p1 - p2; |
| 129 | } | 127 | } |
| 130 | 128 | ||
| 131 | __attribute__ ((noinline)) | 129 | static noinline int krava_3(struct thread *thread) |
| 132 | static int krava_3(struct thread *thread) | ||
| 133 | { | 130 | { |
| 134 | struct thread *array[2] = {thread, thread}; | 131 | struct thread *array[2] = {thread, thread}; |
| 135 | void *fp = &bsearch; | 132 | void *fp = &bsearch; |
| @@ -147,14 +144,12 @@ static int krava_3(struct thread *thread) | |||
| 147 | return global_unwind_retval; | 144 | return global_unwind_retval; |
| 148 | } | 145 | } |
| 149 | 146 | ||
| 150 | __attribute__ ((noinline)) | 147 | static noinline int krava_2(struct thread *thread) |
| 151 | static int krava_2(struct thread *thread) | ||
| 152 | { | 148 | { |
| 153 | return krava_3(thread); | 149 | return krava_3(thread); |
| 154 | } | 150 | } |
| 155 | 151 | ||
| 156 | __attribute__ ((noinline)) | 152 | static noinline int krava_1(struct thread *thread) |
| 157 | static int krava_1(struct thread *thread) | ||
| 158 | { | 153 | { |
| 159 | return krava_2(thread); | 154 | return krava_2(thread); |
| 160 | } | 155 | } |
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 7fad885491c5..812a053d1941 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c | |||
| @@ -1810,17 +1810,6 @@ static int test_pmu_events(void) | |||
| 1810 | return ret; | 1810 | return ret; |
| 1811 | } | 1811 | } |
| 1812 | 1812 | ||
| 1813 | static void debug_warn(const char *warn, va_list params) | ||
| 1814 | { | ||
| 1815 | char msg[1024]; | ||
| 1816 | |||
| 1817 | if (verbose <= 0) | ||
| 1818 | return; | ||
| 1819 | |||
| 1820 | vsnprintf(msg, sizeof(msg), warn, params); | ||
| 1821 | fprintf(stderr, " Warning: %s\n", msg); | ||
| 1822 | } | ||
| 1823 | |||
| 1824 | int test__parse_events(int subtest __maybe_unused) | 1813 | int test__parse_events(int subtest __maybe_unused) |
| 1825 | { | 1814 | { |
| 1826 | int ret1, ret2 = 0; | 1815 | int ret1, ret2 = 0; |
| @@ -1832,8 +1821,6 @@ do { \ | |||
| 1832 | ret2 = ret1; \ | 1821 | ret2 = ret1; \ |
| 1833 | } while (0) | 1822 | } while (0) |
| 1834 | 1823 | ||
| 1835 | set_warning_routine(debug_warn); | ||
| 1836 | |||
| 1837 | TEST_EVENTS(test__events); | 1824 | TEST_EVENTS(test__events); |
| 1838 | 1825 | ||
| 1839 | if (test_pmu()) | 1826 | if (test_pmu()) |
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index d990ad08a3c6..27f41f28dcb4 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c | |||
| @@ -46,12 +46,15 @@ static struct annotate_browser_opt { | |||
| 46 | .jump_arrows = true, | 46 | .jump_arrows = true, |
| 47 | }; | 47 | }; |
| 48 | 48 | ||
| 49 | struct arch; | ||
| 50 | |||
| 49 | struct annotate_browser { | 51 | struct annotate_browser { |
| 50 | struct ui_browser b; | 52 | struct ui_browser b; |
| 51 | struct rb_root entries; | 53 | struct rb_root entries; |
| 52 | struct rb_node *curr_hot; | 54 | struct rb_node *curr_hot; |
| 53 | struct disasm_line *selection; | 55 | struct disasm_line *selection; |
| 54 | struct disasm_line **offsets; | 56 | struct disasm_line **offsets; |
| 57 | struct arch *arch; | ||
| 55 | int nr_events; | 58 | int nr_events; |
| 56 | u64 start; | 59 | u64 start; |
| 57 | int nr_asm_entries; | 60 | int nr_asm_entries; |
| @@ -125,43 +128,57 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int | |||
| 125 | int i, pcnt_width = annotate_browser__pcnt_width(ab); | 128 | int i, pcnt_width = annotate_browser__pcnt_width(ab); |
| 126 | double percent_max = 0.0; | 129 | double percent_max = 0.0; |
| 127 | char bf[256]; | 130 | char bf[256]; |
| 131 | bool show_title = false; | ||
| 128 | 132 | ||
| 129 | for (i = 0; i < ab->nr_events; i++) { | 133 | for (i = 0; i < ab->nr_events; i++) { |
| 130 | if (bdl->samples[i].percent > percent_max) | 134 | if (bdl->samples[i].percent > percent_max) |
| 131 | percent_max = bdl->samples[i].percent; | 135 | percent_max = bdl->samples[i].percent; |
| 132 | } | 136 | } |
| 133 | 137 | ||
| 138 | if ((row == 0) && (dl->offset == -1 || percent_max == 0.0)) { | ||
| 139 | if (ab->have_cycles) { | ||
| 140 | if (dl->ipc == 0.0 && dl->cycles == 0) | ||
| 141 | show_title = true; | ||
| 142 | } else | ||
| 143 | show_title = true; | ||
| 144 | } | ||
| 145 | |||
| 134 | if (dl->offset != -1 && percent_max != 0.0) { | 146 | if (dl->offset != -1 && percent_max != 0.0) { |
| 135 | if (percent_max != 0.0) { | 147 | for (i = 0; i < ab->nr_events; i++) { |
| 136 | for (i = 0; i < ab->nr_events; i++) { | 148 | ui_browser__set_percent_color(browser, |
| 137 | ui_browser__set_percent_color(browser, | 149 | bdl->samples[i].percent, |
| 138 | bdl->samples[i].percent, | 150 | current_entry); |
| 139 | current_entry); | 151 | if (annotate_browser__opts.show_total_period) { |
| 140 | if (annotate_browser__opts.show_total_period) { | 152 | ui_browser__printf(browser, "%6" PRIu64 " ", |
| 141 | ui_browser__printf(browser, "%6" PRIu64 " ", | 153 | bdl->samples[i].nr); |
| 142 | bdl->samples[i].nr); | 154 | } else { |
| 143 | } else { | 155 | ui_browser__printf(browser, "%6.2f ", |
| 144 | ui_browser__printf(browser, "%6.2f ", | 156 | bdl->samples[i].percent); |
| 145 | bdl->samples[i].percent); | ||
| 146 | } | ||
| 147 | } | 157 | } |
| 148 | } else { | ||
| 149 | ui_browser__write_nstring(browser, " ", 7 * ab->nr_events); | ||
| 150 | } | 158 | } |
| 151 | } else { | 159 | } else { |
| 152 | ui_browser__set_percent_color(browser, 0, current_entry); | 160 | ui_browser__set_percent_color(browser, 0, current_entry); |
| 153 | ui_browser__write_nstring(browser, " ", 7 * ab->nr_events); | 161 | |
| 162 | if (!show_title) | ||
| 163 | ui_browser__write_nstring(browser, " ", 7 * ab->nr_events); | ||
| 164 | else | ||
| 165 | ui_browser__printf(browser, "%*s", 7, "Percent"); | ||
| 154 | } | 166 | } |
| 155 | if (ab->have_cycles) { | 167 | if (ab->have_cycles) { |
| 156 | if (dl->ipc) | 168 | if (dl->ipc) |
| 157 | ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc); | 169 | ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc); |
| 158 | else | 170 | else if (!show_title) |
| 159 | ui_browser__write_nstring(browser, " ", IPC_WIDTH); | 171 | ui_browser__write_nstring(browser, " ", IPC_WIDTH); |
| 172 | else | ||
| 173 | ui_browser__printf(browser, "%*s ", IPC_WIDTH - 1, "IPC"); | ||
| 174 | |||
| 160 | if (dl->cycles) | 175 | if (dl->cycles) |
| 161 | ui_browser__printf(browser, "%*" PRIu64 " ", | 176 | ui_browser__printf(browser, "%*" PRIu64 " ", |
| 162 | CYCLES_WIDTH - 1, dl->cycles); | 177 | CYCLES_WIDTH - 1, dl->cycles); |
| 163 | else | 178 | else if (!show_title) |
| 164 | ui_browser__write_nstring(browser, " ", CYCLES_WIDTH); | 179 | ui_browser__write_nstring(browser, " ", CYCLES_WIDTH); |
| 180 | else | ||
| 181 | ui_browser__printf(browser, "%*s ", CYCLES_WIDTH - 1, "Cycle"); | ||
| 165 | } | 182 | } |
| 166 | 183 | ||
| 167 | SLsmg_write_char(' '); | 184 | SLsmg_write_char(' '); |
| @@ -1056,7 +1073,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, | |||
| 1056 | (nr_pcnt - 1); | 1073 | (nr_pcnt - 1); |
| 1057 | } | 1074 | } |
| 1058 | 1075 | ||
| 1059 | err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), sizeof_bdl); | 1076 | err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), |
| 1077 | sizeof_bdl, &browser.arch); | ||
| 1060 | if (err) { | 1078 | if (err) { |
| 1061 | char msg[BUFSIZ]; | 1079 | char msg[BUFSIZ]; |
| 1062 | symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); | 1080 | symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); |
diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index e99ba86158d2..d903fd493416 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c | |||
| @@ -168,7 +168,8 @@ static int symbol__gtk_annotate(struct symbol *sym, struct map *map, | |||
| 168 | if (map->dso->annotate_warned) | 168 | if (map->dso->annotate_warned) |
| 169 | return -1; | 169 | return -1; |
| 170 | 170 | ||
| 171 | err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), 0); | 171 | err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), |
| 172 | 0, NULL); | ||
| 172 | if (err) { | 173 | if (err) { |
| 173 | char msg[BUFSIZ]; | 174 | char msg[BUFSIZ]; |
| 174 | symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); | 175 | symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ddbd56df9187..be1caabb9290 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
| @@ -1379,7 +1379,9 @@ static const char *annotate__norm_arch(const char *arch_name) | |||
| 1379 | return normalize_arch((char *)arch_name); | 1379 | return normalize_arch((char *)arch_name); |
| 1380 | } | 1380 | } |
| 1381 | 1381 | ||
| 1382 | int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_name, size_t privsize) | 1382 | int symbol__disassemble(struct symbol *sym, struct map *map, |
| 1383 | const char *arch_name, size_t privsize, | ||
| 1384 | struct arch **parch) | ||
| 1383 | { | 1385 | { |
| 1384 | struct dso *dso = map->dso; | 1386 | struct dso *dso = map->dso; |
| 1385 | char command[PATH_MAX * 2]; | 1387 | char command[PATH_MAX * 2]; |
| @@ -1405,6 +1407,9 @@ int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_na | |||
| 1405 | if (arch == NULL) | 1407 | if (arch == NULL) |
| 1406 | return -ENOTSUP; | 1408 | return -ENOTSUP; |
| 1407 | 1409 | ||
| 1410 | if (parch) | ||
| 1411 | *parch = arch; | ||
| 1412 | |||
| 1408 | if (arch->init) { | 1413 | if (arch->init) { |
| 1409 | err = arch->init(arch); | 1414 | err = arch->init(arch); |
| 1410 | if (err) { | 1415 | if (err) { |
| @@ -1901,7 +1906,8 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, | |||
| 1901 | struct rb_root source_line = RB_ROOT; | 1906 | struct rb_root source_line = RB_ROOT; |
| 1902 | u64 len; | 1907 | u64 len; |
| 1903 | 1908 | ||
| 1904 | if (symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), 0) < 0) | 1909 | if (symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), |
| 1910 | 0, NULL) < 0) | ||
| 1905 | return -1; | 1911 | return -1; |
| 1906 | 1912 | ||
| 1907 | len = symbol__size(sym); | 1913 | len = symbol__size(sym); |
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 948aa8e6fd39..21055034aedd 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
| @@ -158,7 +158,9 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr); | |||
| 158 | int symbol__alloc_hist(struct symbol *sym); | 158 | int symbol__alloc_hist(struct symbol *sym); |
| 159 | void symbol__annotate_zero_histograms(struct symbol *sym); | 159 | void symbol__annotate_zero_histograms(struct symbol *sym); |
| 160 | 160 | ||
| 161 | int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_name, size_t privsize); | 161 | int symbol__disassemble(struct symbol *sym, struct map *map, |
| 162 | const char *arch_name, size_t privsize, | ||
| 163 | struct arch **parch); | ||
| 162 | 164 | ||
| 163 | enum symbol_disassemble_errno { | 165 | enum symbol_disassemble_errno { |
| 164 | SYMBOL_ANNOTATE_ERRNO__SUCCESS = 0, | 166 | SYMBOL_ANNOTATE_ERRNO__SUCCESS = 0, |
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index 0daf63b9ee3e..5547457566a7 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c | |||
| @@ -322,6 +322,13 @@ static int auxtrace_queues__add_event_buffer(struct auxtrace_queues *queues, | |||
| 322 | return auxtrace_queues__add_buffer(queues, idx, buffer); | 322 | return auxtrace_queues__add_buffer(queues, idx, buffer); |
| 323 | } | 323 | } |
| 324 | 324 | ||
| 325 | static bool filter_cpu(struct perf_session *session, int cpu) | ||
| 326 | { | ||
| 327 | unsigned long *cpu_bitmap = session->itrace_synth_opts->cpu_bitmap; | ||
| 328 | |||
| 329 | return cpu_bitmap && cpu != -1 && !test_bit(cpu, cpu_bitmap); | ||
| 330 | } | ||
| 331 | |||
| 325 | int auxtrace_queues__add_event(struct auxtrace_queues *queues, | 332 | int auxtrace_queues__add_event(struct auxtrace_queues *queues, |
| 326 | struct perf_session *session, | 333 | struct perf_session *session, |
| 327 | union perf_event *event, off_t data_offset, | 334 | union perf_event *event, off_t data_offset, |
| @@ -331,6 +338,9 @@ int auxtrace_queues__add_event(struct auxtrace_queues *queues, | |||
| 331 | unsigned int idx; | 338 | unsigned int idx; |
| 332 | int err; | 339 | int err; |
| 333 | 340 | ||
| 341 | if (filter_cpu(session, event->auxtrace.cpu)) | ||
| 342 | return 0; | ||
| 343 | |||
| 334 | buffer = zalloc(sizeof(struct auxtrace_buffer)); | 344 | buffer = zalloc(sizeof(struct auxtrace_buffer)); |
| 335 | if (!buffer) | 345 | if (!buffer) |
| 336 | return -ENOMEM; | 346 | return -ENOMEM; |
| @@ -947,6 +957,8 @@ void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts) | |||
| 947 | synth_opts->instructions = true; | 957 | synth_opts->instructions = true; |
| 948 | synth_opts->branches = true; | 958 | synth_opts->branches = true; |
| 949 | synth_opts->transactions = true; | 959 | synth_opts->transactions = true; |
| 960 | synth_opts->ptwrites = true; | ||
| 961 | synth_opts->pwr_events = true; | ||
| 950 | synth_opts->errors = true; | 962 | synth_opts->errors = true; |
| 951 | synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; | 963 | synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; |
| 952 | synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; | 964 | synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; |
| @@ -1030,6 +1042,12 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str, | |||
| 1030 | case 'x': | 1042 | case 'x': |
| 1031 | synth_opts->transactions = true; | 1043 | synth_opts->transactions = true; |
| 1032 | break; | 1044 | break; |
| 1045 | case 'w': | ||
| 1046 | synth_opts->ptwrites = true; | ||
| 1047 | break; | ||
| 1048 | case 'p': | ||
| 1049 | synth_opts->pwr_events = true; | ||
| 1050 | break; | ||
| 1033 | case 'e': | 1051 | case 'e': |
| 1034 | synth_opts->errors = true; | 1052 | synth_opts->errors = true; |
| 1035 | break; | 1053 | break; |
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index 9f0de72d58e2..33b5e6cdf38c 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h | |||
| @@ -59,6 +59,8 @@ enum itrace_period_type { | |||
| 59 | * @instructions: whether to synthesize 'instructions' events | 59 | * @instructions: whether to synthesize 'instructions' events |
| 60 | * @branches: whether to synthesize 'branches' events | 60 | * @branches: whether to synthesize 'branches' events |
| 61 | * @transactions: whether to synthesize events for transactions | 61 | * @transactions: whether to synthesize events for transactions |
| 62 | * @ptwrites: whether to synthesize events for ptwrites | ||
| 63 | * @pwr_events: whether to synthesize power events | ||
| 62 | * @errors: whether to synthesize decoder error events | 64 | * @errors: whether to synthesize decoder error events |
| 63 | * @dont_decode: whether to skip decoding entirely | 65 | * @dont_decode: whether to skip decoding entirely |
| 64 | * @log: write a decoding log | 66 | * @log: write a decoding log |
| @@ -72,6 +74,7 @@ enum itrace_period_type { | |||
| 72 | * @period: 'instructions' events period | 74 | * @period: 'instructions' events period |
| 73 | * @period_type: 'instructions' events period type | 75 | * @period_type: 'instructions' events period type |
| 74 | * @initial_skip: skip N events at the beginning. | 76 | * @initial_skip: skip N events at the beginning. |
| 77 | * @cpu_bitmap: CPUs for which to synthesize events, or NULL for all | ||
| 75 | */ | 78 | */ |
| 76 | struct itrace_synth_opts { | 79 | struct itrace_synth_opts { |
| 77 | bool set; | 80 | bool set; |
| @@ -79,6 +82,8 @@ struct itrace_synth_opts { | |||
| 79 | bool instructions; | 82 | bool instructions; |
| 80 | bool branches; | 83 | bool branches; |
| 81 | bool transactions; | 84 | bool transactions; |
| 85 | bool ptwrites; | ||
| 86 | bool pwr_events; | ||
| 82 | bool errors; | 87 | bool errors; |
| 83 | bool dont_decode; | 88 | bool dont_decode; |
| 84 | bool log; | 89 | bool log; |
| @@ -92,6 +97,7 @@ struct itrace_synth_opts { | |||
| 92 | unsigned long long period; | 97 | unsigned long long period; |
| 93 | enum itrace_period_type period_type; | 98 | enum itrace_period_type period_type; |
| 94 | unsigned long initial_skip; | 99 | unsigned long initial_skip; |
| 100 | unsigned long *cpu_bitmap; | ||
| 95 | }; | 101 | }; |
| 96 | 102 | ||
| 97 | /** | 103 | /** |
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 0328f297a748..0175765c05b9 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <subcmd/pager.h> | 5 | #include <subcmd/pager.h> |
| 6 | #include "../ui/ui.h" | 6 | #include "../ui/ui.h" |
| 7 | 7 | ||
| 8 | #include <linux/compiler.h> | ||
| 8 | #include <linux/string.h> | 9 | #include <linux/string.h> |
| 9 | 10 | ||
| 10 | #define CMD_EXEC_PATH "--exec-path" | 11 | #define CMD_EXEC_PATH "--exec-path" |
| @@ -24,6 +25,6 @@ static inline int is_absolute_path(const char *path) | |||
| 24 | return path[0] == '/'; | 25 | return path[0] == '/'; |
| 25 | } | 26 | } |
| 26 | 27 | ||
| 27 | char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); | 28 | char *mkpath(const char *fmt, ...) __printf(1, 2); |
| 28 | 29 | ||
| 29 | #endif /* __PERF_CACHE_H */ | 30 | #endif /* __PERF_CACHE_H */ |
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 8d724f0fa5a8..31a7dea248d0 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c | |||
| @@ -335,32 +335,42 @@ static int perf_parse_long(const char *value, long *ret) | |||
| 335 | return 0; | 335 | return 0; |
| 336 | } | 336 | } |
| 337 | 337 | ||
| 338 | static void die_bad_config(const char *name) | 338 | static void bad_config(const char *name) |
| 339 | { | 339 | { |
| 340 | if (config_file_name) | 340 | if (config_file_name) |
| 341 | die("bad config value for '%s' in %s", name, config_file_name); | 341 | pr_warning("bad config value for '%s' in %s, ignoring...\n", name, config_file_name); |
| 342 | die("bad config value for '%s'", name); | 342 | else |
| 343 | pr_warning("bad config value for '%s', ignoring...\n", name); | ||
| 343 | } | 344 | } |
| 344 | 345 | ||
| 345 | u64 perf_config_u64(const char *name, const char *value) | 346 | int perf_config_u64(u64 *dest, const char *name, const char *value) |
| 346 | { | 347 | { |
| 347 | long long ret = 0; | 348 | long long ret = 0; |
| 348 | 349 | ||
| 349 | if (!perf_parse_llong(value, &ret)) | 350 | if (!perf_parse_llong(value, &ret)) { |
| 350 | die_bad_config(name); | 351 | bad_config(name); |
| 351 | return (u64) ret; | 352 | return -1; |
| 353 | } | ||
| 354 | |||
| 355 | *dest = ret; | ||
| 356 | return 0; | ||
| 352 | } | 357 | } |
| 353 | 358 | ||
| 354 | int perf_config_int(const char *name, const char *value) | 359 | int perf_config_int(int *dest, const char *name, const char *value) |
| 355 | { | 360 | { |
| 356 | long ret = 0; | 361 | long ret = 0; |
| 357 | if (!perf_parse_long(value, &ret)) | 362 | if (!perf_parse_long(value, &ret)) { |
| 358 | die_bad_config(name); | 363 | bad_config(name); |
| 359 | return ret; | 364 | return -1; |
| 365 | } | ||
| 366 | *dest = ret; | ||
| 367 | return 0; | ||
| 360 | } | 368 | } |
| 361 | 369 | ||
| 362 | static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool) | 370 | static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool) |
| 363 | { | 371 | { |
| 372 | int ret; | ||
| 373 | |||
| 364 | *is_bool = 1; | 374 | *is_bool = 1; |
| 365 | if (!value) | 375 | if (!value) |
| 366 | return 1; | 376 | return 1; |
| @@ -371,7 +381,7 @@ static int perf_config_bool_or_int(const char *name, const char *value, int *is_ | |||
| 371 | if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off")) | 381 | if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off")) |
| 372 | return 0; | 382 | return 0; |
| 373 | *is_bool = 0; | 383 | *is_bool = 0; |
| 374 | return perf_config_int(name, value); | 384 | return perf_config_int(&ret, name, value) < 0 ? -1 : ret; |
| 375 | } | 385 | } |
| 376 | 386 | ||
| 377 | int perf_config_bool(const char *name, const char *value) | 387 | int perf_config_bool(const char *name, const char *value) |
| @@ -657,8 +667,7 @@ static int perf_config_set__init(struct perf_config_set *set) | |||
| 657 | 667 | ||
| 658 | user_config = strdup(mkpath("%s/.perfconfig", home)); | 668 | user_config = strdup(mkpath("%s/.perfconfig", home)); |
| 659 | if (user_config == NULL) { | 669 | if (user_config == NULL) { |
| 660 | warning("Not enough memory to process %s/.perfconfig, " | 670 | pr_warning("Not enough memory to process %s/.perfconfig, ignoring it.", home); |
| 661 | "ignoring it.", home); | ||
| 662 | goto out; | 671 | goto out; |
| 663 | } | 672 | } |
| 664 | 673 | ||
| @@ -671,8 +680,7 @@ static int perf_config_set__init(struct perf_config_set *set) | |||
| 671 | ret = 0; | 680 | ret = 0; |
| 672 | 681 | ||
| 673 | if (st.st_uid && (st.st_uid != geteuid())) { | 682 | if (st.st_uid && (st.st_uid != geteuid())) { |
| 674 | warning("File %s not owned by current user or root, " | 683 | pr_warning("File %s not owned by current user or root, ignoring it.", user_config); |
| 675 | "ignoring it.", user_config); | ||
| 676 | goto out_free; | 684 | goto out_free; |
| 677 | } | 685 | } |
| 678 | 686 | ||
| @@ -795,7 +803,8 @@ void perf_config_set__delete(struct perf_config_set *set) | |||
| 795 | */ | 803 | */ |
| 796 | int config_error_nonbool(const char *var) | 804 | int config_error_nonbool(const char *var) |
| 797 | { | 805 | { |
| 798 | return error("Missing value for '%s'", var); | 806 | pr_err("Missing value for '%s'", var); |
| 807 | return -1; | ||
| 799 | } | 808 | } |
| 800 | 809 | ||
| 801 | void set_buildid_dir(const char *dir) | 810 | void set_buildid_dir(const char *dir) |
diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h index 1a59a6b43f8b..b6bb11f3f165 100644 --- a/tools/perf/util/config.h +++ b/tools/perf/util/config.h | |||
| @@ -27,8 +27,8 @@ extern const char *config_exclusive_filename; | |||
| 27 | typedef int (*config_fn_t)(const char *, const char *, void *); | 27 | typedef int (*config_fn_t)(const char *, const char *, void *); |
| 28 | int perf_default_config(const char *, const char *, void *); | 28 | int perf_default_config(const char *, const char *, void *); |
| 29 | int perf_config(config_fn_t fn, void *); | 29 | int perf_config(config_fn_t fn, void *); |
| 30 | int perf_config_int(const char *, const char *); | 30 | int perf_config_int(int *dest, const char *, const char *); |
| 31 | u64 perf_config_u64(const char *, const char *); | 31 | int perf_config_u64(u64 *dest, const char *, const char *); |
| 32 | int perf_config_bool(const char *, const char *); | 32 | int perf_config_bool(const char *, const char *); |
| 33 | int config_error_nonbool(const char *); | 33 | int config_error_nonbool(const char *); |
| 34 | const char *perf_etc_perfconfig(void); | 34 | const char *perf_etc_perfconfig(void); |
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 89d50318833d..3149b70799fd 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c | |||
| @@ -1444,10 +1444,8 @@ static int convert__config(const char *var, const char *value, void *cb) | |||
| 1444 | { | 1444 | { |
| 1445 | struct convert *c = cb; | 1445 | struct convert *c = cb; |
| 1446 | 1446 | ||
| 1447 | if (!strcmp(var, "convert.queue-size")) { | 1447 | if (!strcmp(var, "convert.queue-size")) |
| 1448 | c->queue_size = perf_config_u64(var, value); | 1448 | return perf_config_u64(&c->queue_size, var, value); |
| 1449 | return 0; | ||
| 1450 | } | ||
| 1451 | 1449 | ||
| 1452 | return 0; | 1450 | return 0; |
| 1453 | } | 1451 | } |
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 8a23ea1a71c7..c818bdb1c1ab 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include <stdbool.h> | 5 | #include <stdbool.h> |
| 6 | #include <string.h> | 6 | #include <string.h> |
| 7 | #include <linux/compiler.h> | ||
| 7 | #include "event.h" | 8 | #include "event.h" |
| 8 | #include "../ui/helpline.h" | 9 | #include "../ui/helpline.h" |
| 9 | #include "../ui/progress.h" | 10 | #include "../ui/progress.h" |
| @@ -40,16 +41,16 @@ extern int debug_data_convert; | |||
| 40 | 41 | ||
| 41 | #define STRERR_BUFSIZE 128 /* For the buffer size of str_error_r */ | 42 | #define STRERR_BUFSIZE 128 /* For the buffer size of str_error_r */ |
| 42 | 43 | ||
| 43 | int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); | 44 | int dump_printf(const char *fmt, ...) __printf(1, 2); |
| 44 | void trace_event(union perf_event *event); | 45 | void trace_event(union perf_event *event); |
| 45 | 46 | ||
| 46 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); | 47 | int ui__error(const char *format, ...) __printf(1, 2); |
| 47 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); | 48 | int ui__warning(const char *format, ...) __printf(1, 2); |
| 48 | 49 | ||
| 49 | void pr_stat(const char *fmt, ...); | 50 | void pr_stat(const char *fmt, ...); |
| 50 | 51 | ||
| 51 | int eprintf(int level, int var, const char *fmt, ...) __attribute__((format(printf, 3, 4))); | 52 | int eprintf(int level, int var, const char *fmt, ...) __printf(3, 4); |
| 52 | int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __attribute__((format(printf, 4, 5))); | 53 | int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __printf(4, 5); |
| 53 | int veprintf(int level, int var, const char *fmt, va_list args); | 54 | int veprintf(int level, int var, const char *fmt, va_list args); |
| 54 | 55 | ||
| 55 | int perf_debug_option(const char *str); | 56 | int perf_debug_option(const char *str); |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 7c3fa1c8cbcd..9967c87af7a6 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
| @@ -252,6 +252,127 @@ enum auxtrace_error_type { | |||
| 252 | PERF_AUXTRACE_ERROR_MAX | 252 | PERF_AUXTRACE_ERROR_MAX |
| 253 | }; | 253 | }; |
| 254 | 254 | ||
| 255 | /* Attribute type for custom synthesized events */ | ||
| 256 | #define PERF_TYPE_SYNTH (INT_MAX + 1U) | ||
| 257 | |||
| 258 | /* Attribute config for custom synthesized events */ | ||
| 259 | enum perf_synth_id { | ||
| 260 | PERF_SYNTH_INTEL_PTWRITE, | ||
| 261 | PERF_SYNTH_INTEL_MWAIT, | ||
| 262 | PERF_SYNTH_INTEL_PWRE, | ||
| 263 | PERF_SYNTH_INTEL_EXSTOP, | ||
| 264 | PERF_SYNTH_INTEL_PWRX, | ||
| 265 | PERF_SYNTH_INTEL_CBR, | ||
| 266 | }; | ||
| 267 | |||
| 268 | /* | ||
| 269 | * Raw data formats for synthesized events. Note that 4 bytes of padding are | ||
| 270 | * present to match the 'size' member of PERF_SAMPLE_RAW data which is always | ||
| 271 | * 8-byte aligned. That means we must dereference raw_data with an offset of 4. | ||
| 272 | * Refer perf_sample__synth_ptr() and perf_synth__raw_data(). It also means the | ||
| 273 | * structure sizes are 4 bytes bigger than the raw_size, refer | ||
| 274 | * perf_synth__raw_size(). | ||
| 275 | */ | ||
| 276 | |||
| 277 | struct perf_synth_intel_ptwrite { | ||
| 278 | u32 padding; | ||
| 279 | union { | ||
| 280 | struct { | ||
| 281 | u32 ip : 1, | ||
| 282 | reserved : 31; | ||
| 283 | }; | ||
| 284 | u32 flags; | ||
| 285 | }; | ||
| 286 | u64 payload; | ||
| 287 | }; | ||
| 288 | |||
| 289 | struct perf_synth_intel_mwait { | ||
| 290 | u32 padding; | ||
| 291 | u32 reserved; | ||
| 292 | union { | ||
| 293 | struct { | ||
| 294 | u64 hints : 8, | ||
| 295 | reserved1 : 24, | ||
| 296 | extensions : 2, | ||
| 297 | reserved2 : 30; | ||
| 298 | }; | ||
| 299 | u64 payload; | ||
| 300 | }; | ||
| 301 | }; | ||
| 302 | |||
| 303 | struct perf_synth_intel_pwre { | ||
| 304 | u32 padding; | ||
| 305 | u32 reserved; | ||
| 306 | union { | ||
| 307 | struct { | ||
| 308 | u64 reserved1 : 7, | ||
| 309 | hw : 1, | ||
| 310 | subcstate : 4, | ||
| 311 | cstate : 4, | ||
| 312 | reserved2 : 48; | ||
| 313 | }; | ||
| 314 | u64 payload; | ||
| 315 | }; | ||
| 316 | }; | ||
| 317 | |||
| 318 | struct perf_synth_intel_exstop { | ||
| 319 | u32 padding; | ||
| 320 | union { | ||
| 321 | struct { | ||
| 322 | u32 ip : 1, | ||
| 323 | reserved : 31; | ||
| 324 | }; | ||
| 325 | u32 flags; | ||
| 326 | }; | ||
| 327 | }; | ||
| 328 | |||
| 329 | struct perf_synth_intel_pwrx { | ||
| 330 | u32 padding; | ||
| 331 | u32 reserved; | ||
| 332 | union { | ||
| 333 | struct { | ||
| 334 | u64 deepest_cstate : 4, | ||
| 335 | last_cstate : 4, | ||
| 336 | wake_reason : 4, | ||
| 337 | reserved1 : 52; | ||
| 338 | }; | ||
| 339 | u64 payload; | ||
| 340 | }; | ||
| 341 | }; | ||
| 342 | |||
| 343 | struct perf_synth_intel_cbr { | ||
| 344 | u32 padding; | ||
| 345 | union { | ||
| 346 | struct { | ||
| 347 | u32 cbr : 8, | ||
| 348 | reserved1 : 8, | ||
| 349 | max_nonturbo : 8, | ||
| 350 | reserved2 : 8; | ||
| 351 | }; | ||
| 352 | u32 flags; | ||
| 353 | }; | ||
| 354 | u32 freq; | ||
| 355 | u32 reserved3; | ||
| 356 | }; | ||
| 357 | |||
| 358 | /* | ||
| 359 | * raw_data is always 4 bytes from an 8-byte boundary, so subtract 4 to get | ||
| 360 | * 8-byte alignment. | ||
| 361 | */ | ||
| 362 | static inline void *perf_sample__synth_ptr(struct perf_sample *sample) | ||
| 363 | { | ||
| 364 | return sample->raw_data - 4; | ||
| 365 | } | ||
| 366 | |||
| 367 | static inline void *perf_synth__raw_data(void *p) | ||
| 368 | { | ||
| 369 | return p + 4; | ||
| 370 | } | ||
| 371 | |||
| 372 | #define perf_synth__raw_size(d) (sizeof(d) - 4) | ||
| 373 | |||
| 374 | #define perf_sample__bad_synth_size(s, d) ((s)->raw_size < sizeof(d) - 4) | ||
| 375 | |||
| 255 | /* | 376 | /* |
| 256 | * The kernel collects the number of events it couldn't send in a stretch and | 377 | * The kernel collects the number of events it couldn't send in a stretch and |
| 257 | * when possible sends this number in a PERF_RECORD_LOST event. The number of | 378 | * when possible sends this number in a PERF_RECORD_LOST event. The number of |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 94cea4398a13..8d601fbdd8d6 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | #ifndef __PERF_EVLIST_H | 1 | #ifndef __PERF_EVLIST_H |
| 2 | #define __PERF_EVLIST_H 1 | 2 | #define __PERF_EVLIST_H 1 |
| 3 | 3 | ||
| 4 | #include <linux/compiler.h> | ||
| 4 | #include <linux/kernel.h> | 5 | #include <linux/kernel.h> |
| 5 | #include <linux/refcount.h> | 6 | #include <linux/refcount.h> |
| 6 | #include <linux/list.h> | 7 | #include <linux/list.h> |
| @@ -34,7 +35,7 @@ struct perf_mmap { | |||
| 34 | refcount_t refcnt; | 35 | refcount_t refcnt; |
| 35 | u64 prev; | 36 | u64 prev; |
| 36 | struct auxtrace_mmap auxtrace_mmap; | 37 | struct auxtrace_mmap auxtrace_mmap; |
| 37 | char event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8))); | 38 | char event_copy[PERF_SAMPLE_MAX_SIZE] __aligned(8); |
| 38 | }; | 39 | }; |
| 39 | 40 | ||
| 40 | static inline size_t | 41 | static inline size_t |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index cda44b0e821c..6f4882f8d61f 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
| @@ -11,13 +11,17 @@ | |||
| 11 | #include <errno.h> | 11 | #include <errno.h> |
| 12 | #include <inttypes.h> | 12 | #include <inttypes.h> |
| 13 | #include <linux/bitops.h> | 13 | #include <linux/bitops.h> |
| 14 | #include <api/fs/fs.h> | ||
| 14 | #include <api/fs/tracing_path.h> | 15 | #include <api/fs/tracing_path.h> |
| 15 | #include <traceevent/event-parse.h> | 16 | #include <traceevent/event-parse.h> |
| 16 | #include <linux/hw_breakpoint.h> | 17 | #include <linux/hw_breakpoint.h> |
| 17 | #include <linux/perf_event.h> | 18 | #include <linux/perf_event.h> |
| 19 | #include <linux/compiler.h> | ||
| 18 | #include <linux/err.h> | 20 | #include <linux/err.h> |
| 19 | #include <sys/ioctl.h> | 21 | #include <sys/ioctl.h> |
| 20 | #include <sys/resource.h> | 22 | #include <sys/resource.h> |
| 23 | #include <sys/types.h> | ||
| 24 | #include <dirent.h> | ||
| 21 | #include "asm/bug.h" | 25 | #include "asm/bug.h" |
| 22 | #include "callchain.h" | 26 | #include "callchain.h" |
| 23 | #include "cgroup.h" | 27 | #include "cgroup.h" |
| @@ -1441,7 +1445,7 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, | |||
| 1441 | } | 1445 | } |
| 1442 | 1446 | ||
| 1443 | static int __open_attr__fprintf(FILE *fp, const char *name, const char *val, | 1447 | static int __open_attr__fprintf(FILE *fp, const char *name, const char *val, |
| 1444 | void *priv __attribute__((unused))) | 1448 | void *priv __maybe_unused) |
| 1445 | { | 1449 | { |
| 1446 | return fprintf(fp, " %-32s %s\n", name, val); | 1450 | return fprintf(fp, " %-32s %s\n", name, val); |
| 1447 | } | 1451 | } |
| @@ -2471,6 +2475,42 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err, | |||
| 2471 | return false; | 2475 | return false; |
| 2472 | } | 2476 | } |
| 2473 | 2477 | ||
| 2478 | static bool find_process(const char *name) | ||
| 2479 | { | ||
| 2480 | size_t len = strlen(name); | ||
| 2481 | DIR *dir; | ||
| 2482 | struct dirent *d; | ||
| 2483 | int ret = -1; | ||
| 2484 | |||
| 2485 | dir = opendir(procfs__mountpoint()); | ||
| 2486 | if (!dir) | ||
| 2487 | return false; | ||
| 2488 | |||
| 2489 | /* Walk through the directory. */ | ||
| 2490 | while (ret && (d = readdir(dir)) != NULL) { | ||
| 2491 | char path[PATH_MAX]; | ||
| 2492 | char *data; | ||
| 2493 | size_t size; | ||
| 2494 | |||
| 2495 | if ((d->d_type != DT_DIR) || | ||
| 2496 | !strcmp(".", d->d_name) || | ||
| 2497 | !strcmp("..", d->d_name)) | ||
| 2498 | continue; | ||
| 2499 | |||
| 2500 | scnprintf(path, sizeof(path), "%s/%s/comm", | ||
| 2501 | procfs__mountpoint(), d->d_name); | ||
| 2502 | |||
| 2503 | if (filename__read_str(path, &data, &size)) | ||
| 2504 | continue; | ||
| 2505 | |||
| 2506 | ret = strncmp(name, data, len); | ||
| 2507 | free(data); | ||
| 2508 | } | ||
| 2509 | |||
| 2510 | closedir(dir); | ||
| 2511 | return ret ? false : true; | ||
| 2512 | } | ||
| 2513 | |||
| 2474 | int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, | 2514 | int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, |
| 2475 | int err, char *msg, size_t size) | 2515 | int err, char *msg, size_t size) |
| 2476 | { | 2516 | { |
diff --git a/tools/perf/util/genelf_debug.c b/tools/perf/util/genelf_debug.c index 5980f7d256b1..40789d8603d0 100644 --- a/tools/perf/util/genelf_debug.c +++ b/tools/perf/util/genelf_debug.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | * @remark Copyright 2007 OProfile authors | 11 | * @remark Copyright 2007 OProfile authors |
| 12 | * @author Philippe Elie | 12 | * @author Philippe Elie |
| 13 | */ | 13 | */ |
| 14 | #include <linux/compiler.h> | ||
| 14 | #include <sys/types.h> | 15 | #include <sys/types.h> |
| 15 | #include <stdio.h> | 16 | #include <stdio.h> |
| 16 | #include <getopt.h> | 17 | #include <getopt.h> |
| @@ -125,7 +126,7 @@ struct debug_line_header { | |||
| 125 | * and filesize, last entry is followed by en empty string. | 126 | * and filesize, last entry is followed by en empty string. |
| 126 | */ | 127 | */ |
| 127 | /* follow the first program statement */ | 128 | /* follow the first program statement */ |
| 128 | } __attribute__((packed)); | 129 | } __packed; |
| 129 | 130 | ||
| 130 | /* DWARF 2 spec talk only about one possible compilation unit header while | 131 | /* DWARF 2 spec talk only about one possible compilation unit header while |
| 131 | * binutils can handle two flavours of dwarf 2, 32 and 64 bits, this is not | 132 | * binutils can handle two flavours of dwarf 2, 32 and 64 bits, this is not |
| @@ -138,7 +139,7 @@ struct compilation_unit_header { | |||
| 138 | uhalf version; | 139 | uhalf version; |
| 139 | uword debug_abbrev_offset; | 140 | uword debug_abbrev_offset; |
| 140 | ubyte pointer_size; | 141 | ubyte pointer_size; |
| 141 | } __attribute__((packed)); | 142 | } __packed; |
| 142 | 143 | ||
| 143 | #define DW_LNS_num_opcode (DW_LNS_set_isa + 1) | 144 | #define DW_LNS_num_opcode (DW_LNS_set_isa + 1) |
| 144 | 145 | ||
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index b5baff3007bb..76ed7d03e500 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <unistd.h> | 8 | #include <unistd.h> |
| 9 | #include <stdio.h> | 9 | #include <stdio.h> |
| 10 | #include <stdlib.h> | 10 | #include <stdlib.h> |
| 11 | #include <linux/compiler.h> | ||
| 11 | #include <linux/list.h> | 12 | #include <linux/list.h> |
| 12 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
| 13 | #include <linux/bitops.h> | 14 | #include <linux/bitops.h> |
| @@ -1274,7 +1275,7 @@ error: | |||
| 1274 | } | 1275 | } |
| 1275 | 1276 | ||
| 1276 | static int __desc_attr__fprintf(FILE *fp, const char *name, const char *val, | 1277 | static int __desc_attr__fprintf(FILE *fp, const char *name, const char *val, |
| 1277 | void *priv __attribute__((unused))) | 1278 | void *priv __maybe_unused) |
| 1278 | { | 1279 | { |
| 1279 | return fprintf(fp, ", %s = %s", name, val); | 1280 | return fprintf(fp, ", %s = %s", name, val); |
| 1280 | } | 1281 | } |
diff --git a/tools/perf/util/help-unknown-cmd.c b/tools/perf/util/help-unknown-cmd.c index 1c88ad6425b8..15b95300d7f3 100644 --- a/tools/perf/util/help-unknown-cmd.c +++ b/tools/perf/util/help-unknown-cmd.c | |||
| @@ -12,7 +12,7 @@ static int perf_unknown_cmd_config(const char *var, const char *value, | |||
| 12 | void *cb __maybe_unused) | 12 | void *cb __maybe_unused) |
| 13 | { | 13 | { |
| 14 | if (!strcmp(var, "help.autocorrect")) | 14 | if (!strcmp(var, "help.autocorrect")) |
| 15 | autocorrect = perf_config_int(var,value); | 15 | return perf_config_int(&autocorrect, var,value); |
| 16 | 16 | ||
| 17 | return 0; | 17 | return 0; |
| 18 | } | 18 | } |
diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c index b2834ac7b1f5..218ee2bac9a5 100644 --- a/tools/perf/util/intel-bts.c +++ b/tools/perf/util/intel-bts.c | |||
| @@ -866,8 +866,6 @@ static void intel_bts_print_info(u64 *arr, int start, int finish) | |||
| 866 | fprintf(stdout, intel_bts_info_fmts[i], arr[i]); | 866 | fprintf(stdout, intel_bts_info_fmts[i], arr[i]); |
| 867 | } | 867 | } |
| 868 | 868 | ||
| 869 | u64 intel_bts_auxtrace_info_priv[INTEL_BTS_AUXTRACE_PRIV_SIZE]; | ||
| 870 | |||
| 871 | int intel_bts_process_auxtrace_info(union perf_event *event, | 869 | int intel_bts_process_auxtrace_info(union perf_event *event, |
| 872 | struct perf_session *session) | 870 | struct perf_session *session) |
| 873 | { | 871 | { |
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 7cf7f7aca4d2..aa1593ce551d 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | |||
| @@ -64,6 +64,25 @@ enum intel_pt_pkt_state { | |||
| 64 | INTEL_PT_STATE_FUP_NO_TIP, | 64 | INTEL_PT_STATE_FUP_NO_TIP, |
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| 67 | static inline bool intel_pt_sample_time(enum intel_pt_pkt_state pkt_state) | ||
| 68 | { | ||
| 69 | switch (pkt_state) { | ||
| 70 | case INTEL_PT_STATE_NO_PSB: | ||
| 71 | case INTEL_PT_STATE_NO_IP: | ||
| 72 | case INTEL_PT_STATE_ERR_RESYNC: | ||
| 73 | case INTEL_PT_STATE_IN_SYNC: | ||
| 74 | case INTEL_PT_STATE_TNT: | ||
| 75 | return true; | ||
| 76 | case INTEL_PT_STATE_TIP: | ||
| 77 | case INTEL_PT_STATE_TIP_PGD: | ||
| 78 | case INTEL_PT_STATE_FUP: | ||
| 79 | case INTEL_PT_STATE_FUP_NO_TIP: | ||
| 80 | return false; | ||
| 81 | default: | ||
| 82 | return true; | ||
| 83 | }; | ||
| 84 | } | ||
| 85 | |||
| 67 | #ifdef INTEL_PT_STRICT | 86 | #ifdef INTEL_PT_STRICT |
| 68 | #define INTEL_PT_STATE_ERR1 INTEL_PT_STATE_NO_PSB | 87 | #define INTEL_PT_STATE_ERR1 INTEL_PT_STATE_NO_PSB |
| 69 | #define INTEL_PT_STATE_ERR2 INTEL_PT_STATE_NO_PSB | 88 | #define INTEL_PT_STATE_ERR2 INTEL_PT_STATE_NO_PSB |
| @@ -87,11 +106,13 @@ struct intel_pt_decoder { | |||
| 87 | const unsigned char *buf; | 106 | const unsigned char *buf; |
| 88 | size_t len; | 107 | size_t len; |
| 89 | bool return_compression; | 108 | bool return_compression; |
| 109 | bool branch_enable; | ||
| 90 | bool mtc_insn; | 110 | bool mtc_insn; |
| 91 | bool pge; | 111 | bool pge; |
| 92 | bool have_tma; | 112 | bool have_tma; |
| 93 | bool have_cyc; | 113 | bool have_cyc; |
| 94 | bool fixup_last_mtc; | 114 | bool fixup_last_mtc; |
| 115 | bool have_last_ip; | ||
| 95 | uint64_t pos; | 116 | uint64_t pos; |
| 96 | uint64_t last_ip; | 117 | uint64_t last_ip; |
| 97 | uint64_t ip; | 118 | uint64_t ip; |
| @@ -99,6 +120,7 @@ struct intel_pt_decoder { | |||
| 99 | uint64_t timestamp; | 120 | uint64_t timestamp; |
| 100 | uint64_t tsc_timestamp; | 121 | uint64_t tsc_timestamp; |
| 101 | uint64_t ref_timestamp; | 122 | uint64_t ref_timestamp; |
| 123 | uint64_t sample_timestamp; | ||
| 102 | uint64_t ret_addr; | 124 | uint64_t ret_addr; |
| 103 | uint64_t ctc_timestamp; | 125 | uint64_t ctc_timestamp; |
| 104 | uint64_t ctc_delta; | 126 | uint64_t ctc_delta; |
| @@ -119,6 +141,7 @@ struct intel_pt_decoder { | |||
| 119 | int pkt_len; | 141 | int pkt_len; |
| 120 | int last_packet_type; | 142 | int last_packet_type; |
| 121 | unsigned int cbr; | 143 | unsigned int cbr; |
| 144 | unsigned int cbr_seen; | ||
| 122 | unsigned int max_non_turbo_ratio; | 145 | unsigned int max_non_turbo_ratio; |
| 123 | double max_non_turbo_ratio_fp; | 146 | double max_non_turbo_ratio_fp; |
| 124 | double cbr_cyc_to_tsc; | 147 | double cbr_cyc_to_tsc; |
| @@ -136,9 +159,18 @@ struct intel_pt_decoder { | |||
| 136 | bool continuous_period; | 159 | bool continuous_period; |
| 137 | bool overflow; | 160 | bool overflow; |
| 138 | bool set_fup_tx_flags; | 161 | bool set_fup_tx_flags; |
| 162 | bool set_fup_ptw; | ||
| 163 | bool set_fup_mwait; | ||
| 164 | bool set_fup_pwre; | ||
| 165 | bool set_fup_exstop; | ||
| 139 | unsigned int fup_tx_flags; | 166 | unsigned int fup_tx_flags; |
| 140 | unsigned int tx_flags; | 167 | unsigned int tx_flags; |
| 168 | uint64_t fup_ptw_payload; | ||
| 169 | uint64_t fup_mwait_payload; | ||
| 170 | uint64_t fup_pwre_payload; | ||
| 171 | uint64_t cbr_payload; | ||
| 141 | uint64_t timestamp_insn_cnt; | 172 | uint64_t timestamp_insn_cnt; |
| 173 | uint64_t sample_insn_cnt; | ||
| 142 | uint64_t stuck_ip; | 174 | uint64_t stuck_ip; |
| 143 | int no_progress; | 175 | int no_progress; |
| 144 | int stuck_ip_prd; | 176 | int stuck_ip_prd; |
| @@ -192,6 +224,7 @@ struct intel_pt_decoder *intel_pt_decoder_new(struct intel_pt_params *params) | |||
| 192 | decoder->pgd_ip = params->pgd_ip; | 224 | decoder->pgd_ip = params->pgd_ip; |
| 193 | decoder->data = params->data; | 225 | decoder->data = params->data; |
| 194 | decoder->return_compression = params->return_compression; | 226 | decoder->return_compression = params->return_compression; |
| 227 | decoder->branch_enable = params->branch_enable; | ||
| 195 | 228 | ||
| 196 | decoder->period = params->period; | 229 | decoder->period = params->period; |
| 197 | decoder->period_type = params->period_type; | 230 | decoder->period_type = params->period_type; |
| @@ -398,6 +431,7 @@ static uint64_t intel_pt_calc_ip(const struct intel_pt_pkt *packet, | |||
| 398 | static inline void intel_pt_set_last_ip(struct intel_pt_decoder *decoder) | 431 | static inline void intel_pt_set_last_ip(struct intel_pt_decoder *decoder) |
| 399 | { | 432 | { |
| 400 | decoder->last_ip = intel_pt_calc_ip(&decoder->packet, decoder->last_ip); | 433 | decoder->last_ip = intel_pt_calc_ip(&decoder->packet, decoder->last_ip); |
| 434 | decoder->have_last_ip = true; | ||
| 401 | } | 435 | } |
| 402 | 436 | ||
| 403 | static inline void intel_pt_set_ip(struct intel_pt_decoder *decoder) | 437 | static inline void intel_pt_set_ip(struct intel_pt_decoder *decoder) |
| @@ -635,6 +669,8 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info) | |||
| 635 | case INTEL_PT_PAD: | 669 | case INTEL_PT_PAD: |
| 636 | case INTEL_PT_VMCS: | 670 | case INTEL_PT_VMCS: |
| 637 | case INTEL_PT_MNT: | 671 | case INTEL_PT_MNT: |
| 672 | case INTEL_PT_PTWRITE: | ||
| 673 | case INTEL_PT_PTWRITE_IP: | ||
| 638 | return 0; | 674 | return 0; |
| 639 | 675 | ||
| 640 | case INTEL_PT_MTC: | 676 | case INTEL_PT_MTC: |
| @@ -675,6 +711,12 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info) | |||
| 675 | break; | 711 | break; |
| 676 | 712 | ||
| 677 | case INTEL_PT_TSC: | 713 | case INTEL_PT_TSC: |
| 714 | /* | ||
| 715 | * For now, do not support using TSC packets - refer | ||
| 716 | * intel_pt_calc_cyc_to_tsc(). | ||
| 717 | */ | ||
| 718 | if (data->from_mtc) | ||
| 719 | return 1; | ||
| 678 | timestamp = pkt_info->packet.payload | | 720 | timestamp = pkt_info->packet.payload | |
| 679 | (data->timestamp & (0xffULL << 56)); | 721 | (data->timestamp & (0xffULL << 56)); |
| 680 | if (data->from_mtc && timestamp < data->timestamp && | 722 | if (data->from_mtc && timestamp < data->timestamp && |
| @@ -733,6 +775,11 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info) | |||
| 733 | 775 | ||
| 734 | case INTEL_PT_TIP_PGD: | 776 | case INTEL_PT_TIP_PGD: |
| 735 | case INTEL_PT_TRACESTOP: | 777 | case INTEL_PT_TRACESTOP: |
| 778 | case INTEL_PT_EXSTOP: | ||
| 779 | case INTEL_PT_EXSTOP_IP: | ||
| 780 | case INTEL_PT_MWAIT: | ||
| 781 | case INTEL_PT_PWRE: | ||
| 782 | case INTEL_PT_PWRX: | ||
| 736 | case INTEL_PT_OVF: | 783 | case INTEL_PT_OVF: |
| 737 | case INTEL_PT_BAD: /* Does not happen */ | 784 | case INTEL_PT_BAD: /* Does not happen */ |
| 738 | default: | 785 | default: |
| @@ -787,6 +834,14 @@ static void intel_pt_calc_cyc_to_tsc(struct intel_pt_decoder *decoder, | |||
| 787 | .cbr_cyc_to_tsc = 0, | 834 | .cbr_cyc_to_tsc = 0, |
| 788 | }; | 835 | }; |
| 789 | 836 | ||
| 837 | /* | ||
| 838 | * For now, do not support using TSC packets for at least the reasons: | ||
| 839 | * 1) timing might have stopped | ||
| 840 | * 2) TSC packets within PSB+ can slip against CYC packets | ||
| 841 | */ | ||
| 842 | if (!from_mtc) | ||
| 843 | return; | ||
| 844 | |||
| 790 | intel_pt_pkt_lookahead(decoder, intel_pt_calc_cyc_cb, &data); | 845 | intel_pt_pkt_lookahead(decoder, intel_pt_calc_cyc_cb, &data); |
| 791 | } | 846 | } |
| 792 | 847 | ||
| @@ -898,6 +953,7 @@ static int intel_pt_walk_insn(struct intel_pt_decoder *decoder, | |||
| 898 | 953 | ||
| 899 | decoder->tot_insn_cnt += insn_cnt; | 954 | decoder->tot_insn_cnt += insn_cnt; |
| 900 | decoder->timestamp_insn_cnt += insn_cnt; | 955 | decoder->timestamp_insn_cnt += insn_cnt; |
| 956 | decoder->sample_insn_cnt += insn_cnt; | ||
| 901 | decoder->period_insn_cnt += insn_cnt; | 957 | decoder->period_insn_cnt += insn_cnt; |
| 902 | 958 | ||
| 903 | if (err) { | 959 | if (err) { |
| @@ -990,6 +1046,57 @@ out_no_progress: | |||
| 990 | return err; | 1046 | return err; |
| 991 | } | 1047 | } |
| 992 | 1048 | ||
| 1049 | static bool intel_pt_fup_event(struct intel_pt_decoder *decoder) | ||
| 1050 | { | ||
| 1051 | bool ret = false; | ||
| 1052 | |||
| 1053 | if (decoder->set_fup_tx_flags) { | ||
| 1054 | decoder->set_fup_tx_flags = false; | ||
| 1055 | decoder->tx_flags = decoder->fup_tx_flags; | ||
| 1056 | decoder->state.type = INTEL_PT_TRANSACTION; | ||
| 1057 | decoder->state.from_ip = decoder->ip; | ||
| 1058 | decoder->state.to_ip = 0; | ||
| 1059 | decoder->state.flags = decoder->fup_tx_flags; | ||
| 1060 | return true; | ||
| 1061 | } | ||
| 1062 | if (decoder->set_fup_ptw) { | ||
| 1063 | decoder->set_fup_ptw = false; | ||
| 1064 | decoder->state.type = INTEL_PT_PTW; | ||
| 1065 | decoder->state.flags |= INTEL_PT_FUP_IP; | ||
| 1066 | decoder->state.from_ip = decoder->ip; | ||
| 1067 | decoder->state.to_ip = 0; | ||
| 1068 | decoder->state.ptw_payload = decoder->fup_ptw_payload; | ||
| 1069 | return true; | ||
| 1070 | } | ||
| 1071 | if (decoder->set_fup_mwait) { | ||
| 1072 | decoder->set_fup_mwait = false; | ||
| 1073 | decoder->state.type = INTEL_PT_MWAIT_OP; | ||
| 1074 | decoder->state.from_ip = decoder->ip; | ||
| 1075 | decoder->state.to_ip = 0; | ||
| 1076 | decoder->state.mwait_payload = decoder->fup_mwait_payload; | ||
| 1077 | ret = true; | ||
| 1078 | } | ||
| 1079 | if (decoder->set_fup_pwre) { | ||
| 1080 | decoder->set_fup_pwre = false; | ||
| 1081 | decoder->state.type |= INTEL_PT_PWR_ENTRY; | ||
| 1082 | decoder->state.type &= ~INTEL_PT_BRANCH; | ||
| 1083 | decoder->state.from_ip = decoder->ip; | ||
| 1084 | decoder->state.to_ip = 0; | ||
| 1085 | decoder->state.pwre_payload = decoder->fup_pwre_payload; | ||
| 1086 | ret = true; | ||
| 1087 | } | ||
| 1088 | if (decoder->set_fup_exstop) { | ||
| 1089 | decoder->set_fup_exstop = false; | ||
| 1090 | decoder->state.type |= INTEL_PT_EX_STOP; | ||
| 1091 | decoder->state.type &= ~INTEL_PT_BRANCH; | ||
| 1092 | decoder->state.flags |= INTEL_PT_FUP_IP; | ||
| 1093 | decoder->state.from_ip = decoder->ip; | ||
| 1094 | decoder->state.to_ip = 0; | ||
| 1095 | ret = true; | ||
| 1096 | } | ||
| 1097 | return ret; | ||
| 1098 | } | ||
| 1099 | |||
| 993 | static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) | 1100 | static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) |
| 994 | { | 1101 | { |
| 995 | struct intel_pt_insn intel_pt_insn; | 1102 | struct intel_pt_insn intel_pt_insn; |
| @@ -1003,15 +1110,8 @@ static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) | |||
| 1003 | if (err == INTEL_PT_RETURN) | 1110 | if (err == INTEL_PT_RETURN) |
| 1004 | return 0; | 1111 | return 0; |
| 1005 | if (err == -EAGAIN) { | 1112 | if (err == -EAGAIN) { |
| 1006 | if (decoder->set_fup_tx_flags) { | 1113 | if (intel_pt_fup_event(decoder)) |
| 1007 | decoder->set_fup_tx_flags = false; | ||
| 1008 | decoder->tx_flags = decoder->fup_tx_flags; | ||
| 1009 | decoder->state.type = INTEL_PT_TRANSACTION; | ||
| 1010 | decoder->state.from_ip = decoder->ip; | ||
| 1011 | decoder->state.to_ip = 0; | ||
| 1012 | decoder->state.flags = decoder->fup_tx_flags; | ||
| 1013 | return 0; | 1114 | return 0; |
| 1014 | } | ||
| 1015 | return err; | 1115 | return err; |
| 1016 | } | 1116 | } |
| 1017 | decoder->set_fup_tx_flags = false; | 1117 | decoder->set_fup_tx_flags = false; |
| @@ -1360,7 +1460,9 @@ static void intel_pt_calc_mtc_timestamp(struct intel_pt_decoder *decoder) | |||
| 1360 | 1460 | ||
| 1361 | static void intel_pt_calc_cbr(struct intel_pt_decoder *decoder) | 1461 | static void intel_pt_calc_cbr(struct intel_pt_decoder *decoder) |
| 1362 | { | 1462 | { |
| 1363 | unsigned int cbr = decoder->packet.payload; | 1463 | unsigned int cbr = decoder->packet.payload & 0xff; |
| 1464 | |||
| 1465 | decoder->cbr_payload = decoder->packet.payload; | ||
| 1364 | 1466 | ||
| 1365 | if (decoder->cbr == cbr) | 1467 | if (decoder->cbr == cbr) |
| 1366 | return; | 1468 | return; |
| @@ -1417,6 +1519,13 @@ static int intel_pt_walk_psbend(struct intel_pt_decoder *decoder) | |||
| 1417 | case INTEL_PT_TRACESTOP: | 1519 | case INTEL_PT_TRACESTOP: |
| 1418 | case INTEL_PT_BAD: | 1520 | case INTEL_PT_BAD: |
| 1419 | case INTEL_PT_PSB: | 1521 | case INTEL_PT_PSB: |
| 1522 | case INTEL_PT_PTWRITE: | ||
| 1523 | case INTEL_PT_PTWRITE_IP: | ||
| 1524 | case INTEL_PT_EXSTOP: | ||
| 1525 | case INTEL_PT_EXSTOP_IP: | ||
| 1526 | case INTEL_PT_MWAIT: | ||
| 1527 | case INTEL_PT_PWRE: | ||
| 1528 | case INTEL_PT_PWRX: | ||
| 1420 | decoder->have_tma = false; | 1529 | decoder->have_tma = false; |
| 1421 | intel_pt_log("ERROR: Unexpected packet\n"); | 1530 | intel_pt_log("ERROR: Unexpected packet\n"); |
| 1422 | return -EAGAIN; | 1531 | return -EAGAIN; |
| @@ -1446,7 +1555,8 @@ static int intel_pt_walk_psbend(struct intel_pt_decoder *decoder) | |||
| 1446 | 1555 | ||
| 1447 | case INTEL_PT_FUP: | 1556 | case INTEL_PT_FUP: |
| 1448 | decoder->pge = true; | 1557 | decoder->pge = true; |
| 1449 | intel_pt_set_last_ip(decoder); | 1558 | if (decoder->packet.count) |
| 1559 | intel_pt_set_last_ip(decoder); | ||
| 1450 | break; | 1560 | break; |
| 1451 | 1561 | ||
| 1452 | case INTEL_PT_MODE_TSX: | 1562 | case INTEL_PT_MODE_TSX: |
| @@ -1497,6 +1607,13 @@ static int intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder) | |||
| 1497 | case INTEL_PT_MODE_TSX: | 1607 | case INTEL_PT_MODE_TSX: |
| 1498 | case INTEL_PT_BAD: | 1608 | case INTEL_PT_BAD: |
| 1499 | case INTEL_PT_PSBEND: | 1609 | case INTEL_PT_PSBEND: |
| 1610 | case INTEL_PT_PTWRITE: | ||
| 1611 | case INTEL_PT_PTWRITE_IP: | ||
| 1612 | case INTEL_PT_EXSTOP: | ||
| 1613 | case INTEL_PT_EXSTOP_IP: | ||
| 1614 | case INTEL_PT_MWAIT: | ||
| 1615 | case INTEL_PT_PWRE: | ||
| 1616 | case INTEL_PT_PWRX: | ||
| 1500 | intel_pt_log("ERROR: Missing TIP after FUP\n"); | 1617 | intel_pt_log("ERROR: Missing TIP after FUP\n"); |
| 1501 | decoder->pkt_state = INTEL_PT_STATE_ERR3; | 1618 | decoder->pkt_state = INTEL_PT_STATE_ERR3; |
| 1502 | return -ENOENT; | 1619 | return -ENOENT; |
| @@ -1625,6 +1742,15 @@ next: | |||
| 1625 | break; | 1742 | break; |
| 1626 | } | 1743 | } |
| 1627 | intel_pt_set_last_ip(decoder); | 1744 | intel_pt_set_last_ip(decoder); |
| 1745 | if (!decoder->branch_enable) { | ||
| 1746 | decoder->ip = decoder->last_ip; | ||
| 1747 | if (intel_pt_fup_event(decoder)) | ||
| 1748 | return 0; | ||
| 1749 | no_tip = false; | ||
| 1750 | break; | ||
| 1751 | } | ||
| 1752 | if (decoder->set_fup_mwait) | ||
| 1753 | no_tip = true; | ||
| 1628 | err = intel_pt_walk_fup(decoder); | 1754 | err = intel_pt_walk_fup(decoder); |
| 1629 | if (err != -EAGAIN) { | 1755 | if (err != -EAGAIN) { |
| 1630 | if (err) | 1756 | if (err) |
| @@ -1650,6 +1776,8 @@ next: | |||
| 1650 | break; | 1776 | break; |
| 1651 | 1777 | ||
| 1652 | case INTEL_PT_PSB: | 1778 | case INTEL_PT_PSB: |
| 1779 | decoder->last_ip = 0; | ||
| 1780 | decoder->have_last_ip = true; | ||
| 1653 | intel_pt_clear_stack(&decoder->stack); | 1781 | intel_pt_clear_stack(&decoder->stack); |
| 1654 | err = intel_pt_walk_psbend(decoder); | 1782 | err = intel_pt_walk_psbend(decoder); |
| 1655 | if (err == -EAGAIN) | 1783 | if (err == -EAGAIN) |
| @@ -1696,6 +1824,16 @@ next: | |||
| 1696 | 1824 | ||
| 1697 | case INTEL_PT_CBR: | 1825 | case INTEL_PT_CBR: |
| 1698 | intel_pt_calc_cbr(decoder); | 1826 | intel_pt_calc_cbr(decoder); |
| 1827 | if (!decoder->branch_enable && | ||
| 1828 | decoder->cbr != decoder->cbr_seen) { | ||
| 1829 | decoder->cbr_seen = decoder->cbr; | ||
| 1830 | decoder->state.type = INTEL_PT_CBR_CHG; | ||
| 1831 | decoder->state.from_ip = decoder->ip; | ||
| 1832 | decoder->state.to_ip = 0; | ||
| 1833 | decoder->state.cbr_payload = | ||
| 1834 | decoder->packet.payload; | ||
| 1835 | return 0; | ||
| 1836 | } | ||
| 1699 | break; | 1837 | break; |
| 1700 | 1838 | ||
| 1701 | case INTEL_PT_MODE_EXEC: | 1839 | case INTEL_PT_MODE_EXEC: |
| @@ -1722,6 +1860,71 @@ next: | |||
| 1722 | case INTEL_PT_PAD: | 1860 | case INTEL_PT_PAD: |
| 1723 | break; | 1861 | break; |
| 1724 | 1862 | ||
| 1863 | case INTEL_PT_PTWRITE_IP: | ||
| 1864 | decoder->fup_ptw_payload = decoder->packet.payload; | ||
| 1865 | err = intel_pt_get_next_packet(decoder); | ||
| 1866 | if (err) | ||
| 1867 | return err; | ||
| 1868 | if (decoder->packet.type == INTEL_PT_FUP) { | ||
| 1869 | decoder->set_fup_ptw = true; | ||
| 1870 | no_tip = true; | ||
| 1871 | } else { | ||
| 1872 | intel_pt_log_at("ERROR: Missing FUP after PTWRITE", | ||
| 1873 | decoder->pos); | ||
| 1874 | } | ||
| 1875 | goto next; | ||
| 1876 | |||
| 1877 | case INTEL_PT_PTWRITE: | ||
| 1878 | decoder->state.type = INTEL_PT_PTW; | ||
| 1879 | decoder->state.from_ip = decoder->ip; | ||
| 1880 | decoder->state.to_ip = 0; | ||
| 1881 | decoder->state.ptw_payload = decoder->packet.payload; | ||
| 1882 | return 0; | ||
| 1883 | |||
| 1884 | case INTEL_PT_MWAIT: | ||
| 1885 | decoder->fup_mwait_payload = decoder->packet.payload; | ||
| 1886 | decoder->set_fup_mwait = true; | ||
| 1887 | break; | ||
| 1888 | |||
| 1889 | case INTEL_PT_PWRE: | ||
| 1890 | if (decoder->set_fup_mwait) { | ||
| 1891 | decoder->fup_pwre_payload = | ||
| 1892 | decoder->packet.payload; | ||
| 1893 | decoder->set_fup_pwre = true; | ||
| 1894 | break; | ||
| 1895 | } | ||
| 1896 | decoder->state.type = INTEL_PT_PWR_ENTRY; | ||
| 1897 | decoder->state.from_ip = decoder->ip; | ||
| 1898 | decoder->state.to_ip = 0; | ||
| 1899 | decoder->state.pwrx_payload = decoder->packet.payload; | ||
| 1900 | return 0; | ||
| 1901 | |||
| 1902 | case INTEL_PT_EXSTOP_IP: | ||
| 1903 | err = intel_pt_get_next_packet(decoder); | ||
| 1904 | if (err) | ||
| 1905 | return err; | ||
| 1906 | if (decoder->packet.type == INTEL_PT_FUP) { | ||
| 1907 | decoder->set_fup_exstop = true; | ||
| 1908 | no_tip = true; | ||
| 1909 | } else { | ||
| 1910 | intel_pt_log_at("ERROR: Missing FUP after EXSTOP", | ||
| 1911 | decoder->pos); | ||
| 1912 | } | ||
| 1913 | goto next; | ||
| 1914 | |||
| 1915 | case INTEL_PT_EXSTOP: | ||
| 1916 | decoder->state.type = INTEL_PT_EX_STOP; | ||
| 1917 | decoder->state.from_ip = decoder->ip; | ||
| 1918 | decoder->state.to_ip = 0; | ||
| 1919 | return 0; | ||
| 1920 | |||
| 1921 | case INTEL_PT_PWRX: | ||
| 1922 | decoder->state.type = INTEL_PT_PWR_EXIT; | ||
| 1923 | decoder->state.from_ip = decoder->ip; | ||
| 1924 | decoder->state.to_ip = 0; | ||
| 1925 | decoder->state.pwrx_payload = decoder->packet.payload; | ||
| 1926 | return 0; | ||
| 1927 | |||
| 1725 | default: | 1928 | default: |
| 1726 | return intel_pt_bug(decoder); | 1929 | return intel_pt_bug(decoder); |
| 1727 | } | 1930 | } |
| @@ -1730,8 +1933,9 @@ next: | |||
| 1730 | 1933 | ||
| 1731 | static inline bool intel_pt_have_ip(struct intel_pt_decoder *decoder) | 1934 | static inline bool intel_pt_have_ip(struct intel_pt_decoder *decoder) |
| 1732 | { | 1935 | { |
| 1733 | return decoder->last_ip || decoder->packet.count == 0 || | 1936 | return decoder->packet.count && |
| 1734 | decoder->packet.count == 3 || decoder->packet.count == 6; | 1937 | (decoder->have_last_ip || decoder->packet.count == 3 || |
| 1938 | decoder->packet.count == 6); | ||
| 1735 | } | 1939 | } |
| 1736 | 1940 | ||
| 1737 | /* Walk PSB+ packets to get in sync. */ | 1941 | /* Walk PSB+ packets to get in sync. */ |
| @@ -1750,6 +1954,13 @@ static int intel_pt_walk_psb(struct intel_pt_decoder *decoder) | |||
| 1750 | __fallthrough; | 1954 | __fallthrough; |
| 1751 | case INTEL_PT_TIP_PGE: | 1955 | case INTEL_PT_TIP_PGE: |
| 1752 | case INTEL_PT_TIP: | 1956 | case INTEL_PT_TIP: |
| 1957 | case INTEL_PT_PTWRITE: | ||
| 1958 | case INTEL_PT_PTWRITE_IP: | ||
| 1959 | case INTEL_PT_EXSTOP: | ||
| 1960 | case INTEL_PT_EXSTOP_IP: | ||
| 1961 | case INTEL_PT_MWAIT: | ||
| 1962 | case INTEL_PT_PWRE: | ||
| 1963 | case INTEL_PT_PWRX: | ||
| 1753 | intel_pt_log("ERROR: Unexpected packet\n"); | 1964 | intel_pt_log("ERROR: Unexpected packet\n"); |
| 1754 | return -ENOENT; | 1965 | return -ENOENT; |
| 1755 | 1966 | ||
| @@ -1854,14 +2065,10 @@ static int intel_pt_walk_to_ip(struct intel_pt_decoder *decoder) | |||
| 1854 | break; | 2065 | break; |
| 1855 | 2066 | ||
| 1856 | case INTEL_PT_FUP: | 2067 | case INTEL_PT_FUP: |
| 1857 | if (decoder->overflow) { | 2068 | if (intel_pt_have_ip(decoder)) |
| 1858 | if (intel_pt_have_ip(decoder)) | 2069 | intel_pt_set_ip(decoder); |
| 1859 | intel_pt_set_ip(decoder); | 2070 | if (decoder->ip) |
| 1860 | if (decoder->ip) | 2071 | return 0; |
| 1861 | return 0; | ||
| 1862 | } | ||
| 1863 | if (decoder->packet.count) | ||
| 1864 | intel_pt_set_last_ip(decoder); | ||
| 1865 | break; | 2072 | break; |
| 1866 | 2073 | ||
| 1867 | case INTEL_PT_MTC: | 2074 | case INTEL_PT_MTC: |
| @@ -1910,6 +2117,9 @@ static int intel_pt_walk_to_ip(struct intel_pt_decoder *decoder) | |||
| 1910 | break; | 2117 | break; |
| 1911 | 2118 | ||
| 1912 | case INTEL_PT_PSB: | 2119 | case INTEL_PT_PSB: |
| 2120 | decoder->last_ip = 0; | ||
| 2121 | decoder->have_last_ip = true; | ||
| 2122 | intel_pt_clear_stack(&decoder->stack); | ||
| 1913 | err = intel_pt_walk_psb(decoder); | 2123 | err = intel_pt_walk_psb(decoder); |
| 1914 | if (err) | 2124 | if (err) |
| 1915 | return err; | 2125 | return err; |
| @@ -1925,6 +2135,13 @@ static int intel_pt_walk_to_ip(struct intel_pt_decoder *decoder) | |||
| 1925 | case INTEL_PT_VMCS: | 2135 | case INTEL_PT_VMCS: |
| 1926 | case INTEL_PT_MNT: | 2136 | case INTEL_PT_MNT: |
| 1927 | case INTEL_PT_PAD: | 2137 | case INTEL_PT_PAD: |
| 2138 | case INTEL_PT_PTWRITE: | ||
| 2139 | case INTEL_PT_PTWRITE_IP: | ||
| 2140 | case INTEL_PT_EXSTOP: | ||
| 2141 | case INTEL_PT_EXSTOP_IP: | ||
| 2142 | case INTEL_PT_MWAIT: | ||
| 2143 | case INTEL_PT_PWRE: | ||
| 2144 | case INTEL_PT_PWRX: | ||
| 1928 | default: | 2145 | default: |
| 1929 | break; | 2146 | break; |
| 1930 | } | 2147 | } |
| @@ -1935,6 +2152,19 @@ static int intel_pt_sync_ip(struct intel_pt_decoder *decoder) | |||
| 1935 | { | 2152 | { |
| 1936 | int err; | 2153 | int err; |
| 1937 | 2154 | ||
| 2155 | decoder->set_fup_tx_flags = false; | ||
| 2156 | decoder->set_fup_ptw = false; | ||
| 2157 | decoder->set_fup_mwait = false; | ||
| 2158 | decoder->set_fup_pwre = false; | ||
| 2159 | decoder->set_fup_exstop = false; | ||
| 2160 | |||
| 2161 | if (!decoder->branch_enable) { | ||
| 2162 | decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; | ||
| 2163 | decoder->overflow = false; | ||
| 2164 | decoder->state.type = 0; /* Do not have a sample */ | ||
| 2165 | return 0; | ||
| 2166 | } | ||
| 2167 | |||
| 1938 | intel_pt_log("Scanning for full IP\n"); | 2168 | intel_pt_log("Scanning for full IP\n"); |
| 1939 | err = intel_pt_walk_to_ip(decoder); | 2169 | err = intel_pt_walk_to_ip(decoder); |
| 1940 | if (err) | 2170 | if (err) |
| @@ -2043,6 +2273,7 @@ static int intel_pt_sync(struct intel_pt_decoder *decoder) | |||
| 2043 | 2273 | ||
| 2044 | decoder->pge = false; | 2274 | decoder->pge = false; |
| 2045 | decoder->continuous_period = false; | 2275 | decoder->continuous_period = false; |
| 2276 | decoder->have_last_ip = false; | ||
| 2046 | decoder->last_ip = 0; | 2277 | decoder->last_ip = 0; |
| 2047 | decoder->ip = 0; | 2278 | decoder->ip = 0; |
| 2048 | intel_pt_clear_stack(&decoder->stack); | 2279 | intel_pt_clear_stack(&decoder->stack); |
| @@ -2051,6 +2282,7 @@ static int intel_pt_sync(struct intel_pt_decoder *decoder) | |||
| 2051 | if (err) | 2282 | if (err) |
| 2052 | return err; | 2283 | return err; |
| 2053 | 2284 | ||
| 2285 | decoder->have_last_ip = true; | ||
| 2054 | decoder->pkt_state = INTEL_PT_STATE_NO_IP; | 2286 | decoder->pkt_state = INTEL_PT_STATE_NO_IP; |
| 2055 | 2287 | ||
| 2056 | err = intel_pt_walk_psb(decoder); | 2288 | err = intel_pt_walk_psb(decoder); |
| @@ -2069,7 +2301,7 @@ static int intel_pt_sync(struct intel_pt_decoder *decoder) | |||
| 2069 | 2301 | ||
| 2070 | static uint64_t intel_pt_est_timestamp(struct intel_pt_decoder *decoder) | 2302 | static uint64_t intel_pt_est_timestamp(struct intel_pt_decoder *decoder) |
| 2071 | { | 2303 | { |
| 2072 | uint64_t est = decoder->timestamp_insn_cnt << 1; | 2304 | uint64_t est = decoder->sample_insn_cnt << 1; |
| 2073 | 2305 | ||
| 2074 | if (!decoder->cbr || !decoder->max_non_turbo_ratio) | 2306 | if (!decoder->cbr || !decoder->max_non_turbo_ratio) |
| 2075 | goto out; | 2307 | goto out; |
| @@ -2077,7 +2309,7 @@ static uint64_t intel_pt_est_timestamp(struct intel_pt_decoder *decoder) | |||
| 2077 | est *= decoder->max_non_turbo_ratio; | 2309 | est *= decoder->max_non_turbo_ratio; |
| 2078 | est /= decoder->cbr; | 2310 | est /= decoder->cbr; |
| 2079 | out: | 2311 | out: |
| 2080 | return decoder->timestamp + est; | 2312 | return decoder->sample_timestamp + est; |
| 2081 | } | 2313 | } |
| 2082 | 2314 | ||
| 2083 | const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) | 2315 | const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) |
| @@ -2093,8 +2325,10 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) | |||
| 2093 | err = intel_pt_sync(decoder); | 2325 | err = intel_pt_sync(decoder); |
| 2094 | break; | 2326 | break; |
| 2095 | case INTEL_PT_STATE_NO_IP: | 2327 | case INTEL_PT_STATE_NO_IP: |
| 2328 | decoder->have_last_ip = false; | ||
| 2096 | decoder->last_ip = 0; | 2329 | decoder->last_ip = 0; |
| 2097 | /* Fall through */ | 2330 | decoder->ip = 0; |
| 2331 | __fallthrough; | ||
| 2098 | case INTEL_PT_STATE_ERR_RESYNC: | 2332 | case INTEL_PT_STATE_ERR_RESYNC: |
| 2099 | err = intel_pt_sync_ip(decoder); | 2333 | err = intel_pt_sync_ip(decoder); |
| 2100 | break; | 2334 | break; |
| @@ -2130,15 +2364,29 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) | |||
| 2130 | } | 2364 | } |
| 2131 | } while (err == -ENOLINK); | 2365 | } while (err == -ENOLINK); |
| 2132 | 2366 | ||
| 2133 | decoder->state.err = err ? intel_pt_ext_err(err) : 0; | 2367 | if (err) { |
| 2134 | decoder->state.timestamp = decoder->timestamp; | 2368 | decoder->state.err = intel_pt_ext_err(err); |
| 2369 | decoder->state.from_ip = decoder->ip; | ||
| 2370 | decoder->sample_timestamp = decoder->timestamp; | ||
| 2371 | decoder->sample_insn_cnt = decoder->timestamp_insn_cnt; | ||
| 2372 | } else { | ||
| 2373 | decoder->state.err = 0; | ||
| 2374 | if (decoder->cbr != decoder->cbr_seen && decoder->state.type) { | ||
| 2375 | decoder->cbr_seen = decoder->cbr; | ||
| 2376 | decoder->state.type |= INTEL_PT_CBR_CHG; | ||
| 2377 | decoder->state.cbr_payload = decoder->cbr_payload; | ||
| 2378 | } | ||
| 2379 | if (intel_pt_sample_time(decoder->pkt_state)) { | ||
| 2380 | decoder->sample_timestamp = decoder->timestamp; | ||
| 2381 | decoder->sample_insn_cnt = decoder->timestamp_insn_cnt; | ||
| 2382 | } | ||
| 2383 | } | ||
| 2384 | |||
| 2385 | decoder->state.timestamp = decoder->sample_timestamp; | ||
| 2135 | decoder->state.est_timestamp = intel_pt_est_timestamp(decoder); | 2386 | decoder->state.est_timestamp = intel_pt_est_timestamp(decoder); |
| 2136 | decoder->state.cr3 = decoder->cr3; | 2387 | decoder->state.cr3 = decoder->cr3; |
| 2137 | decoder->state.tot_insn_cnt = decoder->tot_insn_cnt; | 2388 | decoder->state.tot_insn_cnt = decoder->tot_insn_cnt; |
| 2138 | 2389 | ||
| 2139 | if (err) | ||
| 2140 | decoder->state.from_ip = decoder->ip; | ||
| 2141 | |||
| 2142 | return &decoder->state; | 2390 | return &decoder->state; |
| 2143 | } | 2391 | } |
| 2144 | 2392 | ||
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h index e90619a43c0c..921b22e8ca0e 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h | |||
| @@ -25,11 +25,18 @@ | |||
| 25 | #define INTEL_PT_IN_TX (1 << 0) | 25 | #define INTEL_PT_IN_TX (1 << 0) |
| 26 | #define INTEL_PT_ABORT_TX (1 << 1) | 26 | #define INTEL_PT_ABORT_TX (1 << 1) |
| 27 | #define INTEL_PT_ASYNC (1 << 2) | 27 | #define INTEL_PT_ASYNC (1 << 2) |
| 28 | #define INTEL_PT_FUP_IP (1 << 3) | ||
| 28 | 29 | ||
| 29 | enum intel_pt_sample_type { | 30 | enum intel_pt_sample_type { |
| 30 | INTEL_PT_BRANCH = 1 << 0, | 31 | INTEL_PT_BRANCH = 1 << 0, |
| 31 | INTEL_PT_INSTRUCTION = 1 << 1, | 32 | INTEL_PT_INSTRUCTION = 1 << 1, |
| 32 | INTEL_PT_TRANSACTION = 1 << 2, | 33 | INTEL_PT_TRANSACTION = 1 << 2, |
| 34 | INTEL_PT_PTW = 1 << 3, | ||
| 35 | INTEL_PT_MWAIT_OP = 1 << 4, | ||
| 36 | INTEL_PT_PWR_ENTRY = 1 << 5, | ||
| 37 | INTEL_PT_EX_STOP = 1 << 6, | ||
| 38 | INTEL_PT_PWR_EXIT = 1 << 7, | ||
| 39 | INTEL_PT_CBR_CHG = 1 << 8, | ||
| 33 | }; | 40 | }; |
| 34 | 41 | ||
| 35 | enum intel_pt_period_type { | 42 | enum intel_pt_period_type { |
| @@ -63,6 +70,11 @@ struct intel_pt_state { | |||
| 63 | uint64_t timestamp; | 70 | uint64_t timestamp; |
| 64 | uint64_t est_timestamp; | 71 | uint64_t est_timestamp; |
| 65 | uint64_t trace_nr; | 72 | uint64_t trace_nr; |
| 73 | uint64_t ptw_payload; | ||
| 74 | uint64_t mwait_payload; | ||
| 75 | uint64_t pwre_payload; | ||
| 76 | uint64_t pwrx_payload; | ||
| 77 | uint64_t cbr_payload; | ||
| 66 | uint32_t flags; | 78 | uint32_t flags; |
| 67 | enum intel_pt_insn_op insn_op; | 79 | enum intel_pt_insn_op insn_op; |
| 68 | int insn_len; | 80 | int insn_len; |
| @@ -87,6 +99,7 @@ struct intel_pt_params { | |||
| 87 | bool (*pgd_ip)(uint64_t ip, void *data); | 99 | bool (*pgd_ip)(uint64_t ip, void *data); |
| 88 | void *data; | 100 | void *data; |
| 89 | bool return_compression; | 101 | bool return_compression; |
| 102 | bool branch_enable; | ||
| 90 | uint64_t period; | 103 | uint64_t period; |
| 91 | enum intel_pt_period_type period_type; | 104 | enum intel_pt_period_type period_type; |
| 92 | unsigned max_non_turbo_ratio; | 105 | unsigned max_non_turbo_ratio; |
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-log.h b/tools/perf/util/intel-pt-decoder/intel-pt-log.h index debe751dc3d6..45b64f93f358 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-log.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-log.h | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #ifndef INCLUDE__INTEL_PT_LOG_H__ | 16 | #ifndef INCLUDE__INTEL_PT_LOG_H__ |
| 17 | #define INCLUDE__INTEL_PT_LOG_H__ | 17 | #define INCLUDE__INTEL_PT_LOG_H__ |
| 18 | 18 | ||
| 19 | #include <linux/compiler.h> | ||
| 19 | #include <stdint.h> | 20 | #include <stdint.h> |
| 20 | #include <inttypes.h> | 21 | #include <inttypes.h> |
| 21 | 22 | ||
| @@ -34,8 +35,7 @@ void __intel_pt_log_insn(struct intel_pt_insn *intel_pt_insn, uint64_t ip); | |||
| 34 | void __intel_pt_log_insn_no_data(struct intel_pt_insn *intel_pt_insn, | 35 | void __intel_pt_log_insn_no_data(struct intel_pt_insn *intel_pt_insn, |
| 35 | uint64_t ip); | 36 | uint64_t ip); |
| 36 | 37 | ||
| 37 | __attribute__((format(printf, 1, 2))) | 38 | void __intel_pt_log(const char *fmt, ...) __printf(1, 2); |
| 38 | void __intel_pt_log(const char *fmt, ...); | ||
| 39 | 39 | ||
| 40 | #define intel_pt_log(fmt, ...) \ | 40 | #define intel_pt_log(fmt, ...) \ |
| 41 | do { \ | 41 | do { \ |
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c index 7528ae4f7e28..ba4c9dd18643 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c | |||
| @@ -64,6 +64,13 @@ static const char * const packet_name[] = { | |||
| 64 | [INTEL_PT_PIP] = "PIP", | 64 | [INTEL_PT_PIP] = "PIP", |
| 65 | [INTEL_PT_OVF] = "OVF", | 65 | [INTEL_PT_OVF] = "OVF", |
| 66 | [INTEL_PT_MNT] = "MNT", | 66 | [INTEL_PT_MNT] = "MNT", |
| 67 | [INTEL_PT_PTWRITE] = "PTWRITE", | ||
| 68 | [INTEL_PT_PTWRITE_IP] = "PTWRITE", | ||
| 69 | [INTEL_PT_EXSTOP] = "EXSTOP", | ||
| 70 | [INTEL_PT_EXSTOP_IP] = "EXSTOP", | ||
| 71 | [INTEL_PT_MWAIT] = "MWAIT", | ||
| 72 | [INTEL_PT_PWRE] = "PWRE", | ||
| 73 | [INTEL_PT_PWRX] = "PWRX", | ||
| 67 | }; | 74 | }; |
| 68 | 75 | ||
| 69 | const char *intel_pt_pkt_name(enum intel_pt_pkt_type type) | 76 | const char *intel_pt_pkt_name(enum intel_pt_pkt_type type) |
| @@ -123,7 +130,7 @@ static int intel_pt_get_cbr(const unsigned char *buf, size_t len, | |||
| 123 | if (len < 4) | 130 | if (len < 4) |
| 124 | return INTEL_PT_NEED_MORE_BYTES; | 131 | return INTEL_PT_NEED_MORE_BYTES; |
| 125 | packet->type = INTEL_PT_CBR; | 132 | packet->type = INTEL_PT_CBR; |
| 126 | packet->payload = buf[2]; | 133 | packet->payload = le16_to_cpu(*(uint16_t *)(buf + 2)); |
| 127 | return 4; | 134 | return 4; |
| 128 | } | 135 | } |
| 129 | 136 | ||
| @@ -217,12 +224,80 @@ static int intel_pt_get_3byte(const unsigned char *buf, size_t len, | |||
| 217 | } | 224 | } |
| 218 | } | 225 | } |
| 219 | 226 | ||
| 227 | static int intel_pt_get_ptwrite(const unsigned char *buf, size_t len, | ||
| 228 | struct intel_pt_pkt *packet) | ||
| 229 | { | ||
| 230 | packet->count = (buf[1] >> 5) & 0x3; | ||
| 231 | packet->type = buf[1] & BIT(7) ? INTEL_PT_PTWRITE_IP : | ||
| 232 | INTEL_PT_PTWRITE; | ||
| 233 | |||
| 234 | switch (packet->count) { | ||
| 235 | case 0: | ||
| 236 | if (len < 6) | ||
| 237 | return INTEL_PT_NEED_MORE_BYTES; | ||
| 238 | packet->payload = le32_to_cpu(*(uint32_t *)(buf + 2)); | ||
| 239 | return 6; | ||
| 240 | case 1: | ||
| 241 | if (len < 10) | ||
| 242 | return INTEL_PT_NEED_MORE_BYTES; | ||
| 243 | packet->payload = le64_to_cpu(*(uint64_t *)(buf + 2)); | ||
| 244 | return 10; | ||
| 245 | default: | ||
| 246 | return INTEL_PT_BAD_PACKET; | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | static int intel_pt_get_exstop(struct intel_pt_pkt *packet) | ||
| 251 | { | ||
| 252 | packet->type = INTEL_PT_EXSTOP; | ||
| 253 | return 2; | ||
| 254 | } | ||
| 255 | |||
| 256 | static int intel_pt_get_exstop_ip(struct intel_pt_pkt *packet) | ||
| 257 | { | ||
| 258 | packet->type = INTEL_PT_EXSTOP_IP; | ||
| 259 | return 2; | ||
| 260 | } | ||
| 261 | |||
| 262 | static int intel_pt_get_mwait(const unsigned char *buf, size_t len, | ||
| 263 | struct intel_pt_pkt *packet) | ||
| 264 | { | ||
| 265 | if (len < 10) | ||
| 266 | return INTEL_PT_NEED_MORE_BYTES; | ||
| 267 | packet->type = INTEL_PT_MWAIT; | ||
| 268 | packet->payload = le64_to_cpu(*(uint64_t *)(buf + 2)); | ||
| 269 | return 10; | ||
| 270 | } | ||
| 271 | |||
| 272 | static int intel_pt_get_pwre(const unsigned char *buf, size_t len, | ||
| 273 | struct intel_pt_pkt *packet) | ||
| 274 | { | ||
| 275 | if (len < 4) | ||
| 276 | return INTEL_PT_NEED_MORE_BYTES; | ||
| 277 | packet->type = INTEL_PT_PWRE; | ||
| 278 | memcpy_le64(&packet->payload, buf + 2, 2); | ||
| 279 | return 4; | ||
| 280 | } | ||
| 281 | |||
| 282 | static int intel_pt_get_pwrx(const unsigned char *buf, size_t len, | ||
| 283 | struct intel_pt_pkt *packet) | ||
| 284 | { | ||
| 285 | if (len < 7) | ||
| 286 | return INTEL_PT_NEED_MORE_BYTES; | ||
| 287 | packet->type = INTEL_PT_PWRX; | ||
| 288 | memcpy_le64(&packet->payload, buf + 2, 5); | ||
| 289 | return 7; | ||
| 290 | } | ||
| 291 | |||
| 220 | static int intel_pt_get_ext(const unsigned char *buf, size_t len, | 292 | static int intel_pt_get_ext(const unsigned char *buf, size_t len, |
| 221 | struct intel_pt_pkt *packet) | 293 | struct intel_pt_pkt *packet) |
| 222 | { | 294 | { |
| 223 | if (len < 2) | 295 | if (len < 2) |
| 224 | return INTEL_PT_NEED_MORE_BYTES; | 296 | return INTEL_PT_NEED_MORE_BYTES; |
| 225 | 297 | ||
| 298 | if ((buf[1] & 0x1f) == 0x12) | ||
| 299 | return intel_pt_get_ptwrite(buf, len, packet); | ||
| 300 | |||
| 226 | switch (buf[1]) { | 301 | switch (buf[1]) { |
| 227 | case 0xa3: /* Long TNT */ | 302 | case 0xa3: /* Long TNT */ |
| 228 | return intel_pt_get_long_tnt(buf, len, packet); | 303 | return intel_pt_get_long_tnt(buf, len, packet); |
| @@ -244,6 +319,16 @@ static int intel_pt_get_ext(const unsigned char *buf, size_t len, | |||
| 244 | return intel_pt_get_tma(buf, len, packet); | 319 | return intel_pt_get_tma(buf, len, packet); |
| 245 | case 0xC3: /* 3-byte header */ | 320 | case 0xC3: /* 3-byte header */ |
| 246 | return intel_pt_get_3byte(buf, len, packet); | 321 | return intel_pt_get_3byte(buf, len, packet); |
| 322 | case 0x62: /* EXSTOP no IP */ | ||
| 323 | return intel_pt_get_exstop(packet); | ||
| 324 | case 0xE2: /* EXSTOP with IP */ | ||
| 325 | return intel_pt_get_exstop_ip(packet); | ||
| 326 | case 0xC2: /* MWAIT */ | ||
| 327 | return intel_pt_get_mwait(buf, len, packet); | ||
| 328 | case 0x22: /* PWRE */ | ||
| 329 | return intel_pt_get_pwre(buf, len, packet); | ||
| 330 | case 0xA2: /* PWRX */ | ||
| 331 | return intel_pt_get_pwrx(buf, len, packet); | ||
| 247 | default: | 332 | default: |
| 248 | return INTEL_PT_BAD_PACKET; | 333 | return INTEL_PT_BAD_PACKET; |
| 249 | } | 334 | } |
| @@ -522,6 +607,29 @@ int intel_pt_pkt_desc(const struct intel_pt_pkt *packet, char *buf, | |||
| 522 | ret = snprintf(buf, buf_len, "%s 0x%llx (NR=%d)", | 607 | ret = snprintf(buf, buf_len, "%s 0x%llx (NR=%d)", |
| 523 | name, payload, nr); | 608 | name, payload, nr); |
| 524 | return ret; | 609 | return ret; |
| 610 | case INTEL_PT_PTWRITE: | ||
| 611 | return snprintf(buf, buf_len, "%s 0x%llx IP:0", name, payload); | ||
| 612 | case INTEL_PT_PTWRITE_IP: | ||
| 613 | return snprintf(buf, buf_len, "%s 0x%llx IP:1", name, payload); | ||
| 614 | case INTEL_PT_EXSTOP: | ||
| 615 | return snprintf(buf, buf_len, "%s IP:0", name); | ||
| 616 | case INTEL_PT_EXSTOP_IP: | ||
| 617 | return snprintf(buf, buf_len, "%s IP:1", name); | ||
| 618 | case INTEL_PT_MWAIT: | ||
| 619 | return snprintf(buf, buf_len, "%s 0x%llx Hints 0x%x Extensions 0x%x", | ||
| 620 | name, payload, (unsigned int)(payload & 0xff), | ||
| 621 | (unsigned int)((payload >> 32) & 0x3)); | ||
| 622 | case INTEL_PT_PWRE: | ||
| 623 | return snprintf(buf, buf_len, "%s 0x%llx HW:%u CState:%u Sub-CState:%u", | ||
| 624 | name, payload, !!(payload & 0x80), | ||
| 625 | (unsigned int)((payload >> 12) & 0xf), | ||
| 626 | (unsigned int)((payload >> 8) & 0xf)); | ||
| 627 | case INTEL_PT_PWRX: | ||
| 628 | return snprintf(buf, buf_len, "%s 0x%llx Last CState:%u Deepest CState:%u Wake Reason 0x%x", | ||
| 629 | name, payload, | ||
| 630 | (unsigned int)((payload >> 4) & 0xf), | ||
| 631 | (unsigned int)(payload & 0xf), | ||
| 632 | (unsigned int)((payload >> 8) & 0xf)); | ||
| 525 | default: | 633 | default: |
| 526 | break; | 634 | break; |
| 527 | } | 635 | } |
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.h index 781bb79883bd..73ddc3a88d07 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.h | |||
| @@ -52,6 +52,13 @@ enum intel_pt_pkt_type { | |||
| 52 | INTEL_PT_PIP, | 52 | INTEL_PT_PIP, |
| 53 | INTEL_PT_OVF, | 53 | INTEL_PT_OVF, |
| 54 | INTEL_PT_MNT, | 54 | INTEL_PT_MNT, |
| 55 | INTEL_PT_PTWRITE, | ||
| 56 | INTEL_PT_PTWRITE_IP, | ||
| 57 | INTEL_PT_EXSTOP, | ||
| 58 | INTEL_PT_EXSTOP_IP, | ||
| 59 | INTEL_PT_MWAIT, | ||
| 60 | INTEL_PT_PWRE, | ||
| 61 | INTEL_PT_PWRX, | ||
| 55 | }; | 62 | }; |
| 56 | 63 | ||
| 57 | struct intel_pt_pkt { | 64 | struct intel_pt_pkt { |
diff --git a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt index 767be7c76034..12e377184ee4 100644 --- a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt +++ b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt | |||
| @@ -1009,7 +1009,7 @@ GrpTable: Grp15 | |||
| 1009 | 1: fxstor | RDGSBASE Ry (F3),(11B) | 1009 | 1: fxstor | RDGSBASE Ry (F3),(11B) |
| 1010 | 2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) | 1010 | 2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) |
| 1011 | 3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) | 1011 | 3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) |
| 1012 | 4: XSAVE | 1012 | 4: XSAVE | ptwrite Ey (F3),(11B) |
| 1013 | 5: XRSTOR | lfence (11B) | 1013 | 5: XRSTOR | lfence (11B) |
| 1014 | 6: XSAVEOPT | clwb (66) | mfence (11B) | 1014 | 6: XSAVEOPT | clwb (66) | mfence (11B) |
| 1015 | 7: clflush | clflushopt (66) | sfence (11B) | 1015 | 7: clflush | clflushopt (66) | sfence (11B) |
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 4c7718f87a08..b58f9fd1e2ee 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c | |||
| @@ -81,7 +81,6 @@ struct intel_pt { | |||
| 81 | 81 | ||
| 82 | bool sample_instructions; | 82 | bool sample_instructions; |
| 83 | u64 instructions_sample_type; | 83 | u64 instructions_sample_type; |
| 84 | u64 instructions_sample_period; | ||
| 85 | u64 instructions_id; | 84 | u64 instructions_id; |
| 86 | 85 | ||
| 87 | bool sample_branches; | 86 | bool sample_branches; |
| @@ -93,6 +92,18 @@ struct intel_pt { | |||
| 93 | u64 transactions_sample_type; | 92 | u64 transactions_sample_type; |
| 94 | u64 transactions_id; | 93 | u64 transactions_id; |
| 95 | 94 | ||
| 95 | bool sample_ptwrites; | ||
| 96 | u64 ptwrites_sample_type; | ||
| 97 | u64 ptwrites_id; | ||
| 98 | |||
| 99 | bool sample_pwr_events; | ||
| 100 | u64 pwr_events_sample_type; | ||
| 101 | u64 mwait_id; | ||
| 102 | u64 pwre_id; | ||
| 103 | u64 exstop_id; | ||
| 104 | u64 pwrx_id; | ||
| 105 | u64 cbr_id; | ||
| 106 | |||
| 96 | bool synth_needs_swap; | 107 | bool synth_needs_swap; |
| 97 | 108 | ||
| 98 | u64 tsc_bit; | 109 | u64 tsc_bit; |
| @@ -103,6 +114,7 @@ struct intel_pt { | |||
| 103 | u64 cyc_bit; | 114 | u64 cyc_bit; |
| 104 | u64 noretcomp_bit; | 115 | u64 noretcomp_bit; |
| 105 | unsigned max_non_turbo_ratio; | 116 | unsigned max_non_turbo_ratio; |
| 117 | unsigned cbr2khz; | ||
| 106 | 118 | ||
| 107 | unsigned long num_events; | 119 | unsigned long num_events; |
| 108 | 120 | ||
| @@ -668,6 +680,19 @@ static bool intel_pt_return_compression(struct intel_pt *pt) | |||
| 668 | return true; | 680 | return true; |
| 669 | } | 681 | } |
| 670 | 682 | ||
| 683 | static bool intel_pt_branch_enable(struct intel_pt *pt) | ||
| 684 | { | ||
| 685 | struct perf_evsel *evsel; | ||
| 686 | u64 config; | ||
| 687 | |||
| 688 | evlist__for_each_entry(pt->session->evlist, evsel) { | ||
| 689 | if (intel_pt_get_config(pt, &evsel->attr, &config) && | ||
| 690 | (config & 1) && !(config & 0x2000)) | ||
| 691 | return false; | ||
| 692 | } | ||
| 693 | return true; | ||
| 694 | } | ||
| 695 | |||
| 671 | static unsigned int intel_pt_mtc_period(struct intel_pt *pt) | 696 | static unsigned int intel_pt_mtc_period(struct intel_pt *pt) |
| 672 | { | 697 | { |
| 673 | struct perf_evsel *evsel; | 698 | struct perf_evsel *evsel; |
| @@ -799,6 +824,7 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, | |||
| 799 | params.walk_insn = intel_pt_walk_next_insn; | 824 | params.walk_insn = intel_pt_walk_next_insn; |
| 800 | params.data = ptq; | 825 | params.data = ptq; |
| 801 | params.return_compression = intel_pt_return_compression(pt); | 826 | params.return_compression = intel_pt_return_compression(pt); |
| 827 | params.branch_enable = intel_pt_branch_enable(pt); | ||
| 802 | params.max_non_turbo_ratio = pt->max_non_turbo_ratio; | 828 | params.max_non_turbo_ratio = pt->max_non_turbo_ratio; |
| 803 | params.mtc_period = intel_pt_mtc_period(pt); | 829 | params.mtc_period = intel_pt_mtc_period(pt); |
| 804 | params.tsc_ctc_ratio_n = pt->tsc_ctc_ratio_n; | 830 | params.tsc_ctc_ratio_n = pt->tsc_ctc_ratio_n; |
| @@ -1044,6 +1070,36 @@ static void intel_pt_update_last_branch_rb(struct intel_pt_queue *ptq) | |||
| 1044 | bs->nr += 1; | 1070 | bs->nr += 1; |
| 1045 | } | 1071 | } |
| 1046 | 1072 | ||
| 1073 | static inline bool intel_pt_skip_event(struct intel_pt *pt) | ||
| 1074 | { | ||
| 1075 | return pt->synth_opts.initial_skip && | ||
| 1076 | pt->num_events++ < pt->synth_opts.initial_skip; | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | static void intel_pt_prep_b_sample(struct intel_pt *pt, | ||
| 1080 | struct intel_pt_queue *ptq, | ||
| 1081 | union perf_event *event, | ||
| 1082 | struct perf_sample *sample) | ||
| 1083 | { | ||
| 1084 | event->sample.header.type = PERF_RECORD_SAMPLE; | ||
| 1085 | event->sample.header.misc = PERF_RECORD_MISC_USER; | ||
| 1086 | event->sample.header.size = sizeof(struct perf_event_header); | ||
| 1087 | |||
| 1088 | if (!pt->timeless_decoding) | ||
| 1089 | sample->time = tsc_to_perf_time(ptq->timestamp, &pt->tc); | ||
| 1090 | |||
| 1091 | sample->cpumode = PERF_RECORD_MISC_USER; | ||
| 1092 | sample->ip = ptq->state->from_ip; | ||
| 1093 | sample->pid = ptq->pid; | ||
| 1094 | sample->tid = ptq->tid; | ||
| 1095 | sample->addr = ptq->state->to_ip; | ||
| 1096 | sample->period = 1; | ||
| 1097 | sample->cpu = ptq->cpu; | ||
| 1098 | sample->flags = ptq->flags; | ||
| 1099 | sample->insn_len = ptq->insn_len; | ||
| 1100 | memcpy(sample->insn, ptq->insn, INTEL_PT_INSN_BUF_SZ); | ||
| 1101 | } | ||
| 1102 | |||
| 1047 | static int intel_pt_inject_event(union perf_event *event, | 1103 | static int intel_pt_inject_event(union perf_event *event, |
| 1048 | struct perf_sample *sample, u64 type, | 1104 | struct perf_sample *sample, u64 type, |
| 1049 | bool swapped) | 1105 | bool swapped) |
| @@ -1052,9 +1108,35 @@ static int intel_pt_inject_event(union perf_event *event, | |||
| 1052 | return perf_event__synthesize_sample(event, type, 0, sample, swapped); | 1108 | return perf_event__synthesize_sample(event, type, 0, sample, swapped); |
| 1053 | } | 1109 | } |
| 1054 | 1110 | ||
| 1055 | static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) | 1111 | static inline int intel_pt_opt_inject(struct intel_pt *pt, |
| 1112 | union perf_event *event, | ||
| 1113 | struct perf_sample *sample, u64 type) | ||
| 1114 | { | ||
| 1115 | if (!pt->synth_opts.inject) | ||
| 1116 | return 0; | ||
| 1117 | |||
| 1118 | return intel_pt_inject_event(event, sample, type, pt->synth_needs_swap); | ||
| 1119 | } | ||
| 1120 | |||
| 1121 | static int intel_pt_deliver_synth_b_event(struct intel_pt *pt, | ||
| 1122 | union perf_event *event, | ||
| 1123 | struct perf_sample *sample, u64 type) | ||
| 1056 | { | 1124 | { |
| 1057 | int ret; | 1125 | int ret; |
| 1126 | |||
| 1127 | ret = intel_pt_opt_inject(pt, event, sample, type); | ||
| 1128 | if (ret) | ||
| 1129 | return ret; | ||
| 1130 | |||
| 1131 | ret = perf_session__deliver_synth_event(pt->session, event, sample); | ||
| 1132 | if (ret) | ||
| 1133 | pr_err("Intel PT: failed to deliver event, error %d\n", ret); | ||
| 1134 | |||
| 1135 | return ret; | ||
| 1136 | } | ||
| 1137 | |||
| 1138 | static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) | ||
| 1139 | { | ||
| 1058 | struct intel_pt *pt = ptq->pt; | 1140 | struct intel_pt *pt = ptq->pt; |
| 1059 | union perf_event *event = ptq->event_buf; | 1141 | union perf_event *event = ptq->event_buf; |
| 1060 | struct perf_sample sample = { .ip = 0, }; | 1142 | struct perf_sample sample = { .ip = 0, }; |
| @@ -1066,29 +1148,13 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) | |||
| 1066 | if (pt->branches_filter && !(pt->branches_filter & ptq->flags)) | 1148 | if (pt->branches_filter && !(pt->branches_filter & ptq->flags)) |
| 1067 | return 0; | 1149 | return 0; |
| 1068 | 1150 | ||
| 1069 | if (pt->synth_opts.initial_skip && | 1151 | if (intel_pt_skip_event(pt)) |
| 1070 | pt->num_events++ < pt->synth_opts.initial_skip) | ||
| 1071 | return 0; | 1152 | return 0; |
| 1072 | 1153 | ||
| 1073 | event->sample.header.type = PERF_RECORD_SAMPLE; | 1154 | intel_pt_prep_b_sample(pt, ptq, event, &sample); |
| 1074 | event->sample.header.misc = PERF_RECORD_MISC_USER; | ||
| 1075 | event->sample.header.size = sizeof(struct perf_event_header); | ||
| 1076 | 1155 | ||
| 1077 | if (!pt->timeless_decoding) | ||
| 1078 | sample.time = tsc_to_perf_time(ptq->timestamp, &pt->tc); | ||
| 1079 | |||
| 1080 | sample.cpumode = PERF_RECORD_MISC_USER; | ||
| 1081 | sample.ip = ptq->state->from_ip; | ||
| 1082 | sample.pid = ptq->pid; | ||
| 1083 | sample.tid = ptq->tid; | ||
| 1084 | sample.addr = ptq->state->to_ip; | ||
| 1085 | sample.id = ptq->pt->branches_id; | 1156 | sample.id = ptq->pt->branches_id; |
| 1086 | sample.stream_id = ptq->pt->branches_id; | 1157 | sample.stream_id = ptq->pt->branches_id; |
| 1087 | sample.period = 1; | ||
| 1088 | sample.cpu = ptq->cpu; | ||
| 1089 | sample.flags = ptq->flags; | ||
| 1090 | sample.insn_len = ptq->insn_len; | ||
| 1091 | memcpy(sample.insn, ptq->insn, INTEL_PT_INSN_BUF_SZ); | ||
| 1092 | 1158 | ||
| 1093 | /* | 1159 | /* |
| 1094 | * perf report cannot handle events without a branch stack when using | 1160 | * perf report cannot handle events without a branch stack when using |
| @@ -1105,144 +1171,251 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) | |||
| 1105 | sample.branch_stack = (struct branch_stack *)&dummy_bs; | 1171 | sample.branch_stack = (struct branch_stack *)&dummy_bs; |
| 1106 | } | 1172 | } |
| 1107 | 1173 | ||
| 1108 | if (pt->synth_opts.inject) { | 1174 | return intel_pt_deliver_synth_b_event(pt, event, &sample, |
| 1109 | ret = intel_pt_inject_event(event, &sample, | 1175 | pt->branches_sample_type); |
| 1110 | pt->branches_sample_type, | 1176 | } |
| 1111 | pt->synth_needs_swap); | 1177 | |
| 1112 | if (ret) | 1178 | static void intel_pt_prep_sample(struct intel_pt *pt, |
| 1113 | return ret; | 1179 | struct intel_pt_queue *ptq, |
| 1180 | union perf_event *event, | ||
| 1181 | struct perf_sample *sample) | ||
| 1182 | { | ||
| 1183 | intel_pt_prep_b_sample(pt, ptq, event, sample); | ||
| 1184 | |||
| 1185 | if (pt->synth_opts.callchain) { | ||
| 1186 | thread_stack__sample(ptq->thread, ptq->chain, | ||
| 1187 | pt->synth_opts.callchain_sz, sample->ip); | ||
| 1188 | sample->callchain = ptq->chain; | ||
| 1114 | } | 1189 | } |
| 1115 | 1190 | ||
| 1116 | ret = perf_session__deliver_synth_event(pt->session, event, &sample); | 1191 | if (pt->synth_opts.last_branch) { |
| 1117 | if (ret) | 1192 | intel_pt_copy_last_branch_rb(ptq); |
| 1118 | pr_err("Intel Processor Trace: failed to deliver branch event, error %d\n", | 1193 | sample->branch_stack = ptq->last_branch; |
| 1119 | ret); | 1194 | } |
| 1195 | } | ||
| 1196 | |||
| 1197 | static inline int intel_pt_deliver_synth_event(struct intel_pt *pt, | ||
| 1198 | struct intel_pt_queue *ptq, | ||
| 1199 | union perf_event *event, | ||
| 1200 | struct perf_sample *sample, | ||
| 1201 | u64 type) | ||
| 1202 | { | ||
| 1203 | int ret; | ||
| 1204 | |||
| 1205 | ret = intel_pt_deliver_synth_b_event(pt, event, sample, type); | ||
| 1206 | |||
| 1207 | if (pt->synth_opts.last_branch) | ||
| 1208 | intel_pt_reset_last_branch_rb(ptq); | ||
| 1120 | 1209 | ||
| 1121 | return ret; | 1210 | return ret; |
| 1122 | } | 1211 | } |
| 1123 | 1212 | ||
| 1124 | static int intel_pt_synth_instruction_sample(struct intel_pt_queue *ptq) | 1213 | static int intel_pt_synth_instruction_sample(struct intel_pt_queue *ptq) |
| 1125 | { | 1214 | { |
| 1126 | int ret; | ||
| 1127 | struct intel_pt *pt = ptq->pt; | 1215 | struct intel_pt *pt = ptq->pt; |
| 1128 | union perf_event *event = ptq->event_buf; | 1216 | union perf_event *event = ptq->event_buf; |
| 1129 | struct perf_sample sample = { .ip = 0, }; | 1217 | struct perf_sample sample = { .ip = 0, }; |
| 1130 | 1218 | ||
| 1131 | if (pt->synth_opts.initial_skip && | 1219 | if (intel_pt_skip_event(pt)) |
| 1132 | pt->num_events++ < pt->synth_opts.initial_skip) | ||
| 1133 | return 0; | 1220 | return 0; |
| 1134 | 1221 | ||
| 1135 | event->sample.header.type = PERF_RECORD_SAMPLE; | 1222 | intel_pt_prep_sample(pt, ptq, event, &sample); |
| 1136 | event->sample.header.misc = PERF_RECORD_MISC_USER; | ||
| 1137 | event->sample.header.size = sizeof(struct perf_event_header); | ||
| 1138 | |||
| 1139 | if (!pt->timeless_decoding) | ||
| 1140 | sample.time = tsc_to_perf_time(ptq->timestamp, &pt->tc); | ||
| 1141 | 1223 | ||
| 1142 | sample.cpumode = PERF_RECORD_MISC_USER; | ||
| 1143 | sample.ip = ptq->state->from_ip; | ||
| 1144 | sample.pid = ptq->pid; | ||
| 1145 | sample.tid = ptq->tid; | ||
| 1146 | sample.addr = ptq->state->to_ip; | ||
| 1147 | sample.id = ptq->pt->instructions_id; | 1224 | sample.id = ptq->pt->instructions_id; |
| 1148 | sample.stream_id = ptq->pt->instructions_id; | 1225 | sample.stream_id = ptq->pt->instructions_id; |
| 1149 | sample.period = ptq->state->tot_insn_cnt - ptq->last_insn_cnt; | 1226 | sample.period = ptq->state->tot_insn_cnt - ptq->last_insn_cnt; |
| 1150 | sample.cpu = ptq->cpu; | ||
| 1151 | sample.flags = ptq->flags; | ||
| 1152 | sample.insn_len = ptq->insn_len; | ||
| 1153 | memcpy(sample.insn, ptq->insn, INTEL_PT_INSN_BUF_SZ); | ||
| 1154 | 1227 | ||
| 1155 | ptq->last_insn_cnt = ptq->state->tot_insn_cnt; | 1228 | ptq->last_insn_cnt = ptq->state->tot_insn_cnt; |
| 1156 | 1229 | ||
| 1157 | if (pt->synth_opts.callchain) { | 1230 | return intel_pt_deliver_synth_event(pt, ptq, event, &sample, |
| 1158 | thread_stack__sample(ptq->thread, ptq->chain, | 1231 | pt->instructions_sample_type); |
| 1159 | pt->synth_opts.callchain_sz, sample.ip); | 1232 | } |
| 1160 | sample.callchain = ptq->chain; | ||
| 1161 | } | ||
| 1162 | 1233 | ||
| 1163 | if (pt->synth_opts.last_branch) { | 1234 | static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq) |
| 1164 | intel_pt_copy_last_branch_rb(ptq); | 1235 | { |
| 1165 | sample.branch_stack = ptq->last_branch; | 1236 | struct intel_pt *pt = ptq->pt; |
| 1166 | } | 1237 | union perf_event *event = ptq->event_buf; |
| 1238 | struct perf_sample sample = { .ip = 0, }; | ||
| 1167 | 1239 | ||
| 1168 | if (pt->synth_opts.inject) { | 1240 | if (intel_pt_skip_event(pt)) |
| 1169 | ret = intel_pt_inject_event(event, &sample, | 1241 | return 0; |
| 1170 | pt->instructions_sample_type, | ||
| 1171 | pt->synth_needs_swap); | ||
| 1172 | if (ret) | ||
| 1173 | return ret; | ||
| 1174 | } | ||
| 1175 | 1242 | ||
| 1176 | ret = perf_session__deliver_synth_event(pt->session, event, &sample); | 1243 | intel_pt_prep_sample(pt, ptq, event, &sample); |
| 1177 | if (ret) | ||
| 1178 | pr_err("Intel Processor Trace: failed to deliver instruction event, error %d\n", | ||
| 1179 | ret); | ||
| 1180 | 1244 | ||
| 1181 | if (pt->synth_opts.last_branch) | 1245 | sample.id = ptq->pt->transactions_id; |
| 1182 | intel_pt_reset_last_branch_rb(ptq); | 1246 | sample.stream_id = ptq->pt->transactions_id; |
| 1183 | 1247 | ||
| 1184 | return ret; | 1248 | return intel_pt_deliver_synth_event(pt, ptq, event, &sample, |
| 1249 | pt->transactions_sample_type); | ||
| 1185 | } | 1250 | } |
| 1186 | 1251 | ||
| 1187 | static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq) | 1252 | static void intel_pt_prep_p_sample(struct intel_pt *pt, |
| 1253 | struct intel_pt_queue *ptq, | ||
| 1254 | union perf_event *event, | ||
| 1255 | struct perf_sample *sample) | ||
| 1256 | { | ||
| 1257 | intel_pt_prep_sample(pt, ptq, event, sample); | ||
| 1258 | |||
| 1259 | /* | ||
| 1260 | * Zero IP is used to mean "trace start" but that is not the case for | ||
| 1261 | * power or PTWRITE events with no IP, so clear the flags. | ||
| 1262 | */ | ||
| 1263 | if (!sample->ip) | ||
| 1264 | sample->flags = 0; | ||
| 1265 | } | ||
| 1266 | |||
| 1267 | static int intel_pt_synth_ptwrite_sample(struct intel_pt_queue *ptq) | ||
| 1188 | { | 1268 | { |
| 1189 | int ret; | ||
| 1190 | struct intel_pt *pt = ptq->pt; | 1269 | struct intel_pt *pt = ptq->pt; |
| 1191 | union perf_event *event = ptq->event_buf; | 1270 | union perf_event *event = ptq->event_buf; |
| 1192 | struct perf_sample sample = { .ip = 0, }; | 1271 | struct perf_sample sample = { .ip = 0, }; |
| 1272 | struct perf_synth_intel_ptwrite raw; | ||
| 1193 | 1273 | ||
| 1194 | if (pt->synth_opts.initial_skip && | 1274 | if (intel_pt_skip_event(pt)) |
| 1195 | pt->num_events++ < pt->synth_opts.initial_skip) | ||
| 1196 | return 0; | 1275 | return 0; |
| 1197 | 1276 | ||
| 1198 | event->sample.header.type = PERF_RECORD_SAMPLE; | 1277 | intel_pt_prep_p_sample(pt, ptq, event, &sample); |
| 1199 | event->sample.header.misc = PERF_RECORD_MISC_USER; | ||
| 1200 | event->sample.header.size = sizeof(struct perf_event_header); | ||
| 1201 | 1278 | ||
| 1202 | if (!pt->timeless_decoding) | 1279 | sample.id = ptq->pt->ptwrites_id; |
| 1203 | sample.time = tsc_to_perf_time(ptq->timestamp, &pt->tc); | 1280 | sample.stream_id = ptq->pt->ptwrites_id; |
| 1204 | 1281 | ||
| 1205 | sample.cpumode = PERF_RECORD_MISC_USER; | 1282 | raw.flags = 0; |
| 1206 | sample.ip = ptq->state->from_ip; | 1283 | raw.ip = !!(ptq->state->flags & INTEL_PT_FUP_IP); |
| 1207 | sample.pid = ptq->pid; | 1284 | raw.payload = cpu_to_le64(ptq->state->ptw_payload); |
| 1208 | sample.tid = ptq->tid; | ||
| 1209 | sample.addr = ptq->state->to_ip; | ||
| 1210 | sample.id = ptq->pt->transactions_id; | ||
| 1211 | sample.stream_id = ptq->pt->transactions_id; | ||
| 1212 | sample.period = 1; | ||
| 1213 | sample.cpu = ptq->cpu; | ||
| 1214 | sample.flags = ptq->flags; | ||
| 1215 | sample.insn_len = ptq->insn_len; | ||
| 1216 | memcpy(sample.insn, ptq->insn, INTEL_PT_INSN_BUF_SZ); | ||
| 1217 | 1285 | ||
| 1218 | if (pt->synth_opts.callchain) { | 1286 | sample.raw_size = perf_synth__raw_size(raw); |
| 1219 | thread_stack__sample(ptq->thread, ptq->chain, | 1287 | sample.raw_data = perf_synth__raw_data(&raw); |
| 1220 | pt->synth_opts.callchain_sz, sample.ip); | ||
| 1221 | sample.callchain = ptq->chain; | ||
| 1222 | } | ||
| 1223 | 1288 | ||
| 1224 | if (pt->synth_opts.last_branch) { | 1289 | return intel_pt_deliver_synth_event(pt, ptq, event, &sample, |
| 1225 | intel_pt_copy_last_branch_rb(ptq); | 1290 | pt->ptwrites_sample_type); |
| 1226 | sample.branch_stack = ptq->last_branch; | 1291 | } |
| 1227 | } | ||
| 1228 | 1292 | ||
| 1229 | if (pt->synth_opts.inject) { | 1293 | static int intel_pt_synth_cbr_sample(struct intel_pt_queue *ptq) |
| 1230 | ret = intel_pt_inject_event(event, &sample, | 1294 | { |
| 1231 | pt->transactions_sample_type, | 1295 | struct intel_pt *pt = ptq->pt; |
| 1232 | pt->synth_needs_swap); | 1296 | union perf_event *event = ptq->event_buf; |
| 1233 | if (ret) | 1297 | struct perf_sample sample = { .ip = 0, }; |
| 1234 | return ret; | 1298 | struct perf_synth_intel_cbr raw; |
| 1235 | } | 1299 | u32 flags; |
| 1236 | 1300 | ||
| 1237 | ret = perf_session__deliver_synth_event(pt->session, event, &sample); | 1301 | if (intel_pt_skip_event(pt)) |
| 1238 | if (ret) | 1302 | return 0; |
| 1239 | pr_err("Intel Processor Trace: failed to deliver transaction event, error %d\n", | ||
| 1240 | ret); | ||
| 1241 | 1303 | ||
| 1242 | if (pt->synth_opts.last_branch) | 1304 | intel_pt_prep_p_sample(pt, ptq, event, &sample); |
| 1243 | intel_pt_reset_last_branch_rb(ptq); | ||
| 1244 | 1305 | ||
| 1245 | return ret; | 1306 | sample.id = ptq->pt->cbr_id; |
| 1307 | sample.stream_id = ptq->pt->cbr_id; | ||
| 1308 | |||
| 1309 | flags = (u16)ptq->state->cbr_payload | (pt->max_non_turbo_ratio << 16); | ||
| 1310 | raw.flags = cpu_to_le32(flags); | ||
| 1311 | raw.freq = cpu_to_le32(raw.cbr * pt->cbr2khz); | ||
| 1312 | raw.reserved3 = 0; | ||
| 1313 | |||
| 1314 | sample.raw_size = perf_synth__raw_size(raw); | ||
| 1315 | sample.raw_data = perf_synth__raw_data(&raw); | ||
| 1316 | |||
| 1317 | return intel_pt_deliver_synth_event(pt, ptq, event, &sample, | ||
| 1318 | pt->pwr_events_sample_type); | ||
| 1319 | } | ||
| 1320 | |||
| 1321 | static int intel_pt_synth_mwait_sample(struct intel_pt_queue *ptq) | ||
| 1322 | { | ||
| 1323 | struct intel_pt *pt = ptq->pt; | ||
| 1324 | union perf_event *event = ptq->event_buf; | ||
| 1325 | struct perf_sample sample = { .ip = 0, }; | ||
| 1326 | struct perf_synth_intel_mwait raw; | ||
| 1327 | |||
| 1328 | if (intel_pt_skip_event(pt)) | ||
| 1329 | return 0; | ||
| 1330 | |||
| 1331 | intel_pt_prep_p_sample(pt, ptq, event, &sample); | ||
| 1332 | |||
| 1333 | sample.id = ptq->pt->mwait_id; | ||
| 1334 | sample.stream_id = ptq->pt->mwait_id; | ||
| 1335 | |||
| 1336 | raw.reserved = 0; | ||
| 1337 | raw.payload = cpu_to_le64(ptq->state->mwait_payload); | ||
| 1338 | |||
| 1339 | sample.raw_size = perf_synth__raw_size(raw); | ||
| 1340 | sample.raw_data = perf_synth__raw_data(&raw); | ||
| 1341 | |||
| 1342 | return intel_pt_deliver_synth_event(pt, ptq, event, &sample, | ||
| 1343 | pt->pwr_events_sample_type); | ||
| 1344 | } | ||
| 1345 | |||
| 1346 | static int intel_pt_synth_pwre_sample(struct intel_pt_queue *ptq) | ||
| 1347 | { | ||
| 1348 | struct intel_pt *pt = ptq->pt; | ||
| 1349 | union perf_event *event = ptq->event_buf; | ||
| 1350 | struct perf_sample sample = { .ip = 0, }; | ||
| 1351 | struct perf_synth_intel_pwre raw; | ||
| 1352 | |||
| 1353 | if (intel_pt_skip_event(pt)) | ||
| 1354 | return 0; | ||
| 1355 | |||
| 1356 | intel_pt_prep_p_sample(pt, ptq, event, &sample); | ||
| 1357 | |||
| 1358 | sample.id = ptq->pt->pwre_id; | ||
| 1359 | sample.stream_id = ptq->pt->pwre_id; | ||
| 1360 | |||
| 1361 | raw.reserved = 0; | ||
| 1362 | raw.payload = cpu_to_le64(ptq->state->pwre_payload); | ||
| 1363 | |||
| 1364 | sample.raw_size = perf_synth__raw_size(raw); | ||
| 1365 | sample.raw_data = perf_synth__raw_data(&raw); | ||
| 1366 | |||
| 1367 | return intel_pt_deliver_synth_event(pt, ptq, event, &sample, | ||
| 1368 | pt->pwr_events_sample_type); | ||
| 1369 | } | ||
| 1370 | |||
| 1371 | static int intel_pt_synth_exstop_sample(struct intel_pt_queue *ptq) | ||
| 1372 | { | ||
| 1373 | struct intel_pt *pt = ptq->pt; | ||
| 1374 | union perf_event *event = ptq->event_buf; | ||
| 1375 | struct perf_sample sample = { .ip = 0, }; | ||
| 1376 | struct perf_synth_intel_exstop raw; | ||
| 1377 | |||
| 1378 | if (intel_pt_skip_event(pt)) | ||
| 1379 | return 0; | ||
| 1380 | |||
| 1381 | intel_pt_prep_p_sample(pt, ptq, event, &sample); | ||
| 1382 | |||
| 1383 | sample.id = ptq->pt->exstop_id; | ||
| 1384 | sample.stream_id = ptq->pt->exstop_id; | ||
| 1385 | |||
| 1386 | raw.flags = 0; | ||
| 1387 | raw.ip = !!(ptq->state->flags & INTEL_PT_FUP_IP); | ||
| 1388 | |||
| 1389 | sample.raw_size = perf_synth__raw_size(raw); | ||
| 1390 | sample.raw_data = perf_synth__raw_data(&raw); | ||
| 1391 | |||
| 1392 | return intel_pt_deliver_synth_event(pt, ptq, event, &sample, | ||
| 1393 | pt->pwr_events_sample_type); | ||
| 1394 | } | ||
| 1395 | |||
| 1396 | static int intel_pt_synth_pwrx_sample(struct intel_pt_queue *ptq) | ||
| 1397 | { | ||
| 1398 | struct intel_pt *pt = ptq->pt; | ||
| 1399 | union perf_event *event = ptq->event_buf; | ||
| 1400 | struct perf_sample sample = { .ip = 0, }; | ||
| 1401 | struct perf_synth_intel_pwrx raw; | ||
| 1402 | |||
| 1403 | if (intel_pt_skip_event(pt)) | ||
| 1404 | return 0; | ||
| 1405 | |||
| 1406 | intel_pt_prep_p_sample(pt, ptq, event, &sample); | ||
| 1407 | |||
| 1408 | sample.id = ptq->pt->pwrx_id; | ||
| 1409 | sample.stream_id = ptq->pt->pwrx_id; | ||
| 1410 | |||
| 1411 | raw.reserved = 0; | ||
| 1412 | raw.payload = cpu_to_le64(ptq->state->pwrx_payload); | ||
| 1413 | |||
| 1414 | sample.raw_size = perf_synth__raw_size(raw); | ||
| 1415 | sample.raw_data = perf_synth__raw_data(&raw); | ||
| 1416 | |||
| 1417 | return intel_pt_deliver_synth_event(pt, ptq, event, &sample, | ||
| 1418 | pt->pwr_events_sample_type); | ||
| 1246 | } | 1419 | } |
| 1247 | 1420 | ||
| 1248 | static int intel_pt_synth_error(struct intel_pt *pt, int code, int cpu, | 1421 | static int intel_pt_synth_error(struct intel_pt *pt, int code, int cpu, |
| @@ -1296,6 +1469,10 @@ static inline bool intel_pt_is_switch_ip(struct intel_pt_queue *ptq, u64 ip) | |||
| 1296 | PERF_IP_FLAG_INTERRUPT | PERF_IP_FLAG_TX_ABORT)); | 1469 | PERF_IP_FLAG_INTERRUPT | PERF_IP_FLAG_TX_ABORT)); |
| 1297 | } | 1470 | } |
| 1298 | 1471 | ||
| 1472 | #define INTEL_PT_PWR_EVT (INTEL_PT_MWAIT_OP | INTEL_PT_PWR_ENTRY | \ | ||
| 1473 | INTEL_PT_EX_STOP | INTEL_PT_PWR_EXIT | \ | ||
| 1474 | INTEL_PT_CBR_CHG) | ||
| 1475 | |||
| 1299 | static int intel_pt_sample(struct intel_pt_queue *ptq) | 1476 | static int intel_pt_sample(struct intel_pt_queue *ptq) |
| 1300 | { | 1477 | { |
| 1301 | const struct intel_pt_state *state = ptq->state; | 1478 | const struct intel_pt_state *state = ptq->state; |
| @@ -1307,24 +1484,52 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) | |||
| 1307 | 1484 | ||
| 1308 | ptq->have_sample = false; | 1485 | ptq->have_sample = false; |
| 1309 | 1486 | ||
| 1310 | if (pt->sample_instructions && | 1487 | if (pt->sample_pwr_events && (state->type & INTEL_PT_PWR_EVT)) { |
| 1311 | (state->type & INTEL_PT_INSTRUCTION) && | 1488 | if (state->type & INTEL_PT_CBR_CHG) { |
| 1312 | (!pt->synth_opts.initial_skip || | 1489 | err = intel_pt_synth_cbr_sample(ptq); |
| 1313 | pt->num_events++ >= pt->synth_opts.initial_skip)) { | 1490 | if (err) |
| 1491 | return err; | ||
| 1492 | } | ||
| 1493 | if (state->type & INTEL_PT_MWAIT_OP) { | ||
| 1494 | err = intel_pt_synth_mwait_sample(ptq); | ||
| 1495 | if (err) | ||
| 1496 | return err; | ||
| 1497 | } | ||
| 1498 | if (state->type & INTEL_PT_PWR_ENTRY) { | ||
| 1499 | err = intel_pt_synth_pwre_sample(ptq); | ||
| 1500 | if (err) | ||
| 1501 | return err; | ||
| 1502 | } | ||
| 1503 | if (state->type & INTEL_PT_EX_STOP) { | ||
| 1504 | err = intel_pt_synth_exstop_sample(ptq); | ||
| 1505 | if (err) | ||
| 1506 | return err; | ||
| 1507 | } | ||
| 1508 | if (state->type & INTEL_PT_PWR_EXIT) { | ||
| 1509 | err = intel_pt_synth_pwrx_sample(ptq); | ||
| 1510 | if (err) | ||
| 1511 | return err; | ||
| 1512 | } | ||
| 1513 | } | ||
| 1514 | |||
| 1515 | if (pt->sample_instructions && (state->type & INTEL_PT_INSTRUCTION)) { | ||
| 1314 | err = intel_pt_synth_instruction_sample(ptq); | 1516 | err = intel_pt_synth_instruction_sample(ptq); |
| 1315 | if (err) | 1517 | if (err) |
| 1316 | return err; | 1518 | return err; |
| 1317 | } | 1519 | } |
| 1318 | 1520 | ||
| 1319 | if (pt->sample_transactions && | 1521 | if (pt->sample_transactions && (state->type & INTEL_PT_TRANSACTION)) { |
| 1320 | (state->type & INTEL_PT_TRANSACTION) && | ||
| 1321 | (!pt->synth_opts.initial_skip || | ||
| 1322 | pt->num_events++ >= pt->synth_opts.initial_skip)) { | ||
| 1323 | err = intel_pt_synth_transaction_sample(ptq); | 1522 | err = intel_pt_synth_transaction_sample(ptq); |
| 1324 | if (err) | 1523 | if (err) |
| 1325 | return err; | 1524 | return err; |
| 1326 | } | 1525 | } |
| 1327 | 1526 | ||
| 1527 | if (pt->sample_ptwrites && (state->type & INTEL_PT_PTW)) { | ||
| 1528 | err = intel_pt_synth_ptwrite_sample(ptq); | ||
| 1529 | if (err) | ||
| 1530 | return err; | ||
| 1531 | } | ||
| 1532 | |||
| 1328 | if (!(state->type & INTEL_PT_BRANCH)) | 1533 | if (!(state->type & INTEL_PT_BRANCH)) |
| 1329 | return 0; | 1534 | return 0; |
| 1330 | 1535 | ||
| @@ -1925,36 +2130,65 @@ static int intel_pt_event_synth(struct perf_tool *tool, | |||
| 1925 | NULL); | 2130 | NULL); |
| 1926 | } | 2131 | } |
| 1927 | 2132 | ||
| 1928 | static int intel_pt_synth_event(struct perf_session *session, | 2133 | static int intel_pt_synth_event(struct perf_session *session, const char *name, |
| 1929 | struct perf_event_attr *attr, u64 id) | 2134 | struct perf_event_attr *attr, u64 id) |
| 1930 | { | 2135 | { |
| 1931 | struct intel_pt_synth intel_pt_synth; | 2136 | struct intel_pt_synth intel_pt_synth; |
| 2137 | int err; | ||
| 2138 | |||
| 2139 | pr_debug("Synthesizing '%s' event with id %" PRIu64 " sample type %#" PRIx64 "\n", | ||
| 2140 | name, id, (u64)attr->sample_type); | ||
| 1932 | 2141 | ||
| 1933 | memset(&intel_pt_synth, 0, sizeof(struct intel_pt_synth)); | 2142 | memset(&intel_pt_synth, 0, sizeof(struct intel_pt_synth)); |
| 1934 | intel_pt_synth.session = session; | 2143 | intel_pt_synth.session = session; |
| 1935 | 2144 | ||
| 1936 | return perf_event__synthesize_attr(&intel_pt_synth.dummy_tool, attr, 1, | 2145 | err = perf_event__synthesize_attr(&intel_pt_synth.dummy_tool, attr, 1, |
| 1937 | &id, intel_pt_event_synth); | 2146 | &id, intel_pt_event_synth); |
| 2147 | if (err) | ||
| 2148 | pr_err("%s: failed to synthesize '%s' event type\n", | ||
| 2149 | __func__, name); | ||
| 2150 | |||
| 2151 | return err; | ||
| 1938 | } | 2152 | } |
| 1939 | 2153 | ||
| 1940 | static int intel_pt_synth_events(struct intel_pt *pt, | 2154 | static void intel_pt_set_event_name(struct perf_evlist *evlist, u64 id, |
| 1941 | struct perf_session *session) | 2155 | const char *name) |
| 1942 | { | 2156 | { |
| 1943 | struct perf_evlist *evlist = session->evlist; | ||
| 1944 | struct perf_evsel *evsel; | 2157 | struct perf_evsel *evsel; |
| 1945 | struct perf_event_attr attr; | ||
| 1946 | bool found = false; | ||
| 1947 | u64 id; | ||
| 1948 | int err; | ||
| 1949 | 2158 | ||
| 1950 | evlist__for_each_entry(evlist, evsel) { | 2159 | evlist__for_each_entry(evlist, evsel) { |
| 1951 | if (evsel->attr.type == pt->pmu_type && evsel->ids) { | 2160 | if (evsel->id && evsel->id[0] == id) { |
| 1952 | found = true; | 2161 | if (evsel->name) |
| 2162 | zfree(&evsel->name); | ||
| 2163 | evsel->name = strdup(name); | ||
| 1953 | break; | 2164 | break; |
| 1954 | } | 2165 | } |
| 1955 | } | 2166 | } |
| 2167 | } | ||
| 1956 | 2168 | ||
| 1957 | if (!found) { | 2169 | static struct perf_evsel *intel_pt_evsel(struct intel_pt *pt, |
| 2170 | struct perf_evlist *evlist) | ||
| 2171 | { | ||
| 2172 | struct perf_evsel *evsel; | ||
| 2173 | |||
| 2174 | evlist__for_each_entry(evlist, evsel) { | ||
| 2175 | if (evsel->attr.type == pt->pmu_type && evsel->ids) | ||
| 2176 | return evsel; | ||
| 2177 | } | ||
| 2178 | |||
| 2179 | return NULL; | ||
| 2180 | } | ||
| 2181 | |||
| 2182 | static int intel_pt_synth_events(struct intel_pt *pt, | ||
| 2183 | struct perf_session *session) | ||
| 2184 | { | ||
| 2185 | struct perf_evlist *evlist = session->evlist; | ||
| 2186 | struct perf_evsel *evsel = intel_pt_evsel(pt, evlist); | ||
| 2187 | struct perf_event_attr attr; | ||
| 2188 | u64 id; | ||
| 2189 | int err; | ||
| 2190 | |||
| 2191 | if (!evsel) { | ||
| 1958 | pr_debug("There are no selected events with Intel Processor Trace data\n"); | 2192 | pr_debug("There are no selected events with Intel Processor Trace data\n"); |
| 1959 | return 0; | 2193 | return 0; |
| 1960 | } | 2194 | } |
| @@ -1983,6 +2217,25 @@ static int intel_pt_synth_events(struct intel_pt *pt, | |||
| 1983 | if (!id) | 2217 | if (!id) |
| 1984 | id = 1; | 2218 | id = 1; |
| 1985 | 2219 | ||
| 2220 | if (pt->synth_opts.branches) { | ||
| 2221 | attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS; | ||
| 2222 | attr.sample_period = 1; | ||
| 2223 | attr.sample_type |= PERF_SAMPLE_ADDR; | ||
| 2224 | err = intel_pt_synth_event(session, "branches", &attr, id); | ||
| 2225 | if (err) | ||
| 2226 | return err; | ||
| 2227 | pt->sample_branches = true; | ||
| 2228 | pt->branches_sample_type = attr.sample_type; | ||
| 2229 | pt->branches_id = id; | ||
| 2230 | id += 1; | ||
| 2231 | attr.sample_type &= ~(u64)PERF_SAMPLE_ADDR; | ||
| 2232 | } | ||
| 2233 | |||
| 2234 | if (pt->synth_opts.callchain) | ||
| 2235 | attr.sample_type |= PERF_SAMPLE_CALLCHAIN; | ||
| 2236 | if (pt->synth_opts.last_branch) | ||
| 2237 | attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; | ||
| 2238 | |||
| 1986 | if (pt->synth_opts.instructions) { | 2239 | if (pt->synth_opts.instructions) { |
| 1987 | attr.config = PERF_COUNT_HW_INSTRUCTIONS; | 2240 | attr.config = PERF_COUNT_HW_INSTRUCTIONS; |
| 1988 | if (pt->synth_opts.period_type == PERF_ITRACE_PERIOD_NANOSECS) | 2241 | if (pt->synth_opts.period_type == PERF_ITRACE_PERIOD_NANOSECS) |
| @@ -1990,70 +2243,90 @@ static int intel_pt_synth_events(struct intel_pt *pt, | |||
| 1990 | intel_pt_ns_to_ticks(pt, pt->synth_opts.period); | 2243 | intel_pt_ns_to_ticks(pt, pt->synth_opts.period); |
| 1991 | else | 2244 | else |
| 1992 | attr.sample_period = pt->synth_opts.period; | 2245 | attr.sample_period = pt->synth_opts.period; |
| 1993 | pt->instructions_sample_period = attr.sample_period; | 2246 | err = intel_pt_synth_event(session, "instructions", &attr, id); |
| 1994 | if (pt->synth_opts.callchain) | 2247 | if (err) |
| 1995 | attr.sample_type |= PERF_SAMPLE_CALLCHAIN; | ||
| 1996 | if (pt->synth_opts.last_branch) | ||
| 1997 | attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; | ||
| 1998 | pr_debug("Synthesizing 'instructions' event with id %" PRIu64 " sample type %#" PRIx64 "\n", | ||
| 1999 | id, (u64)attr.sample_type); | ||
| 2000 | err = intel_pt_synth_event(session, &attr, id); | ||
| 2001 | if (err) { | ||
| 2002 | pr_err("%s: failed to synthesize 'instructions' event type\n", | ||
| 2003 | __func__); | ||
| 2004 | return err; | 2248 | return err; |
| 2005 | } | ||
| 2006 | pt->sample_instructions = true; | 2249 | pt->sample_instructions = true; |
| 2007 | pt->instructions_sample_type = attr.sample_type; | 2250 | pt->instructions_sample_type = attr.sample_type; |
| 2008 | pt->instructions_id = id; | 2251 | pt->instructions_id = id; |
| 2009 | id += 1; | 2252 | id += 1; |
| 2010 | } | 2253 | } |
| 2011 | 2254 | ||
| 2255 | attr.sample_type &= ~(u64)PERF_SAMPLE_PERIOD; | ||
| 2256 | attr.sample_period = 1; | ||
| 2257 | |||
| 2012 | if (pt->synth_opts.transactions) { | 2258 | if (pt->synth_opts.transactions) { |
| 2013 | attr.config = PERF_COUNT_HW_INSTRUCTIONS; | 2259 | attr.config = PERF_COUNT_HW_INSTRUCTIONS; |
| 2014 | attr.sample_period = 1; | 2260 | err = intel_pt_synth_event(session, "transactions", &attr, id); |
| 2015 | if (pt->synth_opts.callchain) | 2261 | if (err) |
| 2016 | attr.sample_type |= PERF_SAMPLE_CALLCHAIN; | ||
| 2017 | if (pt->synth_opts.last_branch) | ||
| 2018 | attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; | ||
| 2019 | pr_debug("Synthesizing 'transactions' event with id %" PRIu64 " sample type %#" PRIx64 "\n", | ||
| 2020 | id, (u64)attr.sample_type); | ||
| 2021 | err = intel_pt_synth_event(session, &attr, id); | ||
| 2022 | if (err) { | ||
| 2023 | pr_err("%s: failed to synthesize 'transactions' event type\n", | ||
| 2024 | __func__); | ||
| 2025 | return err; | 2262 | return err; |
| 2026 | } | ||
| 2027 | pt->sample_transactions = true; | 2263 | pt->sample_transactions = true; |
| 2264 | pt->transactions_sample_type = attr.sample_type; | ||
| 2028 | pt->transactions_id = id; | 2265 | pt->transactions_id = id; |
| 2266 | intel_pt_set_event_name(evlist, id, "transactions"); | ||
| 2029 | id += 1; | 2267 | id += 1; |
| 2030 | evlist__for_each_entry(evlist, evsel) { | ||
| 2031 | if (evsel->id && evsel->id[0] == pt->transactions_id) { | ||
| 2032 | if (evsel->name) | ||
| 2033 | zfree(&evsel->name); | ||
| 2034 | evsel->name = strdup("transactions"); | ||
| 2035 | break; | ||
| 2036 | } | ||
| 2037 | } | ||
| 2038 | } | 2268 | } |
| 2039 | 2269 | ||
| 2040 | if (pt->synth_opts.branches) { | 2270 | attr.type = PERF_TYPE_SYNTH; |
| 2041 | attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS; | 2271 | attr.sample_type |= PERF_SAMPLE_RAW; |
| 2042 | attr.sample_period = 1; | 2272 | |
| 2043 | attr.sample_type |= PERF_SAMPLE_ADDR; | 2273 | if (pt->synth_opts.ptwrites) { |
| 2044 | attr.sample_type &= ~(u64)PERF_SAMPLE_CALLCHAIN; | 2274 | attr.config = PERF_SYNTH_INTEL_PTWRITE; |
| 2045 | attr.sample_type &= ~(u64)PERF_SAMPLE_BRANCH_STACK; | 2275 | err = intel_pt_synth_event(session, "ptwrite", &attr, id); |
| 2046 | pr_debug("Synthesizing 'branches' event with id %" PRIu64 " sample type %#" PRIx64 "\n", | 2276 | if (err) |
| 2047 | id, (u64)attr.sample_type); | ||
| 2048 | err = intel_pt_synth_event(session, &attr, id); | ||
| 2049 | if (err) { | ||
| 2050 | pr_err("%s: failed to synthesize 'branches' event type\n", | ||
| 2051 | __func__); | ||
| 2052 | return err; | 2277 | return err; |
| 2053 | } | 2278 | pt->sample_ptwrites = true; |
| 2054 | pt->sample_branches = true; | 2279 | pt->ptwrites_sample_type = attr.sample_type; |
| 2055 | pt->branches_sample_type = attr.sample_type; | 2280 | pt->ptwrites_id = id; |
| 2056 | pt->branches_id = id; | 2281 | intel_pt_set_event_name(evlist, id, "ptwrite"); |
| 2282 | id += 1; | ||
| 2283 | } | ||
| 2284 | |||
| 2285 | if (pt->synth_opts.pwr_events) { | ||
| 2286 | pt->sample_pwr_events = true; | ||
| 2287 | pt->pwr_events_sample_type = attr.sample_type; | ||
| 2288 | |||
| 2289 | attr.config = PERF_SYNTH_INTEL_CBR; | ||
| 2290 | err = intel_pt_synth_event(session, "cbr", &attr, id); | ||
| 2291 | if (err) | ||
| 2292 | return err; | ||
| 2293 | pt->cbr_id = id; | ||
| 2294 | intel_pt_set_event_name(evlist, id, "cbr"); | ||
| 2295 | id += 1; | ||
| 2296 | } | ||
| 2297 | |||
| 2298 | if (pt->synth_opts.pwr_events && (evsel->attr.config & 0x10)) { | ||
| 2299 | attr.config = PERF_SYNTH_INTEL_MWAIT; | ||
| 2300 | err = intel_pt_synth_event(session, "mwait", &attr, id); | ||
| 2301 | if (err) | ||
| 2302 | return err; | ||
| 2303 | pt->mwait_id = id; | ||
| 2304 | intel_pt_set_event_name(evlist, id, "mwait"); | ||
| 2305 | id += 1; | ||
| 2306 | |||
| 2307 | attr.config = PERF_SYNTH_INTEL_PWRE; | ||
| 2308 | err = intel_pt_synth_event(session, "pwre", &attr, id); | ||
| 2309 | if (err) | ||
| 2310 | return err; | ||
| 2311 | pt->pwre_id = id; | ||
| 2312 | intel_pt_set_event_name(evlist, id, "pwre"); | ||
| 2313 | id += 1; | ||
| 2314 | |||
| 2315 | attr.config = PERF_SYNTH_INTEL_EXSTOP; | ||
| 2316 | err = intel_pt_synth_event(session, "exstop", &attr, id); | ||
| 2317 | if (err) | ||
| 2318 | return err; | ||
| 2319 | pt->exstop_id = id; | ||
| 2320 | intel_pt_set_event_name(evlist, id, "exstop"); | ||
| 2321 | id += 1; | ||
| 2322 | |||
| 2323 | attr.config = PERF_SYNTH_INTEL_PWRX; | ||
| 2324 | err = intel_pt_synth_event(session, "pwrx", &attr, id); | ||
| 2325 | if (err) | ||
| 2326 | return err; | ||
| 2327 | pt->pwrx_id = id; | ||
| 2328 | intel_pt_set_event_name(evlist, id, "pwrx"); | ||
| 2329 | id += 1; | ||
| 2057 | } | 2330 | } |
| 2058 | 2331 | ||
| 2059 | pt->synth_needs_swap = evsel->needs_swap; | 2332 | pt->synth_needs_swap = evsel->needs_swap; |
| @@ -2322,6 +2595,7 @@ int intel_pt_process_auxtrace_info(union perf_event *event, | |||
| 2322 | intel_pt_log("TSC frequency %"PRIu64"\n", tsc_freq); | 2595 | intel_pt_log("TSC frequency %"PRIu64"\n", tsc_freq); |
| 2323 | intel_pt_log("Maximum non-turbo ratio %u\n", | 2596 | intel_pt_log("Maximum non-turbo ratio %u\n", |
| 2324 | pt->max_non_turbo_ratio); | 2597 | pt->max_non_turbo_ratio); |
| 2598 | pt->cbr2khz = tsc_freq / pt->max_non_turbo_ratio / 1000; | ||
| 2325 | } | 2599 | } |
| 2326 | 2600 | ||
| 2327 | if (pt->synth_opts.calls) | 2601 | if (pt->synth_opts.calls) |
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index ea7f450dc609..389e9729331f 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #define __PMU_H | 2 | #define __PMU_H |
| 3 | 3 | ||
| 4 | #include <linux/bitmap.h> | 4 | #include <linux/bitmap.h> |
| 5 | #include <linux/compiler.h> | ||
| 5 | #include <linux/perf_event.h> | 6 | #include <linux/perf_event.h> |
| 6 | #include <stdbool.h> | 7 | #include <stdbool.h> |
| 7 | #include "evsel.h" | 8 | #include "evsel.h" |
| @@ -83,8 +84,7 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet, | |||
| 83 | bool long_desc, bool details_flag); | 84 | bool long_desc, bool details_flag); |
| 84 | bool pmu_have_event(const char *pname, const char *name); | 85 | bool pmu_have_event(const char *pname, const char *name); |
| 85 | 86 | ||
| 86 | int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, | 87 | int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, ...) __scanf(3, 4); |
| 87 | ...) __attribute__((format(scanf, 3, 4))); | ||
| 88 | 88 | ||
| 89 | int perf_pmu__test(void); | 89 | int perf_pmu__test(void); |
| 90 | 90 | ||
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 373842656fb6..5812947418dd 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | #ifndef _PROBE_EVENT_H | 1 | #ifndef _PROBE_EVENT_H |
| 2 | #define _PROBE_EVENT_H | 2 | #define _PROBE_EVENT_H |
| 3 | 3 | ||
| 4 | #include <linux/compiler.h> | ||
| 4 | #include <stdbool.h> | 5 | #include <stdbool.h> |
| 5 | #include "intlist.h" | 6 | #include "intlist.h" |
| 6 | 7 | ||
| @@ -171,8 +172,7 @@ void arch__fix_tev_from_maps(struct perf_probe_event *pev, | |||
| 171 | struct symbol *sym); | 172 | struct symbol *sym); |
| 172 | 173 | ||
| 173 | /* If there is no space to write, returns -E2BIG. */ | 174 | /* If there is no space to write, returns -E2BIG. */ |
| 174 | int e_snprintf(char *str, size_t size, const char *format, ...) | 175 | int e_snprintf(char *str, size_t size, const char *format, ...) __printf(3, 4); |
| 175 | __attribute__((format(printf, 3, 4))); | ||
| 176 | 176 | ||
| 177 | /* Maximum index number of event-name postfix */ | 177 | /* Maximum index number of event-name postfix */ |
| 178 | #define MAX_EVENT_INDEX 1024 | 178 | #define MAX_EVENT_INDEX 1024 |
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 40de3cb40d21..57b7a00e6f16 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <stdbool.h> | 28 | #include <stdbool.h> |
| 29 | #include <errno.h> | 29 | #include <errno.h> |
| 30 | #include <linux/bitmap.h> | 30 | #include <linux/bitmap.h> |
| 31 | #include <linux/compiler.h> | ||
| 31 | #include <linux/time64.h> | 32 | #include <linux/time64.h> |
| 32 | 33 | ||
| 33 | #include "../../perf.h" | 34 | #include "../../perf.h" |
| @@ -84,7 +85,7 @@ struct tables { | |||
| 84 | 85 | ||
| 85 | static struct tables tables_global; | 86 | static struct tables tables_global; |
| 86 | 87 | ||
| 87 | static void handler_call_die(const char *handler_name) NORETURN; | 88 | static void handler_call_die(const char *handler_name) __noreturn; |
| 88 | static void handler_call_die(const char *handler_name) | 89 | static void handler_call_die(const char *handler_name) |
| 89 | { | 90 | { |
| 90 | PyErr_Print(); | 91 | PyErr_Print(); |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 7dc1096264c5..d19c40a81040 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
| @@ -2035,7 +2035,7 @@ int perf_session__cpu_bitmap(struct perf_session *session, | |||
| 2035 | 2035 | ||
| 2036 | if (!(evsel->attr.sample_type & PERF_SAMPLE_CPU)) { | 2036 | if (!(evsel->attr.sample_type & PERF_SAMPLE_CPU)) { |
| 2037 | pr_err("File does not contain CPU events. " | 2037 | pr_err("File does not contain CPU events. " |
| 2038 | "Remove -c option to proceed.\n"); | 2038 | "Remove -C option to proceed.\n"); |
| 2039 | return -1; | 2039 | return -1; |
| 2040 | } | 2040 | } |
| 2041 | } | 2041 | } |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 5762ae4e9e91..8b327c955a4f 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
| @@ -2532,12 +2532,12 @@ static int setup_sort_list(struct perf_hpp_list *list, char *str, | |||
| 2532 | ret = sort_dimension__add(list, tok, evlist, level); | 2532 | ret = sort_dimension__add(list, tok, evlist, level); |
| 2533 | if (ret == -EINVAL) { | 2533 | if (ret == -EINVAL) { |
| 2534 | if (!cacheline_size && !strncasecmp(tok, "dcacheline", strlen(tok))) | 2534 | if (!cacheline_size && !strncasecmp(tok, "dcacheline", strlen(tok))) |
| 2535 | error("The \"dcacheline\" --sort key needs to know the cacheline size and it couldn't be determined on this system"); | 2535 | pr_err("The \"dcacheline\" --sort key needs to know the cacheline size and it couldn't be determined on this system"); |
| 2536 | else | 2536 | else |
| 2537 | error("Invalid --sort key: `%s'", tok); | 2537 | pr_err("Invalid --sort key: `%s'", tok); |
| 2538 | break; | 2538 | break; |
| 2539 | } else if (ret == -ESRCH) { | 2539 | } else if (ret == -ESRCH) { |
| 2540 | error("Unknown --sort key: `%s'", tok); | 2540 | pr_err("Unknown --sort key: `%s'", tok); |
| 2541 | break; | 2541 | break; |
| 2542 | } | 2542 | } |
| 2543 | } | 2543 | } |
| @@ -2594,7 +2594,7 @@ static int setup_sort_order(struct perf_evlist *evlist) | |||
| 2594 | return 0; | 2594 | return 0; |
| 2595 | 2595 | ||
| 2596 | if (sort_order[1] == '\0') { | 2596 | if (sort_order[1] == '\0') { |
| 2597 | error("Invalid --sort key: `+'"); | 2597 | pr_err("Invalid --sort key: `+'"); |
| 2598 | return -EINVAL; | 2598 | return -EINVAL; |
| 2599 | } | 2599 | } |
| 2600 | 2600 | ||
| @@ -2604,7 +2604,7 @@ static int setup_sort_order(struct perf_evlist *evlist) | |||
| 2604 | */ | 2604 | */ |
| 2605 | if (asprintf(&new_sort_order, "%s,%s", | 2605 | if (asprintf(&new_sort_order, "%s,%s", |
| 2606 | get_default_sort_order(evlist), sort_order + 1) < 0) { | 2606 | get_default_sort_order(evlist), sort_order + 1) < 0) { |
| 2607 | error("Not enough memory to set up --sort"); | 2607 | pr_err("Not enough memory to set up --sort"); |
| 2608 | return -ENOMEM; | 2608 | return -ENOMEM; |
| 2609 | } | 2609 | } |
| 2610 | 2610 | ||
| @@ -2668,7 +2668,7 @@ static int __setup_sorting(struct perf_evlist *evlist) | |||
| 2668 | 2668 | ||
| 2669 | str = strdup(sort_keys); | 2669 | str = strdup(sort_keys); |
| 2670 | if (str == NULL) { | 2670 | if (str == NULL) { |
| 2671 | error("Not enough memory to setup sort keys"); | 2671 | pr_err("Not enough memory to setup sort keys"); |
| 2672 | return -ENOMEM; | 2672 | return -ENOMEM; |
| 2673 | } | 2673 | } |
| 2674 | 2674 | ||
| @@ -2678,7 +2678,7 @@ static int __setup_sorting(struct perf_evlist *evlist) | |||
| 2678 | if (!is_strict_order(field_order)) { | 2678 | if (!is_strict_order(field_order)) { |
| 2679 | str = setup_overhead(str); | 2679 | str = setup_overhead(str); |
| 2680 | if (str == NULL) { | 2680 | if (str == NULL) { |
| 2681 | error("Not enough memory to setup overhead keys"); | 2681 | pr_err("Not enough memory to setup overhead keys"); |
| 2682 | return -ENOMEM; | 2682 | return -ENOMEM; |
| 2683 | } | 2683 | } |
| 2684 | } | 2684 | } |
| @@ -2834,10 +2834,10 @@ static int setup_output_list(struct perf_hpp_list *list, char *str) | |||
| 2834 | tok; tok = strtok_r(NULL, ", ", &tmp)) { | 2834 | tok; tok = strtok_r(NULL, ", ", &tmp)) { |
| 2835 | ret = output_field_add(list, tok); | 2835 | ret = output_field_add(list, tok); |
| 2836 | if (ret == -EINVAL) { | 2836 | if (ret == -EINVAL) { |
| 2837 | error("Invalid --fields key: `%s'", tok); | 2837 | pr_err("Invalid --fields key: `%s'", tok); |
| 2838 | break; | 2838 | break; |
| 2839 | } else if (ret == -ESRCH) { | 2839 | } else if (ret == -ESRCH) { |
| 2840 | error("Unknown --fields key: `%s'", tok); | 2840 | pr_err("Unknown --fields key: `%s'", tok); |
| 2841 | break; | 2841 | break; |
| 2842 | } | 2842 | } |
| 2843 | } | 2843 | } |
| @@ -2877,7 +2877,7 @@ static int __setup_output_field(void) | |||
| 2877 | 2877 | ||
| 2878 | strp = str = strdup(field_order); | 2878 | strp = str = strdup(field_order); |
| 2879 | if (str == NULL) { | 2879 | if (str == NULL) { |
| 2880 | error("Not enough memory to setup output fields"); | 2880 | pr_err("Not enough memory to setup output fields"); |
| 2881 | return -ENOMEM; | 2881 | return -ENOMEM; |
| 2882 | } | 2882 | } |
| 2883 | 2883 | ||
| @@ -2885,7 +2885,7 @@ static int __setup_output_field(void) | |||
| 2885 | strp++; | 2885 | strp++; |
| 2886 | 2886 | ||
| 2887 | if (!strlen(strp)) { | 2887 | if (!strlen(strp)) { |
| 2888 | error("Invalid --fields key: `+'"); | 2888 | pr_err("Invalid --fields key: `+'"); |
| 2889 | goto out; | 2889 | goto out; |
| 2890 | } | 2890 | } |
| 2891 | 2891 | ||
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index ac10cc675d39..719d6cb86952 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c | |||
| @@ -44,6 +44,8 @@ static struct stats runtime_topdown_slots_issued[NUM_CTX][MAX_NR_CPUS]; | |||
| 44 | static struct stats runtime_topdown_slots_retired[NUM_CTX][MAX_NR_CPUS]; | 44 | static struct stats runtime_topdown_slots_retired[NUM_CTX][MAX_NR_CPUS]; |
| 45 | static struct stats runtime_topdown_fetch_bubbles[NUM_CTX][MAX_NR_CPUS]; | 45 | static struct stats runtime_topdown_fetch_bubbles[NUM_CTX][MAX_NR_CPUS]; |
| 46 | static struct stats runtime_topdown_recovery_bubbles[NUM_CTX][MAX_NR_CPUS]; | 46 | static struct stats runtime_topdown_recovery_bubbles[NUM_CTX][MAX_NR_CPUS]; |
| 47 | static struct stats runtime_smi_num_stats[NUM_CTX][MAX_NR_CPUS]; | ||
| 48 | static struct stats runtime_aperf_stats[NUM_CTX][MAX_NR_CPUS]; | ||
| 47 | static struct rblist runtime_saved_values; | 49 | static struct rblist runtime_saved_values; |
| 48 | static bool have_frontend_stalled; | 50 | static bool have_frontend_stalled; |
| 49 | 51 | ||
| @@ -157,6 +159,8 @@ void perf_stat__reset_shadow_stats(void) | |||
| 157 | memset(runtime_topdown_slots_issued, 0, sizeof(runtime_topdown_slots_issued)); | 159 | memset(runtime_topdown_slots_issued, 0, sizeof(runtime_topdown_slots_issued)); |
| 158 | memset(runtime_topdown_fetch_bubbles, 0, sizeof(runtime_topdown_fetch_bubbles)); | 160 | memset(runtime_topdown_fetch_bubbles, 0, sizeof(runtime_topdown_fetch_bubbles)); |
| 159 | memset(runtime_topdown_recovery_bubbles, 0, sizeof(runtime_topdown_recovery_bubbles)); | 161 | memset(runtime_topdown_recovery_bubbles, 0, sizeof(runtime_topdown_recovery_bubbles)); |
| 162 | memset(runtime_smi_num_stats, 0, sizeof(runtime_smi_num_stats)); | ||
| 163 | memset(runtime_aperf_stats, 0, sizeof(runtime_aperf_stats)); | ||
| 160 | 164 | ||
| 161 | next = rb_first(&runtime_saved_values.entries); | 165 | next = rb_first(&runtime_saved_values.entries); |
| 162 | while (next) { | 166 | while (next) { |
| @@ -217,6 +221,10 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count, | |||
| 217 | update_stats(&runtime_dtlb_cache_stats[ctx][cpu], count[0]); | 221 | update_stats(&runtime_dtlb_cache_stats[ctx][cpu], count[0]); |
| 218 | else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_ITLB)) | 222 | else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_ITLB)) |
| 219 | update_stats(&runtime_itlb_cache_stats[ctx][cpu], count[0]); | 223 | update_stats(&runtime_itlb_cache_stats[ctx][cpu], count[0]); |
| 224 | else if (perf_stat_evsel__is(counter, SMI_NUM)) | ||
| 225 | update_stats(&runtime_smi_num_stats[ctx][cpu], count[0]); | ||
| 226 | else if (perf_stat_evsel__is(counter, APERF)) | ||
| 227 | update_stats(&runtime_aperf_stats[ctx][cpu], count[0]); | ||
| 220 | 228 | ||
| 221 | if (counter->collect_stat) { | 229 | if (counter->collect_stat) { |
| 222 | struct saved_value *v = saved_value_lookup(counter, cpu, ctx, | 230 | struct saved_value *v = saved_value_lookup(counter, cpu, ctx, |
| @@ -592,6 +600,29 @@ static double td_be_bound(int ctx, int cpu) | |||
| 592 | return sanitize_val(1.0 - sum); | 600 | return sanitize_val(1.0 - sum); |
| 593 | } | 601 | } |
| 594 | 602 | ||
| 603 | static void print_smi_cost(int cpu, struct perf_evsel *evsel, | ||
| 604 | struct perf_stat_output_ctx *out) | ||
| 605 | { | ||
| 606 | double smi_num, aperf, cycles, cost = 0.0; | ||
| 607 | int ctx = evsel_context(evsel); | ||
| 608 | const char *color = NULL; | ||
| 609 | |||
| 610 | smi_num = avg_stats(&runtime_smi_num_stats[ctx][cpu]); | ||
| 611 | aperf = avg_stats(&runtime_aperf_stats[ctx][cpu]); | ||
| 612 | cycles = avg_stats(&runtime_cycles_stats[ctx][cpu]); | ||
| 613 | |||
| 614 | if ((cycles == 0) || (aperf == 0)) | ||
| 615 | return; | ||
| 616 | |||
| 617 | if (smi_num) | ||
| 618 | cost = (aperf - cycles) / aperf * 100.00; | ||
| 619 | |||
| 620 | if (cost > 10) | ||
| 621 | color = PERF_COLOR_RED; | ||
| 622 | out->print_metric(out->ctx, color, "%8.1f%%", "SMI cycles%", cost); | ||
| 623 | out->print_metric(out->ctx, NULL, "%4.0f", "SMI#", smi_num); | ||
| 624 | } | ||
| 625 | |||
| 595 | void perf_stat__print_shadow_stats(struct perf_evsel *evsel, | 626 | void perf_stat__print_shadow_stats(struct perf_evsel *evsel, |
| 596 | double avg, int cpu, | 627 | double avg, int cpu, |
| 597 | struct perf_stat_output_ctx *out) | 628 | struct perf_stat_output_ctx *out) |
| @@ -825,6 +856,8 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel, | |||
| 825 | } | 856 | } |
| 826 | snprintf(unit_buf, sizeof(unit_buf), "%c/sec", unit); | 857 | snprintf(unit_buf, sizeof(unit_buf), "%c/sec", unit); |
| 827 | print_metric(ctxp, NULL, "%8.3f", unit_buf, ratio); | 858 | print_metric(ctxp, NULL, "%8.3f", unit_buf, ratio); |
| 859 | } else if (perf_stat_evsel__is(evsel, SMI_NUM)) { | ||
| 860 | print_smi_cost(cpu, evsel, out); | ||
| 828 | } else { | 861 | } else { |
| 829 | print_metric(ctxp, NULL, NULL, NULL, 0); | 862 | print_metric(ctxp, NULL, NULL, NULL, 0); |
| 830 | } | 863 | } |
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index c58174443dc1..53b9a994a3dc 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c | |||
| @@ -86,6 +86,8 @@ static const char *id_str[PERF_STAT_EVSEL_ID__MAX] = { | |||
| 86 | ID(TOPDOWN_SLOTS_RETIRED, topdown-slots-retired), | 86 | ID(TOPDOWN_SLOTS_RETIRED, topdown-slots-retired), |
| 87 | ID(TOPDOWN_FETCH_BUBBLES, topdown-fetch-bubbles), | 87 | ID(TOPDOWN_FETCH_BUBBLES, topdown-fetch-bubbles), |
| 88 | ID(TOPDOWN_RECOVERY_BUBBLES, topdown-recovery-bubbles), | 88 | ID(TOPDOWN_RECOVERY_BUBBLES, topdown-recovery-bubbles), |
| 89 | ID(SMI_NUM, msr/smi/), | ||
| 90 | ID(APERF, msr/aperf/), | ||
| 89 | }; | 91 | }; |
| 90 | #undef ID | 92 | #undef ID |
| 91 | 93 | ||
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index 0a65ae23f495..7522bf10b03e 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h | |||
| @@ -22,6 +22,8 @@ enum perf_stat_evsel_id { | |||
| 22 | PERF_STAT_EVSEL_ID__TOPDOWN_SLOTS_RETIRED, | 22 | PERF_STAT_EVSEL_ID__TOPDOWN_SLOTS_RETIRED, |
| 23 | PERF_STAT_EVSEL_ID__TOPDOWN_FETCH_BUBBLES, | 23 | PERF_STAT_EVSEL_ID__TOPDOWN_FETCH_BUBBLES, |
| 24 | PERF_STAT_EVSEL_ID__TOPDOWN_RECOVERY_BUBBLES, | 24 | PERF_STAT_EVSEL_ID__TOPDOWN_RECOVERY_BUBBLES, |
| 25 | PERF_STAT_EVSEL_ID__SMI_NUM, | ||
| 26 | PERF_STAT_EVSEL_ID__APERF, | ||
| 25 | PERF_STAT_EVSEL_ID__MAX, | 27 | PERF_STAT_EVSEL_ID__MAX, |
| 26 | }; | 28 | }; |
| 27 | 29 | ||
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h index 318424ea561d..802d743378af 100644 --- a/tools/perf/util/strbuf.h +++ b/tools/perf/util/strbuf.h | |||
| @@ -42,6 +42,7 @@ | |||
| 42 | #include <stdarg.h> | 42 | #include <stdarg.h> |
| 43 | #include <stddef.h> | 43 | #include <stddef.h> |
| 44 | #include <string.h> | 44 | #include <string.h> |
| 45 | #include <linux/compiler.h> | ||
| 45 | #include <sys/types.h> | 46 | #include <sys/types.h> |
| 46 | 47 | ||
| 47 | extern char strbuf_slopbuf[]; | 48 | extern char strbuf_slopbuf[]; |
| @@ -85,8 +86,7 @@ static inline int strbuf_addstr(struct strbuf *sb, const char *s) { | |||
| 85 | return strbuf_add(sb, s, strlen(s)); | 86 | return strbuf_add(sb, s, strlen(s)); |
| 86 | } | 87 | } |
| 87 | 88 | ||
| 88 | __attribute__((format(printf,2,3))) | 89 | int strbuf_addf(struct strbuf *sb, const char *fmt, ...) __printf(2, 3); |
| 89 | int strbuf_addf(struct strbuf *sb, const char *fmt, ...); | ||
| 90 | 90 | ||
| 91 | /* XXX: if read fails, any partial read is undone */ | 91 | /* XXX: if read fails, any partial read is undone */ |
| 92 | ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint); | 92 | ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint); |
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 746bbee645d9..e0a6e9a6a053 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
| @@ -24,7 +24,7 @@ | |||
| 24 | #include <errno.h> | 24 | #include <errno.h> |
| 25 | 25 | ||
| 26 | #include "../perf.h" | 26 | #include "../perf.h" |
| 27 | #include "util.h" | 27 | #include "debug.h" |
| 28 | #include "trace-event.h" | 28 | #include "trace-event.h" |
| 29 | 29 | ||
| 30 | #include "sane_ctype.h" | 30 | #include "sane_ctype.h" |
| @@ -150,7 +150,7 @@ void parse_ftrace_printk(struct pevent *pevent, | |||
| 150 | while (line) { | 150 | while (line) { |
| 151 | addr_str = strtok_r(line, ":", &fmt); | 151 | addr_str = strtok_r(line, ":", &fmt); |
| 152 | if (!addr_str) { | 152 | if (!addr_str) { |
| 153 | warning("printk format with empty entry"); | 153 | pr_warning("printk format with empty entry"); |
| 154 | break; | 154 | break; |
| 155 | } | 155 | } |
| 156 | addr = strtoull(addr_str, NULL, 16); | 156 | addr = strtoull(addr_str, NULL, 16); |
diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c index 996046a66fe5..6cc9d9888ce0 100644 --- a/tools/perf/util/usage.c +++ b/tools/perf/util/usage.c | |||
| @@ -9,75 +9,17 @@ | |||
| 9 | #include "util.h" | 9 | #include "util.h" |
| 10 | #include "debug.h" | 10 | #include "debug.h" |
| 11 | 11 | ||
| 12 | static void report(const char *prefix, const char *err, va_list params) | 12 | static __noreturn void usage_builtin(const char *err) |
| 13 | { | ||
| 14 | char msg[1024]; | ||
| 15 | vsnprintf(msg, sizeof(msg), err, params); | ||
| 16 | fprintf(stderr, " %s%s\n", prefix, msg); | ||
| 17 | } | ||
| 18 | |||
| 19 | static NORETURN void usage_builtin(const char *err) | ||
| 20 | { | 13 | { |
| 21 | fprintf(stderr, "\n Usage: %s\n", err); | 14 | fprintf(stderr, "\n Usage: %s\n", err); |
| 22 | exit(129); | 15 | exit(129); |
| 23 | } | 16 | } |
| 24 | 17 | ||
| 25 | static NORETURN void die_builtin(const char *err, va_list params) | ||
| 26 | { | ||
| 27 | report(" Fatal: ", err, params); | ||
| 28 | exit(128); | ||
| 29 | } | ||
| 30 | |||
| 31 | static void error_builtin(const char *err, va_list params) | ||
| 32 | { | ||
| 33 | report(" Error: ", err, params); | ||
| 34 | } | ||
| 35 | |||
| 36 | static void warn_builtin(const char *warn, va_list params) | ||
| 37 | { | ||
| 38 | report(" Warning: ", warn, params); | ||
| 39 | } | ||
| 40 | |||
| 41 | /* If we are in a dlopen()ed .so write to a global variable would segfault | 18 | /* If we are in a dlopen()ed .so write to a global variable would segfault |
| 42 | * (ugh), so keep things static. */ | 19 | * (ugh), so keep things static. */ |
| 43 | static void (*usage_routine)(const char *err) NORETURN = usage_builtin; | 20 | static void (*usage_routine)(const char *err) __noreturn = usage_builtin; |
| 44 | static void (*error_routine)(const char *err, va_list params) = error_builtin; | ||
| 45 | static void (*warn_routine)(const char *err, va_list params) = warn_builtin; | ||
| 46 | |||
| 47 | void set_warning_routine(void (*routine)(const char *err, va_list params)) | ||
| 48 | { | ||
| 49 | warn_routine = routine; | ||
| 50 | } | ||
| 51 | 21 | ||
| 52 | void usage(const char *err) | 22 | void usage(const char *err) |
| 53 | { | 23 | { |
| 54 | usage_routine(err); | 24 | usage_routine(err); |
| 55 | } | 25 | } |
| 56 | |||
| 57 | void die(const char *err, ...) | ||
| 58 | { | ||
| 59 | va_list params; | ||
| 60 | |||
| 61 | va_start(params, err); | ||
| 62 | die_builtin(err, params); | ||
| 63 | va_end(params); | ||
| 64 | } | ||
| 65 | |||
| 66 | int error(const char *err, ...) | ||
| 67 | { | ||
| 68 | va_list params; | ||
| 69 | |||
| 70 | va_start(params, err); | ||
| 71 | error_routine(err, params); | ||
| 72 | va_end(params); | ||
| 73 | return -1; | ||
| 74 | } | ||
| 75 | |||
| 76 | void warning(const char *warn, ...) | ||
| 77 | { | ||
| 78 | va_list params; | ||
| 79 | |||
| 80 | va_start(params, warn); | ||
| 81 | warn_routine(warn, params); | ||
| 82 | va_end(params); | ||
| 83 | } | ||
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 28c9f335006c..988111e0bab5 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
| @@ -343,43 +343,6 @@ int perf_event_paranoid(void) | |||
| 343 | 343 | ||
| 344 | return value; | 344 | return value; |
| 345 | } | 345 | } |
| 346 | |||
| 347 | bool find_process(const char *name) | ||
| 348 | { | ||
| 349 | size_t len = strlen(name); | ||
| 350 | DIR *dir; | ||
| 351 | struct dirent *d; | ||
| 352 | int ret = -1; | ||
| 353 | |||
| 354 | dir = opendir(procfs__mountpoint()); | ||
| 355 | if (!dir) | ||
| 356 | return false; | ||
| 357 | |||
| 358 | /* Walk through the directory. */ | ||
| 359 | while (ret && (d = readdir(dir)) != NULL) { | ||
| 360 | char path[PATH_MAX]; | ||
| 361 | char *data; | ||
| 362 | size_t size; | ||
| 363 | |||
| 364 | if ((d->d_type != DT_DIR) || | ||
| 365 | !strcmp(".", d->d_name) || | ||
| 366 | !strcmp("..", d->d_name)) | ||
| 367 | continue; | ||
| 368 | |||
| 369 | scnprintf(path, sizeof(path), "%s/%s/comm", | ||
| 370 | procfs__mountpoint(), d->d_name); | ||
| 371 | |||
| 372 | if (filename__read_str(path, &data, &size)) | ||
| 373 | continue; | ||
| 374 | |||
| 375 | ret = strncmp(name, data, len); | ||
| 376 | free(data); | ||
| 377 | } | ||
| 378 | |||
| 379 | closedir(dir); | ||
| 380 | return ret ? false : true; | ||
| 381 | } | ||
| 382 | |||
| 383 | static int | 346 | static int |
| 384 | fetch_ubuntu_kernel_version(unsigned int *puint) | 347 | fetch_ubuntu_kernel_version(unsigned int *puint) |
| 385 | { | 348 | { |
| @@ -387,8 +350,12 @@ fetch_ubuntu_kernel_version(unsigned int *puint) | |||
| 387 | size_t line_len = 0; | 350 | size_t line_len = 0; |
| 388 | char *ptr, *line = NULL; | 351 | char *ptr, *line = NULL; |
| 389 | int version, patchlevel, sublevel, err; | 352 | int version, patchlevel, sublevel, err; |
| 390 | FILE *vsig = fopen("/proc/version_signature", "r"); | 353 | FILE *vsig; |
| 354 | |||
| 355 | if (!puint) | ||
| 356 | return 0; | ||
| 391 | 357 | ||
| 358 | vsig = fopen("/proc/version_signature", "r"); | ||
| 392 | if (!vsig) { | 359 | if (!vsig) { |
| 393 | pr_debug("Open /proc/version_signature failed: %s\n", | 360 | pr_debug("Open /proc/version_signature failed: %s\n", |
| 394 | strerror(errno)); | 361 | strerror(errno)); |
| @@ -418,8 +385,7 @@ fetch_ubuntu_kernel_version(unsigned int *puint) | |||
| 418 | goto errout; | 385 | goto errout; |
| 419 | } | 386 | } |
| 420 | 387 | ||
| 421 | if (puint) | 388 | *puint = (version << 16) + (patchlevel << 8) + sublevel; |
| 422 | *puint = (version << 16) + (patchlevel << 8) + sublevel; | ||
| 423 | err = 0; | 389 | err = 0; |
| 424 | errout: | 390 | errout: |
| 425 | free(line); | 391 | free(line); |
| @@ -446,6 +412,9 @@ fetch_kernel_version(unsigned int *puint, char *str, | |||
| 446 | str[str_size - 1] = '\0'; | 412 | str[str_size - 1] = '\0'; |
| 447 | } | 413 | } |
| 448 | 414 | ||
| 415 | if (!puint || int_ver_ready) | ||
| 416 | return 0; | ||
| 417 | |||
| 449 | err = sscanf(utsname.release, "%d.%d.%d", | 418 | err = sscanf(utsname.release, "%d.%d.%d", |
| 450 | &version, &patchlevel, &sublevel); | 419 | &version, &patchlevel, &sublevel); |
| 451 | 420 | ||
| @@ -455,8 +424,7 @@ fetch_kernel_version(unsigned int *puint, char *str, | |||
| 455 | return -1; | 424 | return -1; |
| 456 | } | 425 | } |
| 457 | 426 | ||
| 458 | if (puint && !int_ver_ready) | 427 | *puint = (version << 16) + (patchlevel << 8) + sublevel; |
| 459 | *puint = (version << 16) + (patchlevel << 8) + sublevel; | ||
| 460 | return 0; | 428 | return 0; |
| 461 | } | 429 | } |
| 462 | 430 | ||
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 5dfb9bb6482d..2c9e58a45310 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | #ifndef GIT_COMPAT_UTIL_H | 1 | #ifndef GIT_COMPAT_UTIL_H |
| 2 | #define GIT_COMPAT_UTIL_H | 2 | #define GIT_COMPAT_UTIL_H |
| 3 | 3 | ||
| 4 | #define _ALL_SOURCE 1 | ||
| 5 | #define _BSD_SOURCE 1 | 4 | #define _BSD_SOURCE 1 |
| 6 | /* glibc 2.20 deprecates _BSD_SOURCE in favour of _DEFAULT_SOURCE */ | 5 | /* glibc 2.20 deprecates _BSD_SOURCE in favour of _DEFAULT_SOURCE */ |
| 7 | #define _DEFAULT_SOURCE 1 | 6 | #define _DEFAULT_SOURCE 1 |
| @@ -11,24 +10,12 @@ | |||
| 11 | #include <stddef.h> | 10 | #include <stddef.h> |
| 12 | #include <stdlib.h> | 11 | #include <stdlib.h> |
| 13 | #include <stdarg.h> | 12 | #include <stdarg.h> |
| 13 | #include <linux/compiler.h> | ||
| 14 | #include <linux/types.h> | 14 | #include <linux/types.h> |
| 15 | 15 | ||
| 16 | #ifdef __GNUC__ | ||
| 17 | #define NORETURN __attribute__((__noreturn__)) | ||
| 18 | #else | ||
| 19 | #define NORETURN | ||
| 20 | #ifndef __attribute__ | ||
| 21 | #define __attribute__(x) | ||
| 22 | #endif | ||
| 23 | #endif | ||
| 24 | |||
| 25 | /* General helper functions */ | 16 | /* General helper functions */ |
| 26 | void usage(const char *err) NORETURN; | 17 | void usage(const char *err) __noreturn; |
| 27 | void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); | 18 | void die(const char *err, ...) __noreturn __printf(1, 2); |
| 28 | int error(const char *err, ...) __attribute__((format (printf, 1, 2))); | ||
| 29 | void warning(const char *err, ...) __attribute__((format (printf, 1, 2))); | ||
| 30 | |||
| 31 | void set_warning_routine(void (*routine)(const char *err, va_list params)); | ||
| 32 | 19 | ||
| 33 | static inline void *zalloc(size_t size) | 20 | static inline void *zalloc(size_t size) |
| 34 | { | 21 | { |
| @@ -57,8 +44,6 @@ int hex2u64(const char *ptr, u64 *val); | |||
| 57 | extern unsigned int page_size; | 44 | extern unsigned int page_size; |
| 58 | extern int cacheline_size; | 45 | extern int cacheline_size; |
| 59 | 46 | ||
| 60 | bool find_process(const char *name); | ||
| 61 | |||
| 62 | int fetch_kernel_version(unsigned int *puint, | 47 | int fetch_kernel_version(unsigned int *puint, |
| 63 | char *str, size_t str_sz); | 48 | char *str, size_t str_sz); |
| 64 | #define KVER_VERSION(x) (((x) >> 16) & 0xff) | 49 | #define KVER_VERSION(x) (((x) >> 16) & 0xff) |
