diff options
Diffstat (limited to 'tools/perf')
62 files changed, 1788 insertions, 769 deletions
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt index b2c63309a651..6f5a498608b2 100644 --- a/tools/perf/Documentation/perf-annotate.txt +++ b/tools/perf/Documentation/perf-annotate.txt | |||
| @@ -24,12 +24,47 @@ OPTIONS | |||
| 24 | --input=:: | 24 | --input=:: |
| 25 | Input file name. (default: perf.data) | 25 | Input file name. (default: perf.data) |
| 26 | 26 | ||
| 27 | -d:: | ||
| 28 | --dsos=<dso[,dso...]>:: | ||
| 29 | Only consider symbols in these dsos. | ||
| 30 | -s:: | ||
| 31 | --symbol=<symbol>:: | ||
| 32 | Symbol to annotate. | ||
| 33 | |||
| 34 | -f:: | ||
| 35 | --force:: | ||
| 36 | Don't complain, do it. | ||
| 37 | |||
| 38 | -v:: | ||
| 39 | --verbose:: | ||
| 40 | Be more verbose. (Show symbol address, etc) | ||
| 41 | |||
| 42 | -D:: | ||
| 43 | --dump-raw-trace:: | ||
| 44 | Dump raw trace in ASCII. | ||
| 45 | |||
| 46 | -k:: | ||
| 47 | --vmlinux=<file>:: | ||
| 48 | vmlinux pathname. | ||
| 49 | |||
| 50 | -m:: | ||
| 51 | --modules:: | ||
| 52 | Load module symbols. WARNING: use only with -k and LIVE kernel. | ||
| 53 | |||
| 54 | -l:: | ||
| 55 | --print-line:: | ||
| 56 | Print matching source lines (may be slow). | ||
| 57 | |||
| 58 | -P:: | ||
| 59 | --full-paths:: | ||
| 60 | Don't shorten the displayed pathnames. | ||
| 61 | |||
| 27 | --stdio:: Use the stdio interface. | 62 | --stdio:: Use the stdio interface. |
| 28 | 63 | ||
| 29 | --tui:: Use the TUI interface Use of --tui requires a tty, if one is not | 64 | --tui:: Use the TUI interface Use of --tui requires a tty, if one is not |
| 30 | present, as when piping to other commands, the stdio interface is | 65 | present, as when piping to other commands, the stdio interface is |
| 31 | used. This interfaces starts by centering on the line with more | 66 | used. This interfaces starts by centering on the line with more |
| 32 | samples, TAB/UNTAB cycles thru the lines with more samples. | 67 | samples, TAB/UNTAB cycles through the lines with more samples. |
| 33 | 68 | ||
| 34 | SEE ALSO | 69 | SEE ALSO |
| 35 | -------- | 70 | -------- |
diff --git a/tools/perf/Documentation/perf-buildid-list.txt b/tools/perf/Documentation/perf-buildid-list.txt index 01b642c0bf8f..5eaac6f26d51 100644 --- a/tools/perf/Documentation/perf-buildid-list.txt +++ b/tools/perf/Documentation/perf-buildid-list.txt | |||
| @@ -18,6 +18,9 @@ perf report. | |||
| 18 | 18 | ||
| 19 | OPTIONS | 19 | OPTIONS |
| 20 | ------- | 20 | ------- |
| 21 | -H:: | ||
| 22 | --with-hits:: | ||
| 23 | Show only DSOs with hits. | ||
| 21 | -i:: | 24 | -i:: |
| 22 | --input=:: | 25 | --input=:: |
| 23 | Input file name. (default: perf.data) | 26 | Input file name. (default: perf.data) |
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt index 20d97d84ea1c..6a9ec2b35310 100644 --- a/tools/perf/Documentation/perf-diff.txt +++ b/tools/perf/Documentation/perf-diff.txt | |||
| @@ -19,6 +19,18 @@ If no parameters are passed it will assume perf.data.old and perf.data. | |||
| 19 | 19 | ||
| 20 | OPTIONS | 20 | OPTIONS |
| 21 | ------- | 21 | ------- |
| 22 | -M:: | ||
| 23 | --displacement:: | ||
| 24 | Show position displacement relative to baseline. | ||
| 25 | |||
| 26 | -D:: | ||
| 27 | --dump-raw-trace:: | ||
| 28 | Dump raw trace in ASCII. | ||
| 29 | |||
| 30 | -m:: | ||
| 31 | --modules:: | ||
| 32 | Load module symbols. WARNING: use only with -k and LIVE kernel | ||
| 33 | |||
| 22 | -d:: | 34 | -d:: |
| 23 | --dsos=:: | 35 | --dsos=:: |
| 24 | Only consider symbols in these dsos. CSV that understands | 36 | Only consider symbols in these dsos. CSV that understands |
| @@ -42,7 +54,7 @@ OPTIONS | |||
| 42 | --field-separator=:: | 54 | --field-separator=:: |
| 43 | 55 | ||
| 44 | Use a special separator character and don't pad with spaces, replacing | 56 | Use a special separator character and don't pad with spaces, replacing |
| 45 | all occurances of this separator in symbol names (and other output) | 57 | all occurrences of this separator in symbol names (and other output) |
| 46 | with a '.' character, that thus it's the only non valid separator. | 58 | with a '.' character, that thus it's the only non valid separator. |
| 47 | 59 | ||
| 48 | -v:: | 60 | -v:: |
| @@ -50,6 +62,11 @@ OPTIONS | |||
| 50 | Be verbose, for instance, show the raw counts in addition to the | 62 | Be verbose, for instance, show the raw counts in addition to the |
| 51 | diff. | 63 | diff. |
| 52 | 64 | ||
| 65 | -f:: | ||
| 66 | --force:: | ||
| 67 | Don't complain, do it. | ||
| 68 | |||
| 69 | |||
| 53 | SEE ALSO | 70 | SEE ALSO |
| 54 | -------- | 71 | -------- |
| 55 | linkperf:perf-record[1] | 72 | linkperf:perf-record[1] |
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt index d004e19fe6d6..dd84cb2f0a88 100644 --- a/tools/perf/Documentation/perf-kvm.txt +++ b/tools/perf/Documentation/perf-kvm.txt | |||
| @@ -22,7 +22,7 @@ There are a couple of variants of perf kvm: | |||
| 22 | a performance counter profile of guest os in realtime | 22 | a performance counter profile of guest os in realtime |
| 23 | of an arbitrary workload. | 23 | of an arbitrary workload. |
| 24 | 24 | ||
| 25 | 'perf kvm record <command>' to record the performance couinter profile | 25 | 'perf kvm record <command>' to record the performance counter profile |
| 26 | of an arbitrary workload and save it into a perf data file. If both | 26 | of an arbitrary workload and save it into a perf data file. If both |
| 27 | --host and --guest are input, the perf data file name is perf.data.kvm. | 27 | --host and --guest are input, the perf data file name is perf.data.kvm. |
| 28 | If there is no --host but --guest, the file name is perf.data.guest. | 28 | If there is no --host but --guest, the file name is perf.data.guest. |
| @@ -40,6 +40,12 @@ There are a couple of variants of perf kvm: | |||
| 40 | 40 | ||
| 41 | OPTIONS | 41 | OPTIONS |
| 42 | ------- | 42 | ------- |
| 43 | -i:: | ||
| 44 | --input=:: | ||
| 45 | Input file name. | ||
| 46 | -o:: | ||
| 47 | --output:: | ||
| 48 | Output file name. | ||
| 43 | --host=:: | 49 | --host=:: |
| 44 | Collect host side performance profile. | 50 | Collect host side performance profile. |
| 45 | --guest=:: | 51 | --guest=:: |
diff --git a/tools/perf/Documentation/perf-lock.txt b/tools/perf/Documentation/perf-lock.txt index b317102138c8..921de259ea10 100644 --- a/tools/perf/Documentation/perf-lock.txt +++ b/tools/perf/Documentation/perf-lock.txt | |||
| @@ -24,6 +24,21 @@ and statistics with this 'perf lock' command. | |||
| 24 | 24 | ||
| 25 | 'perf lock report' reports statistical data. | 25 | 'perf lock report' reports statistical data. |
| 26 | 26 | ||
| 27 | OPTIONS | ||
| 28 | ------- | ||
| 29 | |||
| 30 | -i:: | ||
| 31 | --input=<file>:: | ||
| 32 | Input file name. | ||
| 33 | |||
| 34 | -v:: | ||
| 35 | --verbose:: | ||
| 36 | Be more verbose (show symbol address, etc). | ||
| 37 | |||
| 38 | -D:: | ||
| 39 | --dump-raw-trace:: | ||
| 40 | Dump raw trace in ASCII. | ||
| 41 | |||
| 27 | SEE ALSO | 42 | SEE ALSO |
| 28 | -------- | 43 | -------- |
| 29 | linkperf:perf[1] | 44 | linkperf:perf[1] |
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 62de1b7f4e76..4e2323276984 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt | |||
| @@ -115,7 +115,7 @@ Each probe argument follows below syntax. | |||
| 115 | 115 | ||
| 116 | LINE SYNTAX | 116 | LINE SYNTAX |
| 117 | ----------- | 117 | ----------- |
| 118 | Line range is descripted by following syntax. | 118 | Line range is described by following syntax. |
| 119 | 119 | ||
| 120 | "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]" | 120 | "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]" |
| 121 | 121 | ||
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index a91f9f9e6e5c..52462ae26455 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
| @@ -39,15 +39,24 @@ OPTIONS | |||
| 39 | be passed as follows: '\mem:addr[:[r][w][x]]'. | 39 | be passed as follows: '\mem:addr[:[r][w][x]]'. |
| 40 | If you want to profile read-write accesses in 0x1000, just set | 40 | If you want to profile read-write accesses in 0x1000, just set |
| 41 | 'mem:0x1000:rw'. | 41 | 'mem:0x1000:rw'. |
| 42 | |||
| 43 | --filter=<filter>:: | ||
| 44 | Event filter. | ||
| 45 | |||
| 42 | -a:: | 46 | -a:: |
| 43 | System-wide collection. | 47 | --all-cpus:: |
| 48 | System-wide collection from all CPUs. | ||
| 44 | 49 | ||
| 45 | -l:: | 50 | -l:: |
| 46 | Scale counter values. | 51 | Scale counter values. |
| 47 | 52 | ||
| 48 | -p:: | 53 | -p:: |
| 49 | --pid=:: | 54 | --pid=:: |
| 50 | Record events on existing pid. | 55 | Record events on existing process ID. |
| 56 | |||
| 57 | -t:: | ||
| 58 | --tid=:: | ||
| 59 | Record events on existing thread ID. | ||
| 51 | 60 | ||
| 52 | -r:: | 61 | -r:: |
| 53 | --realtime=:: | 62 | --realtime=:: |
| @@ -99,6 +108,11 @@ OPTIONS | |||
| 99 | --data:: | 108 | --data:: |
| 100 | Sample addresses. | 109 | Sample addresses. |
| 101 | 110 | ||
| 111 | -T:: | ||
| 112 | --timestamp:: | ||
| 113 | Sample timestamps. Use it with 'perf report -D' to see the timestamps, | ||
| 114 | for instance. | ||
| 115 | |||
| 102 | -n:: | 116 | -n:: |
| 103 | --no-samples:: | 117 | --no-samples:: |
| 104 | Don't sample. | 118 | Don't sample. |
| @@ -109,8 +123,8 @@ Collect raw sample records from all opened counters (default for tracepoint coun | |||
| 109 | 123 | ||
| 110 | -C:: | 124 | -C:: |
| 111 | --cpu:: | 125 | --cpu:: |
| 112 | Collect samples only on the list of cpus provided. Multiple CPUs can be provided as a | 126 | Collect samples only on the list of CPUs provided. Multiple CPUs can be provided as a |
| 113 | comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. | 127 | comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. |
| 114 | In per-thread mode with inheritance mode on (default), samples are captured only when | 128 | In per-thread mode with inheritance mode on (default), samples are captured only when |
| 115 | the thread executes on the designated CPUs. Default is to monitor all CPUs. | 129 | the thread executes on the designated CPUs. Default is to monitor all CPUs. |
| 116 | 130 | ||
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 12052c9ed0ba..fefea77ec6e9 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt | |||
| @@ -20,6 +20,11 @@ OPTIONS | |||
| 20 | -i:: | 20 | -i:: |
| 21 | --input=:: | 21 | --input=:: |
| 22 | Input file name. (default: perf.data) | 22 | Input file name. (default: perf.data) |
| 23 | |||
| 24 | -v:: | ||
| 25 | --verbose:: | ||
| 26 | Be more verbose. (show symbol address, etc) | ||
| 27 | |||
| 23 | -d:: | 28 | -d:: |
| 24 | --dsos=:: | 29 | --dsos=:: |
| 25 | Only consider symbols in these dsos. CSV that understands | 30 | Only consider symbols in these dsos. CSV that understands |
| @@ -27,6 +32,10 @@ OPTIONS | |||
| 27 | -n:: | 32 | -n:: |
| 28 | --show-nr-samples:: | 33 | --show-nr-samples:: |
| 29 | Show the number of samples for each symbol | 34 | Show the number of samples for each symbol |
| 35 | |||
| 36 | --showcpuutilization:: | ||
| 37 | Show sample percentage for different cpu modes. | ||
| 38 | |||
| 30 | -T:: | 39 | -T:: |
| 31 | --threads:: | 40 | --threads:: |
| 32 | Show per-thread event counters | 41 | Show per-thread event counters |
| @@ -39,12 +48,24 @@ OPTIONS | |||
| 39 | Only consider these symbols. CSV that understands | 48 | Only consider these symbols. CSV that understands |
| 40 | file://filename entries. | 49 | file://filename entries. |
| 41 | 50 | ||
| 51 | -U:: | ||
| 52 | --hide-unresolved:: | ||
| 53 | Only display entries resolved to a symbol. | ||
| 54 | |||
| 42 | -s:: | 55 | -s:: |
| 43 | --sort=:: | 56 | --sort=:: |
| 44 | Sort by key(s): pid, comm, dso, symbol, parent. | 57 | Sort by key(s): pid, comm, dso, symbol, parent. |
| 45 | 58 | ||
| 59 | -p:: | ||
| 60 | --parent=<regex>:: | ||
| 61 | regex filter to identify parent, see: '--sort parent' | ||
| 62 | |||
| 63 | -x:: | ||
| 64 | --exclude-other:: | ||
| 65 | Only display entries with parent-match. | ||
| 66 | |||
| 46 | -w:: | 67 | -w:: |
| 47 | --field-width=:: | 68 | --column-widths=<width[,width...]>:: |
| 48 | Force each column width to the provided list, for large terminal | 69 | Force each column width to the provided list, for large terminal |
| 49 | readability. | 70 | readability. |
| 50 | 71 | ||
| @@ -52,19 +73,26 @@ OPTIONS | |||
| 52 | --field-separator=:: | 73 | --field-separator=:: |
| 53 | 74 | ||
| 54 | Use a special separator character and don't pad with spaces, replacing | 75 | Use a special separator character and don't pad with spaces, replacing |
| 55 | all occurances of this separator in symbol names (and other output) | 76 | all occurrences of this separator in symbol names (and other output) |
| 56 | with a '.' character, that thus it's the only non valid separator. | 77 | with a '.' character, that thus it's the only non valid separator. |
| 57 | 78 | ||
| 79 | -D:: | ||
| 80 | --dump-raw-trace:: | ||
| 81 | Dump raw trace in ASCII. | ||
| 82 | |||
| 58 | -g [type,min]:: | 83 | -g [type,min]:: |
| 59 | --call-graph:: | 84 | --call-graph:: |
| 60 | Display callchains using type and min percent threshold. | 85 | Display call chains using type and min percent threshold. |
| 61 | type can be either: | 86 | type can be either: |
| 62 | - flat: single column, linear exposure of callchains. | 87 | - flat: single column, linear exposure of call chains. |
| 63 | - graph: use a graph tree, displaying absolute overhead rates. | 88 | - graph: use a graph tree, displaying absolute overhead rates. |
| 64 | - fractal: like graph, but displays relative rates. Each branch of | 89 | - fractal: like graph, but displays relative rates. Each branch of |
| 65 | the tree is considered as a new profiled object. + | 90 | the tree is considered as a new profiled object. + |
| 66 | Default: fractal,0.5. | 91 | Default: fractal,0.5. |
| 67 | 92 | ||
| 93 | --pretty=<key>:: | ||
| 94 | Pretty printing style. key: normal, raw | ||
| 95 | |||
| 68 | --stdio:: Use the stdio interface. | 96 | --stdio:: Use the stdio interface. |
| 69 | 97 | ||
| 70 | --tui:: Use the TUI interface, that is integrated with annotate and allows | 98 | --tui:: Use the TUI interface, that is integrated with annotate and allows |
| @@ -72,6 +100,22 @@ OPTIONS | |||
| 72 | requires a tty, if one is not present, as when piping to other | 100 | requires a tty, if one is not present, as when piping to other |
| 73 | commands, the stdio interface is used. | 101 | commands, the stdio interface is used. |
| 74 | 102 | ||
| 103 | -k:: | ||
| 104 | --vmlinux=<file>:: | ||
| 105 | vmlinux pathname | ||
| 106 | |||
| 107 | --kallsyms=<file>:: | ||
| 108 | kallsyms pathname | ||
| 109 | |||
| 110 | -m:: | ||
| 111 | --modules:: | ||
| 112 | Load module symbols. WARNING: This should only be used with -k and | ||
| 113 | a LIVE kernel. | ||
| 114 | |||
| 115 | -f:: | ||
| 116 | --force:: | ||
| 117 | Don't complain, do it. | ||
| 118 | |||
| 75 | SEE ALSO | 119 | SEE ALSO |
| 76 | -------- | 120 | -------- |
| 77 | linkperf:perf-stat[1] | 121 | linkperf:perf-stat[1] |
diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt index 8417644a6166..46822d5fde1c 100644 --- a/tools/perf/Documentation/perf-sched.txt +++ b/tools/perf/Documentation/perf-sched.txt | |||
| @@ -8,11 +8,11 @@ perf-sched - Tool to trace/measure scheduler properties (latencies) | |||
| 8 | SYNOPSIS | 8 | SYNOPSIS |
| 9 | -------- | 9 | -------- |
| 10 | [verse] | 10 | [verse] |
| 11 | 'perf sched' {record|latency|replay|trace} | 11 | 'perf sched' {record|latency|map|replay|trace} |
| 12 | 12 | ||
| 13 | DESCRIPTION | 13 | DESCRIPTION |
| 14 | ----------- | 14 | ----------- |
| 15 | There are four variants of perf sched: | 15 | There are five variants of perf sched: |
| 16 | 16 | ||
| 17 | 'perf sched record <command>' to record the scheduling events | 17 | 'perf sched record <command>' to record the scheduling events |
| 18 | of an arbitrary workload. | 18 | of an arbitrary workload. |
| @@ -30,8 +30,22 @@ There are four variants of perf sched: | |||
| 30 | of the workload as it occurred when it was recorded - and can repeat | 30 | of the workload as it occurred when it was recorded - and can repeat |
| 31 | it a number of times, measuring its performance.) | 31 | it a number of times, measuring its performance.) |
| 32 | 32 | ||
| 33 | 'perf sched map' to print a textual context-switching outline of | ||
| 34 | workload captured via perf sched record. Columns stand for | ||
| 35 | individual CPUs, and the two-letter shortcuts stand for tasks that | ||
| 36 | are running on a CPU. A '*' denotes the CPU that had the event, and | ||
| 37 | a dot signals an idle CPU. | ||
| 38 | |||
| 33 | OPTIONS | 39 | OPTIONS |
| 34 | ------- | 40 | ------- |
| 41 | -i:: | ||
| 42 | --input=<file>:: | ||
| 43 | Input file name. (default: perf.data) | ||
| 44 | |||
| 45 | -v:: | ||
| 46 | --verbose:: | ||
| 47 | Be more verbose. (show symbol address, etc) | ||
| 48 | |||
| 35 | -D:: | 49 | -D:: |
| 36 | --dump-raw-trace=:: | 50 | --dump-raw-trace=:: |
| 37 | Display verbose dump of the sched data. | 51 | Display verbose dump of the sched data. |
diff --git a/tools/perf/Documentation/perf-trace-perl.txt b/tools/perf/Documentation/perf-script-perl.txt index ee6525ee6d69..5bb41e55a3ac 100644 --- a/tools/perf/Documentation/perf-trace-perl.txt +++ b/tools/perf/Documentation/perf-script-perl.txt | |||
| @@ -1,19 +1,19 @@ | |||
| 1 | perf-trace-perl(1) | 1 | perf-script-perl(1) |
| 2 | ================== | 2 | ================== |
| 3 | 3 | ||
| 4 | NAME | 4 | NAME |
| 5 | ---- | 5 | ---- |
| 6 | perf-trace-perl - Process trace data with a Perl script | 6 | perf-script-perl - Process trace data with a Perl script |
| 7 | 7 | ||
| 8 | SYNOPSIS | 8 | SYNOPSIS |
| 9 | -------- | 9 | -------- |
| 10 | [verse] | 10 | [verse] |
| 11 | 'perf trace' [-s [Perl]:script[.pl] ] | 11 | 'perf script' [-s [Perl]:script[.pl] ] |
| 12 | 12 | ||
| 13 | DESCRIPTION | 13 | DESCRIPTION |
| 14 | ----------- | 14 | ----------- |
| 15 | 15 | ||
| 16 | This perf trace option is used to process perf trace data using perf's | 16 | This perf script option is used to process perf script data using perf's |
| 17 | built-in Perl interpreter. It reads and processes the input file and | 17 | built-in Perl interpreter. It reads and processes the input file and |
| 18 | displays the results of the trace analysis implemented in the given | 18 | displays the results of the trace analysis implemented in the given |
| 19 | Perl script, if any. | 19 | Perl script, if any. |
| @@ -21,7 +21,7 @@ Perl script, if any. | |||
| 21 | STARTER SCRIPTS | 21 | STARTER SCRIPTS |
| 22 | --------------- | 22 | --------------- |
| 23 | 23 | ||
| 24 | You can avoid reading the rest of this document by running 'perf trace | 24 | You can avoid reading the rest of this document by running 'perf script |
| 25 | -g perl' in the same directory as an existing perf.data trace file. | 25 | -g perl' in the same directory as an existing perf.data trace file. |
| 26 | That will generate a starter script containing a handler for each of | 26 | That will generate a starter script containing a handler for each of |
| 27 | the event types in the trace file; it simply prints every available | 27 | the event types in the trace file; it simply prints every available |
| @@ -30,13 +30,13 @@ field for each event in the trace file. | |||
| 30 | You can also look at the existing scripts in | 30 | You can also look at the existing scripts in |
| 31 | ~/libexec/perf-core/scripts/perl for typical examples showing how to | 31 | ~/libexec/perf-core/scripts/perl for typical examples showing how to |
| 32 | do basic things like aggregate event data, print results, etc. Also, | 32 | do basic things like aggregate event data, print results, etc. Also, |
| 33 | the check-perf-trace.pl script, while not interesting for its results, | 33 | the check-perf-script.pl script, while not interesting for its results, |
| 34 | attempts to exercise all of the main scripting features. | 34 | attempts to exercise all of the main scripting features. |
| 35 | 35 | ||
| 36 | EVENT HANDLERS | 36 | EVENT HANDLERS |
| 37 | -------------- | 37 | -------------- |
| 38 | 38 | ||
| 39 | When perf trace is invoked using a trace script, a user-defined | 39 | When perf script is invoked using a trace script, a user-defined |
| 40 | 'handler function' is called for each event in the trace. If there's | 40 | 'handler function' is called for each event in the trace. If there's |
| 41 | no handler function defined for a given event type, the event is | 41 | no handler function defined for a given event type, the event is |
| 42 | ignored (or passed to a 'trace_handled' function, see below) and the | 42 | ignored (or passed to a 'trace_handled' function, see below) and the |
| @@ -112,13 +112,13 @@ write a useful trace script. The sections below cover the rest. | |||
| 112 | SCRIPT LAYOUT | 112 | SCRIPT LAYOUT |
| 113 | ------------- | 113 | ------------- |
| 114 | 114 | ||
| 115 | Every perf trace Perl script should start by setting up a Perl module | 115 | Every perf script Perl script should start by setting up a Perl module |
| 116 | search path and 'use'ing a few support modules (see module | 116 | search path and 'use'ing a few support modules (see module |
| 117 | descriptions below): | 117 | descriptions below): |
| 118 | 118 | ||
| 119 | ---- | 119 | ---- |
| 120 | use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib"; | 120 | use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/perf-script-Util/lib"; |
| 121 | use lib "./Perf-Trace-Util/lib"; | 121 | use lib "./perf-script-Util/lib"; |
| 122 | use Perf::Trace::Core; | 122 | use Perf::Trace::Core; |
| 123 | use Perf::Trace::Context; | 123 | use Perf::Trace::Context; |
| 124 | use Perf::Trace::Util; | 124 | use Perf::Trace::Util; |
| @@ -162,7 +162,7 @@ sub trace_unhandled | |||
| 162 | ---- | 162 | ---- |
| 163 | 163 | ||
| 164 | The remaining sections provide descriptions of each of the available | 164 | The remaining sections provide descriptions of each of the available |
| 165 | built-in perf trace Perl modules and their associated functions. | 165 | built-in perf script Perl modules and their associated functions. |
| 166 | 166 | ||
| 167 | AVAILABLE MODULES AND FUNCTIONS | 167 | AVAILABLE MODULES AND FUNCTIONS |
| 168 | ------------------------------- | 168 | ------------------------------- |
| @@ -170,7 +170,7 @@ AVAILABLE MODULES AND FUNCTIONS | |||
| 170 | The following sections describe the functions and variables available | 170 | The following sections describe the functions and variables available |
| 171 | via the various Perf::Trace::* Perl modules. To use the functions and | 171 | via the various Perf::Trace::* Perl modules. To use the functions and |
| 172 | variables from the given module, add the corresponding 'use | 172 | variables from the given module, add the corresponding 'use |
| 173 | Perf::Trace::XXX' line to your perf trace script. | 173 | Perf::Trace::XXX' line to your perf script script. |
| 174 | 174 | ||
| 175 | Perf::Trace::Core Module | 175 | Perf::Trace::Core Module |
| 176 | ~~~~~~~~~~~~~~~~~~~~~~~~ | 176 | ~~~~~~~~~~~~~~~~~~~~~~~~ |
| @@ -204,7 +204,7 @@ argument. | |||
| 204 | Perf::Trace::Util Module | 204 | Perf::Trace::Util Module |
| 205 | ~~~~~~~~~~~~~~~~~~~~~~~~ | 205 | ~~~~~~~~~~~~~~~~~~~~~~~~ |
| 206 | 206 | ||
| 207 | Various utility functions for use with perf trace: | 207 | Various utility functions for use with perf script: |
| 208 | 208 | ||
| 209 | nsecs($secs, $nsecs) - returns total nsecs given secs/nsecs pair | 209 | nsecs($secs, $nsecs) - returns total nsecs given secs/nsecs pair |
| 210 | nsecs_secs($nsecs) - returns whole secs portion given nsecs | 210 | nsecs_secs($nsecs) - returns whole secs portion given nsecs |
| @@ -214,4 +214,4 @@ Various utility functions for use with perf trace: | |||
| 214 | 214 | ||
| 215 | SEE ALSO | 215 | SEE ALSO |
| 216 | -------- | 216 | -------- |
| 217 | linkperf:perf-trace[1] | 217 | linkperf:perf-script[1] |
diff --git a/tools/perf/Documentation/perf-trace-python.txt b/tools/perf/Documentation/perf-script-python.txt index 693be804dd3d..36b38277422c 100644 --- a/tools/perf/Documentation/perf-trace-python.txt +++ b/tools/perf/Documentation/perf-script-python.txt | |||
| @@ -1,19 +1,19 @@ | |||
| 1 | perf-trace-python(1) | 1 | perf-script-python(1) |
| 2 | ==================== | 2 | ==================== |
| 3 | 3 | ||
| 4 | NAME | 4 | NAME |
| 5 | ---- | 5 | ---- |
| 6 | perf-trace-python - Process trace data with a Python script | 6 | perf-script-python - Process trace data with a Python script |
| 7 | 7 | ||
| 8 | SYNOPSIS | 8 | SYNOPSIS |
| 9 | -------- | 9 | -------- |
| 10 | [verse] | 10 | [verse] |
| 11 | 'perf trace' [-s [Python]:script[.py] ] | 11 | 'perf script' [-s [Python]:script[.py] ] |
| 12 | 12 | ||
| 13 | DESCRIPTION | 13 | DESCRIPTION |
| 14 | ----------- | 14 | ----------- |
| 15 | 15 | ||
| 16 | This perf trace option is used to process perf trace data using perf's | 16 | This perf script option is used to process perf script data using perf's |
| 17 | built-in Python interpreter. It reads and processes the input file and | 17 | built-in Python interpreter. It reads and processes the input file and |
| 18 | displays the results of the trace analysis implemented in the given | 18 | displays the results of the trace analysis implemented in the given |
| 19 | Python script, if any. | 19 | Python script, if any. |
| @@ -23,15 +23,15 @@ A QUICK EXAMPLE | |||
| 23 | 23 | ||
| 24 | This section shows the process, start to finish, of creating a working | 24 | This section shows the process, start to finish, of creating a working |
| 25 | Python script that aggregates and extracts useful information from a | 25 | Python script that aggregates and extracts useful information from a |
| 26 | raw perf trace stream. You can avoid reading the rest of this | 26 | raw perf script stream. You can avoid reading the rest of this |
| 27 | document if an example is enough for you; the rest of the document | 27 | document if an example is enough for you; the rest of the document |
| 28 | provides more details on each step and lists the library functions | 28 | provides more details on each step and lists the library functions |
| 29 | available to script writers. | 29 | available to script writers. |
| 30 | 30 | ||
| 31 | This example actually details the steps that were used to create the | 31 | This example actually details the steps that were used to create the |
| 32 | 'syscall-counts' script you see when you list the available perf trace | 32 | 'syscall-counts' script you see when you list the available perf script |
| 33 | scripts via 'perf trace -l'. As such, this script also shows how to | 33 | scripts via 'perf script -l'. As such, this script also shows how to |
| 34 | integrate your script into the list of general-purpose 'perf trace' | 34 | integrate your script into the list of general-purpose 'perf script' |
| 35 | scripts listed by that command. | 35 | scripts listed by that command. |
| 36 | 36 | ||
| 37 | The syscall-counts script is a simple script, but demonstrates all the | 37 | The syscall-counts script is a simple script, but demonstrates all the |
| @@ -105,31 +105,31 @@ That single stream will be recorded in a file in the current directory | |||
| 105 | called perf.data. | 105 | called perf.data. |
| 106 | 106 | ||
| 107 | Once we have a perf.data file containing our data, we can use the -g | 107 | Once we have a perf.data file containing our data, we can use the -g |
| 108 | 'perf trace' option to generate a Python script that will contain a | 108 | 'perf script' option to generate a Python script that will contain a |
| 109 | callback handler for each event type found in the perf.data trace | 109 | callback handler for each event type found in the perf.data trace |
| 110 | stream (for more details, see the STARTER SCRIPTS section). | 110 | stream (for more details, see the STARTER SCRIPTS section). |
| 111 | 111 | ||
| 112 | ---- | 112 | ---- |
| 113 | # perf trace -g python | 113 | # perf script -g python |
| 114 | generated Python script: perf-trace.py | 114 | generated Python script: perf-script.py |
| 115 | 115 | ||
| 116 | The output file created also in the current directory is named | 116 | The output file created also in the current directory is named |
| 117 | perf-trace.py. Here's the file in its entirety: | 117 | perf-script.py. Here's the file in its entirety: |
| 118 | 118 | ||
| 119 | # perf trace event handlers, generated by perf trace -g python | 119 | # perf script event handlers, generated by perf script -g python |
| 120 | # Licensed under the terms of the GNU GPL License version 2 | 120 | # Licensed under the terms of the GNU GPL License version 2 |
| 121 | 121 | ||
| 122 | # The common_* event handler fields are the most useful fields common to | 122 | # The common_* event handler fields are the most useful fields common to |
| 123 | # all events. They don't necessarily correspond to the 'common_*' fields | 123 | # all events. They don't necessarily correspond to the 'common_*' fields |
| 124 | # in the format files. Those fields not available as handler params can | 124 | # in the format files. Those fields not available as handler params can |
| 125 | # be retrieved using Python functions of the form common_*(context). | 125 | # be retrieved using Python functions of the form common_*(context). |
| 126 | # See the perf-trace-python Documentation for the list of available functions. | 126 | # See the perf-script-python Documentation for the list of available functions. |
| 127 | 127 | ||
| 128 | import os | 128 | import os |
| 129 | import sys | 129 | import sys |
| 130 | 130 | ||
| 131 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | 131 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ |
| 132 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') | 132 | '/scripts/python/perf-script-Util/lib/Perf/Trace') |
| 133 | 133 | ||
| 134 | from perf_trace_context import * | 134 | from perf_trace_context import * |
| 135 | from Core import * | 135 | from Core import * |
| @@ -160,7 +160,7 @@ def print_header(event_name, cpu, secs, nsecs, pid, comm): | |||
| 160 | ---- | 160 | ---- |
| 161 | 161 | ||
| 162 | At the top is a comment block followed by some import statements and a | 162 | At the top is a comment block followed by some import statements and a |
| 163 | path append which every perf trace script should include. | 163 | path append which every perf script script should include. |
| 164 | 164 | ||
| 165 | Following that are a couple generated functions, trace_begin() and | 165 | Following that are a couple generated functions, trace_begin() and |
| 166 | trace_end(), which are called at the beginning and the end of the | 166 | trace_end(), which are called at the beginning and the end of the |
| @@ -189,8 +189,8 @@ simply a utility function used for that purpose. Let's rename the | |||
| 189 | script and run it to see the default output: | 189 | script and run it to see the default output: |
| 190 | 190 | ||
| 191 | ---- | 191 | ---- |
| 192 | # mv perf-trace.py syscall-counts.py | 192 | # mv perf-script.py syscall-counts.py |
| 193 | # perf trace -s syscall-counts.py | 193 | # perf script -s syscall-counts.py |
| 194 | 194 | ||
| 195 | raw_syscalls__sys_enter 1 00840.847582083 7506 perf id=1, args= | 195 | raw_syscalls__sys_enter 1 00840.847582083 7506 perf id=1, args= |
| 196 | raw_syscalls__sys_enter 1 00840.847595764 7506 perf id=1, args= | 196 | raw_syscalls__sys_enter 1 00840.847595764 7506 perf id=1, args= |
| @@ -216,7 +216,7 @@ import os | |||
| 216 | import sys | 216 | import sys |
| 217 | 217 | ||
| 218 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | 218 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ |
| 219 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') | 219 | '/scripts/python/perf-script-Util/lib/Perf/Trace') |
| 220 | 220 | ||
| 221 | from perf_trace_context import * | 221 | from perf_trace_context import * |
| 222 | from Core import * | 222 | from Core import * |
| @@ -279,7 +279,7 @@ import os | |||
| 279 | import sys | 279 | import sys |
| 280 | 280 | ||
| 281 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | 281 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ |
| 282 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') | 282 | '/scripts/python/perf-script-Util/lib/Perf/Trace') |
| 283 | 283 | ||
| 284 | from perf_trace_context import * | 284 | from perf_trace_context import * |
| 285 | from Core import * | 285 | from Core import * |
| @@ -315,7 +315,7 @@ def print_syscall_totals(): | |||
| 315 | 315 | ||
| 316 | The script can be run just as before: | 316 | The script can be run just as before: |
| 317 | 317 | ||
| 318 | # perf trace -s syscall-counts.py | 318 | # perf script -s syscall-counts.py |
| 319 | 319 | ||
| 320 | So those are the essential steps in writing and running a script. The | 320 | So those are the essential steps in writing and running a script. The |
| 321 | process can be generalized to any tracepoint or set of tracepoints | 321 | process can be generalized to any tracepoint or set of tracepoints |
| @@ -324,17 +324,17 @@ interested in by looking at the list of available events shown by | |||
| 324 | 'perf list' and/or look in /sys/kernel/debug/tracing events for | 324 | 'perf list' and/or look in /sys/kernel/debug/tracing events for |
| 325 | detailed event and field info, record the corresponding trace data | 325 | detailed event and field info, record the corresponding trace data |
| 326 | using 'perf record', passing it the list of interesting events, | 326 | using 'perf record', passing it the list of interesting events, |
| 327 | generate a skeleton script using 'perf trace -g python' and modify the | 327 | generate a skeleton script using 'perf script -g python' and modify the |
| 328 | code to aggregate and display it for your particular needs. | 328 | code to aggregate and display it for your particular needs. |
| 329 | 329 | ||
| 330 | After you've done that you may end up with a general-purpose script | 330 | After you've done that you may end up with a general-purpose script |
| 331 | that you want to keep around and have available for future use. By | 331 | that you want to keep around and have available for future use. By |
| 332 | writing a couple of very simple shell scripts and putting them in the | 332 | writing a couple of very simple shell scripts and putting them in the |
| 333 | right place, you can have your script listed alongside the other | 333 | right place, you can have your script listed alongside the other |
| 334 | scripts listed by the 'perf trace -l' command e.g.: | 334 | scripts listed by the 'perf script -l' command e.g.: |
| 335 | 335 | ||
| 336 | ---- | 336 | ---- |
| 337 | root@tropicana:~# perf trace -l | 337 | root@tropicana:~# perf script -l |
| 338 | List of available trace scripts: | 338 | List of available trace scripts: |
| 339 | workqueue-stats workqueue stats (ins/exe/create/destroy) | 339 | workqueue-stats workqueue stats (ins/exe/create/destroy) |
| 340 | wakeup-latency system-wide min/max/avg wakeup latency | 340 | wakeup-latency system-wide min/max/avg wakeup latency |
| @@ -365,14 +365,14 @@ perf record -a -e raw_syscalls:sys_enter | |||
| 365 | The 'report' script is also a shell script with the same base name as | 365 | The 'report' script is also a shell script with the same base name as |
| 366 | your script, but with -report appended. It should also be located in | 366 | your script, but with -report appended. It should also be located in |
| 367 | the perf/scripts/python/bin directory. In that script, you write the | 367 | the perf/scripts/python/bin directory. In that script, you write the |
| 368 | 'perf trace -s' command-line needed for running your script: | 368 | 'perf script -s' command-line needed for running your script: |
| 369 | 369 | ||
| 370 | ---- | 370 | ---- |
| 371 | # cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-report | 371 | # cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-report |
| 372 | 372 | ||
| 373 | #!/bin/bash | 373 | #!/bin/bash |
| 374 | # description: system-wide syscall counts | 374 | # description: system-wide syscall counts |
| 375 | perf trace -s ~/libexec/perf-core/scripts/python/syscall-counts.py | 375 | perf script -s ~/libexec/perf-core/scripts/python/syscall-counts.py |
| 376 | ---- | 376 | ---- |
| 377 | 377 | ||
| 378 | Note that the location of the Python script given in the shell script | 378 | Note that the location of the Python script given in the shell script |
| @@ -390,17 +390,17 @@ total 32 | |||
| 390 | drwxr-xr-x 4 trz trz 4096 2010-01-26 22:30 . | 390 | drwxr-xr-x 4 trz trz 4096 2010-01-26 22:30 . |
| 391 | drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 .. | 391 | drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 .. |
| 392 | drwxr-xr-x 2 trz trz 4096 2010-01-26 22:29 bin | 392 | drwxr-xr-x 2 trz trz 4096 2010-01-26 22:29 bin |
| 393 | -rw-r--r-- 1 trz trz 2548 2010-01-26 22:29 check-perf-trace.py | 393 | -rw-r--r-- 1 trz trz 2548 2010-01-26 22:29 check-perf-script.py |
| 394 | drwxr-xr-x 3 trz trz 4096 2010-01-26 22:49 Perf-Trace-Util | 394 | drwxr-xr-x 3 trz trz 4096 2010-01-26 22:49 perf-script-Util |
| 395 | -rw-r--r-- 1 trz trz 1462 2010-01-26 22:30 syscall-counts.py | 395 | -rw-r--r-- 1 trz trz 1462 2010-01-26 22:30 syscall-counts.py |
| 396 | ---- | 396 | ---- |
| 397 | 397 | ||
| 398 | Once you've done that (don't forget to do a new 'make install', | 398 | Once you've done that (don't forget to do a new 'make install', |
| 399 | otherwise your script won't show up at run-time), 'perf trace -l' | 399 | otherwise your script won't show up at run-time), 'perf script -l' |
| 400 | should show a new entry for your script: | 400 | should show a new entry for your script: |
| 401 | 401 | ||
| 402 | ---- | 402 | ---- |
| 403 | root@tropicana:~# perf trace -l | 403 | root@tropicana:~# perf script -l |
| 404 | List of available trace scripts: | 404 | List of available trace scripts: |
| 405 | workqueue-stats workqueue stats (ins/exe/create/destroy) | 405 | workqueue-stats workqueue stats (ins/exe/create/destroy) |
| 406 | wakeup-latency system-wide min/max/avg wakeup latency | 406 | wakeup-latency system-wide min/max/avg wakeup latency |
| @@ -409,19 +409,19 @@ List of available trace scripts: | |||
| 409 | syscall-counts system-wide syscall counts | 409 | syscall-counts system-wide syscall counts |
| 410 | ---- | 410 | ---- |
| 411 | 411 | ||
| 412 | You can now perform the record step via 'perf trace record': | 412 | You can now perform the record step via 'perf script record': |
| 413 | 413 | ||
| 414 | # perf trace record syscall-counts | 414 | # perf script record syscall-counts |
| 415 | 415 | ||
| 416 | and display the output using 'perf trace report': | 416 | and display the output using 'perf script report': |
| 417 | 417 | ||
| 418 | # perf trace report syscall-counts | 418 | # perf script report syscall-counts |
| 419 | 419 | ||
| 420 | STARTER SCRIPTS | 420 | STARTER SCRIPTS |
| 421 | --------------- | 421 | --------------- |
| 422 | 422 | ||
| 423 | You can quickly get started writing a script for a particular set of | 423 | You can quickly get started writing a script for a particular set of |
| 424 | trace data by generating a skeleton script using 'perf trace -g | 424 | trace data by generating a skeleton script using 'perf script -g |
| 425 | python' in the same directory as an existing perf.data trace file. | 425 | python' in the same directory as an existing perf.data trace file. |
| 426 | That will generate a starter script containing a handler for each of | 426 | That will generate a starter script containing a handler for each of |
| 427 | the event types in the trace file; it simply prints every available | 427 | the event types in the trace file; it simply prints every available |
| @@ -430,13 +430,13 @@ field for each event in the trace file. | |||
| 430 | You can also look at the existing scripts in | 430 | You can also look at the existing scripts in |
| 431 | ~/libexec/perf-core/scripts/python for typical examples showing how to | 431 | ~/libexec/perf-core/scripts/python for typical examples showing how to |
| 432 | do basic things like aggregate event data, print results, etc. Also, | 432 | do basic things like aggregate event data, print results, etc. Also, |
| 433 | the check-perf-trace.py script, while not interesting for its results, | 433 | the check-perf-script.py script, while not interesting for its results, |
| 434 | attempts to exercise all of the main scripting features. | 434 | attempts to exercise all of the main scripting features. |
| 435 | 435 | ||
| 436 | EVENT HANDLERS | 436 | EVENT HANDLERS |
| 437 | -------------- | 437 | -------------- |
| 438 | 438 | ||
| 439 | When perf trace is invoked using a trace script, a user-defined | 439 | When perf script is invoked using a trace script, a user-defined |
| 440 | 'handler function' is called for each event in the trace. If there's | 440 | 'handler function' is called for each event in the trace. If there's |
| 441 | no handler function defined for a given event type, the event is | 441 | no handler function defined for a given event type, the event is |
| 442 | ignored (or passed to a 'trace_handled' function, see below) and the | 442 | ignored (or passed to a 'trace_handled' function, see below) and the |
| @@ -510,7 +510,7 @@ write a useful trace script. The sections below cover the rest. | |||
| 510 | SCRIPT LAYOUT | 510 | SCRIPT LAYOUT |
| 511 | ------------- | 511 | ------------- |
| 512 | 512 | ||
| 513 | Every perf trace Python script should start by setting up a Python | 513 | Every perf script Python script should start by setting up a Python |
| 514 | module search path and 'import'ing a few support modules (see module | 514 | module search path and 'import'ing a few support modules (see module |
| 515 | descriptions below): | 515 | descriptions below): |
| 516 | 516 | ||
| @@ -519,7 +519,7 @@ descriptions below): | |||
| 519 | import sys | 519 | import sys |
| 520 | 520 | ||
| 521 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | 521 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ |
| 522 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') | 522 | '/scripts/python/perf-script-Util/lib/Perf/Trace') |
| 523 | 523 | ||
| 524 | from perf_trace_context import * | 524 | from perf_trace_context import * |
| 525 | from Core import * | 525 | from Core import * |
| @@ -559,15 +559,15 @@ def trace_unhandled(event_name, context, common_cpu, common_secs, | |||
| 559 | ---- | 559 | ---- |
| 560 | 560 | ||
| 561 | The remaining sections provide descriptions of each of the available | 561 | The remaining sections provide descriptions of each of the available |
| 562 | built-in perf trace Python modules and their associated functions. | 562 | built-in perf script Python modules and their associated functions. |
| 563 | 563 | ||
| 564 | AVAILABLE MODULES AND FUNCTIONS | 564 | AVAILABLE MODULES AND FUNCTIONS |
| 565 | ------------------------------- | 565 | ------------------------------- |
| 566 | 566 | ||
| 567 | The following sections describe the functions and variables available | 567 | The following sections describe the functions and variables available |
| 568 | via the various perf trace Python modules. To use the functions and | 568 | via the various perf script Python modules. To use the functions and |
| 569 | variables from the given module, add the corresponding 'from XXXX | 569 | variables from the given module, add the corresponding 'from XXXX |
| 570 | import' line to your perf trace script. | 570 | import' line to your perf script script. |
| 571 | 571 | ||
| 572 | Core.py Module | 572 | Core.py Module |
| 573 | ~~~~~~~~~~~~~~ | 573 | ~~~~~~~~~~~~~~ |
| @@ -610,7 +610,7 @@ argument. | |||
| 610 | Util.py Module | 610 | Util.py Module |
| 611 | ~~~~~~~~~~~~~~ | 611 | ~~~~~~~~~~~~~~ |
| 612 | 612 | ||
| 613 | Various utility functions for use with perf trace: | 613 | Various utility functions for use with perf script: |
| 614 | 614 | ||
| 615 | nsecs(secs, nsecs) - returns total nsecs given secs/nsecs pair | 615 | nsecs(secs, nsecs) - returns total nsecs given secs/nsecs pair |
| 616 | nsecs_secs(nsecs) - returns whole secs portion given nsecs | 616 | nsecs_secs(nsecs) - returns whole secs portion given nsecs |
| @@ -620,4 +620,4 @@ Various utility functions for use with perf trace: | |||
| 620 | 620 | ||
| 621 | SEE ALSO | 621 | SEE ALSO |
| 622 | -------- | 622 | -------- |
| 623 | linkperf:perf-trace[1] | 623 | linkperf:perf-script[1] |
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-script.txt index 26aff6bf9e50..29ad94293cd2 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-script.txt | |||
| @@ -1,71 +1,71 @@ | |||
| 1 | perf-trace(1) | 1 | perf-script(1) |
| 2 | ============= | 2 | ============= |
| 3 | 3 | ||
| 4 | NAME | 4 | NAME |
| 5 | ---- | 5 | ---- |
| 6 | perf-trace - Read perf.data (created by perf record) and display trace output | 6 | perf-script - Read perf.data (created by perf record) and display trace output |
| 7 | 7 | ||
| 8 | SYNOPSIS | 8 | SYNOPSIS |
| 9 | -------- | 9 | -------- |
| 10 | [verse] | 10 | [verse] |
| 11 | 'perf trace' [<options>] | 11 | 'perf script' [<options>] |
| 12 | 'perf trace' [<options>] record <script> [<record-options>] <command> | 12 | 'perf script' [<options>] record <script> [<record-options>] <command> |
| 13 | 'perf trace' [<options>] report <script> [script-args] | 13 | 'perf script' [<options>] report <script> [script-args] |
| 14 | 'perf trace' [<options>] <script> <required-script-args> [<record-options>] <command> | 14 | 'perf script' [<options>] <script> <required-script-args> [<record-options>] <command> |
| 15 | 'perf trace' [<options>] <top-script> [script-args] | 15 | 'perf script' [<options>] <top-script> [script-args] |
| 16 | 16 | ||
| 17 | DESCRIPTION | 17 | DESCRIPTION |
| 18 | ----------- | 18 | ----------- |
| 19 | This command reads the input file and displays the trace recorded. | 19 | This command reads the input file and displays the trace recorded. |
| 20 | 20 | ||
| 21 | There are several variants of perf trace: | 21 | There are several variants of perf script: |
| 22 | 22 | ||
| 23 | 'perf trace' to see a detailed trace of the workload that was | 23 | 'perf script' to see a detailed trace of the workload that was |
| 24 | recorded. | 24 | recorded. |
| 25 | 25 | ||
| 26 | You can also run a set of pre-canned scripts that aggregate and | 26 | You can also run a set of pre-canned scripts that aggregate and |
| 27 | summarize the raw trace data in various ways (the list of scripts is | 27 | summarize the raw trace data in various ways (the list of scripts is |
| 28 | available via 'perf trace -l'). The following variants allow you to | 28 | available via 'perf script -l'). The following variants allow you to |
| 29 | record and run those scripts: | 29 | record and run those scripts: |
| 30 | 30 | ||
| 31 | 'perf trace record <script> <command>' to record the events required | 31 | 'perf script record <script> <command>' to record the events required |
| 32 | for 'perf trace report'. <script> is the name displayed in the | 32 | for 'perf script report'. <script> is the name displayed in the |
| 33 | output of 'perf trace --list' i.e. the actual script name minus any | 33 | output of 'perf script --list' i.e. the actual script name minus any |
| 34 | language extension. If <command> is not specified, the events are | 34 | language extension. If <command> is not specified, the events are |
| 35 | recorded using the -a (system-wide) 'perf record' option. | 35 | recorded using the -a (system-wide) 'perf record' option. |
| 36 | 36 | ||
| 37 | 'perf trace report <script> [args]' to run and display the results | 37 | 'perf script report <script> [args]' to run and display the results |
| 38 | of <script>. <script> is the name displayed in the output of 'perf | 38 | of <script>. <script> is the name displayed in the output of 'perf |
| 39 | trace --list' i.e. the actual script name minus any language | 39 | trace --list' i.e. the actual script name minus any language |
| 40 | extension. The perf.data output from a previous run of 'perf trace | 40 | extension. The perf.data output from a previous run of 'perf script |
| 41 | record <script>' is used and should be present for this command to | 41 | record <script>' is used and should be present for this command to |
| 42 | succeed. [args] refers to the (mainly optional) args expected by | 42 | succeed. [args] refers to the (mainly optional) args expected by |
| 43 | the script. | 43 | the script. |
| 44 | 44 | ||
| 45 | 'perf trace <script> <required-script-args> <command>' to both | 45 | 'perf script <script> <required-script-args> <command>' to both |
| 46 | record the events required for <script> and to run the <script> | 46 | record the events required for <script> and to run the <script> |
| 47 | using 'live-mode' i.e. without writing anything to disk. <script> | 47 | using 'live-mode' i.e. without writing anything to disk. <script> |
| 48 | is the name displayed in the output of 'perf trace --list' i.e. the | 48 | is the name displayed in the output of 'perf script --list' i.e. the |
| 49 | actual script name minus any language extension. If <command> is | 49 | actual script name minus any language extension. If <command> is |
| 50 | not specified, the events are recorded using the -a (system-wide) | 50 | not specified, the events are recorded using the -a (system-wide) |
| 51 | 'perf record' option. If <script> has any required args, they | 51 | 'perf record' option. If <script> has any required args, they |
| 52 | should be specified before <command>. This mode doesn't allow for | 52 | should be specified before <command>. This mode doesn't allow for |
| 53 | optional script args to be specified; if optional script args are | 53 | optional script args to be specified; if optional script args are |
| 54 | desired, they can be specified using separate 'perf trace record' | 54 | desired, they can be specified using separate 'perf script record' |
| 55 | and 'perf trace report' commands, with the stdout of the record step | 55 | and 'perf script report' commands, with the stdout of the record step |
| 56 | piped to the stdin of the report script, using the '-o -' and '-i -' | 56 | piped to the stdin of the report script, using the '-o -' and '-i -' |
| 57 | options of the corresponding commands. | 57 | options of the corresponding commands. |
| 58 | 58 | ||
| 59 | 'perf trace <top-script>' to both record the events required for | 59 | 'perf script <top-script>' to both record the events required for |
| 60 | <top-script> and to run the <top-script> using 'live-mode' | 60 | <top-script> and to run the <top-script> using 'live-mode' |
| 61 | i.e. without writing anything to disk. <top-script> is the name | 61 | i.e. without writing anything to disk. <top-script> is the name |
| 62 | displayed in the output of 'perf trace --list' i.e. the actual | 62 | displayed in the output of 'perf script --list' i.e. the actual |
| 63 | script name minus any language extension; a <top-script> is defined | 63 | script name minus any language extension; a <top-script> is defined |
| 64 | as any script name ending with the string 'top'. | 64 | as any script name ending with the string 'top'. |
| 65 | 65 | ||
| 66 | [<record-options>] can be passed to the record steps of 'perf trace | 66 | [<record-options>] can be passed to the record steps of 'perf script |
| 67 | record' and 'live-mode' variants; this isn't possible however for | 67 | record' and 'live-mode' variants; this isn't possible however for |
| 68 | <top-script> 'live-mode' or 'perf trace report' variants. | 68 | <top-script> 'live-mode' or 'perf script report' variants. |
| 69 | 69 | ||
| 70 | See the 'SEE ALSO' section for links to language-specific | 70 | See the 'SEE ALSO' section for links to language-specific |
| 71 | information on how to write and run your own trace scripts. | 71 | information on how to write and run your own trace scripts. |
| @@ -76,7 +76,7 @@ OPTIONS | |||
| 76 | Any command you can specify in a shell. | 76 | Any command you can specify in a shell. |
| 77 | 77 | ||
| 78 | -D:: | 78 | -D:: |
| 79 | --dump-raw-trace=:: | 79 | --dump-raw-script=:: |
| 80 | Display verbose dump of the trace data. | 80 | Display verbose dump of the trace data. |
| 81 | 81 | ||
| 82 | -L:: | 82 | -L:: |
| @@ -95,7 +95,7 @@ OPTIONS | |||
| 95 | 95 | ||
| 96 | -g:: | 96 | -g:: |
| 97 | --gen-script=:: | 97 | --gen-script=:: |
| 98 | Generate perf-trace.[ext] starter script for given language, | 98 | Generate perf-script.[ext] starter script for given language, |
| 99 | using current perf.data. | 99 | using current perf.data. |
| 100 | 100 | ||
| 101 | -a:: | 101 | -a:: |
| @@ -104,8 +104,15 @@ OPTIONS | |||
| 104 | normally don't - this option allows the latter to be run in | 104 | normally don't - this option allows the latter to be run in |
| 105 | system-wide mode. | 105 | system-wide mode. |
| 106 | 106 | ||
| 107 | -i:: | ||
| 108 | --input=:: | ||
| 109 | Input file name. | ||
| 110 | |||
| 111 | -d:: | ||
| 112 | --debug-mode:: | ||
| 113 | Do various checks like samples ordering and lost events. | ||
| 107 | 114 | ||
| 108 | SEE ALSO | 115 | SEE ALSO |
| 109 | -------- | 116 | -------- |
| 110 | linkperf:perf-record[1], linkperf:perf-trace-perl[1], | 117 | linkperf:perf-record[1], linkperf:perf-script-perl[1], |
| 111 | linkperf:perf-trace-python[1] | 118 | linkperf:perf-script-python[1] |
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 4b3a2d46b437..b6da7affbbee 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt | |||
| @@ -8,8 +8,8 @@ perf-stat - Run a command and gather performance counter statistics | |||
| 8 | SYNOPSIS | 8 | SYNOPSIS |
| 9 | -------- | 9 | -------- |
| 10 | [verse] | 10 | [verse] |
| 11 | 'perf stat' [-e <EVENT> | --event=EVENT] [-S] [-a] <command> | 11 | 'perf stat' [-e <EVENT> | --event=EVENT] [-a] <command> |
| 12 | 'perf stat' [-e <EVENT> | --event=EVENT] [-S] [-a] -- <command> [<options>] | 12 | 'perf stat' [-e <EVENT> | --event=EVENT] [-a] -- <command> [<options>] |
| 13 | 13 | ||
| 14 | DESCRIPTION | 14 | DESCRIPTION |
| 15 | ----------- | 15 | ----------- |
| @@ -35,24 +35,54 @@ OPTIONS | |||
| 35 | child tasks do not inherit counters | 35 | child tasks do not inherit counters |
| 36 | -p:: | 36 | -p:: |
| 37 | --pid=<pid>:: | 37 | --pid=<pid>:: |
| 38 | stat events on existing pid | 38 | stat events on existing process id |
| 39 | |||
| 40 | -t:: | ||
| 41 | --tid=<tid>:: | ||
| 42 | stat events on existing thread id | ||
| 43 | |||
| 39 | 44 | ||
| 40 | -a:: | 45 | -a:: |
| 41 | system-wide collection | 46 | --all-cpus:: |
| 47 | system-wide collection from all CPUs | ||
| 42 | 48 | ||
| 43 | -c:: | 49 | -c:: |
| 44 | scale counter values | 50 | --scale:: |
| 51 | scale/normalize counter values | ||
| 52 | |||
| 53 | -r:: | ||
| 54 | --repeat=<n>:: | ||
| 55 | repeat command and print average + stddev (max: 100) | ||
| 45 | 56 | ||
| 46 | -B:: | 57 | -B:: |
| 58 | --big-num:: | ||
| 47 | print large numbers with thousands' separators according to locale | 59 | print large numbers with thousands' separators according to locale |
| 48 | 60 | ||
| 49 | -C:: | 61 | -C:: |
| 50 | --cpu=:: | 62 | --cpu=:: |
| 51 | Count only on the list of cpus provided. Multiple CPUs can be provided as a | 63 | Count only on the list of CPUs provided. Multiple CPUs can be provided as a |
| 52 | comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. | 64 | comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. |
| 53 | In per-thread mode, this option is ignored. The -a option is still necessary | 65 | In per-thread mode, this option is ignored. The -a option is still necessary |
| 54 | to activate system-wide monitoring. Default is to count on all CPUs. | 66 | to activate system-wide monitoring. Default is to count on all CPUs. |
| 55 | 67 | ||
| 68 | -A:: | ||
| 69 | --no-aggr:: | ||
| 70 | Do not aggregate counts across all monitored CPUs in system-wide mode (-a). | ||
| 71 | This option is only valid in system-wide mode. | ||
| 72 | |||
| 73 | -n:: | ||
| 74 | --null:: | ||
| 75 | null run - don't start any counters | ||
| 76 | |||
| 77 | -v:: | ||
| 78 | --verbose:: | ||
| 79 | be more verbose (show counter open errors, etc) | ||
| 80 | |||
| 81 | -x SEP:: | ||
| 82 | --field-separator SEP:: | ||
| 83 | print counts using a CSV-style output to make it easy to import directly into | ||
| 84 | spreadsheets. Columns are separated by the string specified in SEP. | ||
| 85 | |||
| 56 | EXAMPLES | 86 | EXAMPLES |
| 57 | -------- | 87 | -------- |
| 58 | 88 | ||
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt index 1c4b5f5b7f71..2c3b462f64b0 100644 --- a/tools/perf/Documentation/perf-test.txt +++ b/tools/perf/Documentation/perf-test.txt | |||
| @@ -12,7 +12,7 @@ SYNOPSIS | |||
| 12 | 12 | ||
| 13 | DESCRIPTION | 13 | DESCRIPTION |
| 14 | ----------- | 14 | ----------- |
| 15 | This command does assorted sanity tests, initially thru linked routines but | 15 | This command does assorted sanity tests, initially through linked routines but |
| 16 | also will look for a directory with more tests in the form of scripts. | 16 | also will look for a directory with more tests in the form of scripts. |
| 17 | 17 | ||
| 18 | OPTIONS | 18 | OPTIONS |
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 1f9687663f2a..f6eb1cdafb77 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt | |||
| @@ -12,7 +12,7 @@ SYNOPSIS | |||
| 12 | 12 | ||
| 13 | DESCRIPTION | 13 | DESCRIPTION |
| 14 | ----------- | 14 | ----------- |
| 15 | This command generates and displays a performance counter profile in realtime. | 15 | This command generates and displays a performance counter profile in real time. |
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | OPTIONS | 18 | OPTIONS |
| @@ -27,8 +27,8 @@ OPTIONS | |||
| 27 | 27 | ||
| 28 | -C <cpu-list>:: | 28 | -C <cpu-list>:: |
| 29 | --cpu=<cpu>:: | 29 | --cpu=<cpu>:: |
| 30 | Monitor only on the list of cpus provided. Multiple CPUs can be provided as a | 30 | Monitor only on the list of CPUs provided. Multiple CPUs can be provided as a |
| 31 | comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. | 31 | comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. |
| 32 | Default is to monitor all CPUS. | 32 | Default is to monitor all CPUS. |
| 33 | 33 | ||
| 34 | -d <seconds>:: | 34 | -d <seconds>:: |
| @@ -50,6 +50,10 @@ Default is to monitor all CPUS. | |||
| 50 | --count-filter=<count>:: | 50 | --count-filter=<count>:: |
| 51 | Only display functions with more events than this. | 51 | Only display functions with more events than this. |
| 52 | 52 | ||
| 53 | -g:: | ||
| 54 | --group:: | ||
| 55 | Put the counters into a counter group. | ||
| 56 | |||
| 53 | -F <freq>:: | 57 | -F <freq>:: |
| 54 | --freq=<freq>:: | 58 | --freq=<freq>:: |
| 55 | Profile at this frequency. | 59 | Profile at this frequency. |
| @@ -68,7 +72,11 @@ Default is to monitor all CPUS. | |||
| 68 | 72 | ||
| 69 | -p <pid>:: | 73 | -p <pid>:: |
| 70 | --pid=<pid>:: | 74 | --pid=<pid>:: |
| 71 | Profile events on existing pid. | 75 | Profile events on existing Process ID. |
| 76 | |||
| 77 | -t <tid>:: | ||
| 78 | --tid=<tid>:: | ||
| 79 | Profile events on existing thread ID. | ||
| 72 | 80 | ||
| 73 | -r <priority>:: | 81 | -r <priority>:: |
| 74 | --realtime=<priority>:: | 82 | --realtime=<priority>:: |
| @@ -78,6 +86,18 @@ Default is to monitor all CPUS. | |||
| 78 | --sym-annotate=<symbol>:: | 86 | --sym-annotate=<symbol>:: |
| 79 | Annotate this symbol. | 87 | Annotate this symbol. |
| 80 | 88 | ||
| 89 | -K:: | ||
| 90 | --hide_kernel_symbols:: | ||
| 91 | Hide kernel symbols. | ||
| 92 | |||
| 93 | -U:: | ||
| 94 | --hide_user_symbols:: | ||
| 95 | Hide user symbols. | ||
| 96 | |||
| 97 | -D:: | ||
| 98 | --dump-symtab:: | ||
| 99 | Dump the symbol table used for profiling. | ||
| 100 | |||
| 81 | -v:: | 101 | -v:: |
| 82 | --verbose:: | 102 | --verbose:: |
| 83 | Be more verbose (show counter open errors, etc). | 103 | Be more verbose (show counter open errors, etc). |
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 8c7fc0c8f0b8..c12659d8cb26 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST | |||
| @@ -7,6 +7,7 @@ include/linux/stringify.h | |||
| 7 | lib/rbtree.c | 7 | lib/rbtree.c |
| 8 | include/linux/swab.h | 8 | include/linux/swab.h |
| 9 | arch/*/include/asm/unistd*.h | 9 | arch/*/include/asm/unistd*.h |
| 10 | arch/*/lib/memcpy*.S | ||
| 10 | include/linux/poison.h | 11 | include/linux/poison.h |
| 11 | include/linux/magic.h | 12 | include/linux/magic.h |
| 12 | include/linux/hw_breakpoint.h | 13 | include/linux/hw_breakpoint.h |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index d1db0f676a4b..ac6692cf5508 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
| @@ -185,7 +185,10 @@ ifeq ($(ARCH),i386) | |||
| 185 | ARCH := x86 | 185 | ARCH := x86 |
| 186 | endif | 186 | endif |
| 187 | ifeq ($(ARCH),x86_64) | 187 | ifeq ($(ARCH),x86_64) |
| 188 | RAW_ARCH := x86_64 | ||
| 188 | ARCH := x86 | 189 | ARCH := x86 |
| 190 | ARCH_CFLAGS := -DARCH_X86_64 | ||
| 191 | ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S | ||
| 189 | endif | 192 | endif |
| 190 | 193 | ||
| 191 | # CFLAGS and LDFLAGS are for the users to override from the command line. | 194 | # CFLAGS and LDFLAGS are for the users to override from the command line. |
| @@ -375,6 +378,7 @@ LIB_H += util/include/linux/prefetch.h | |||
| 375 | LIB_H += util/include/linux/rbtree.h | 378 | LIB_H += util/include/linux/rbtree.h |
| 376 | LIB_H += util/include/linux/string.h | 379 | LIB_H += util/include/linux/string.h |
| 377 | LIB_H += util/include/linux/types.h | 380 | LIB_H += util/include/linux/types.h |
| 381 | LIB_H += util/include/linux/linkage.h | ||
| 378 | LIB_H += util/include/asm/asm-offsets.h | 382 | LIB_H += util/include/asm/asm-offsets.h |
| 379 | LIB_H += util/include/asm/bug.h | 383 | LIB_H += util/include/asm/bug.h |
| 380 | LIB_H += util/include/asm/byteorder.h | 384 | LIB_H += util/include/asm/byteorder.h |
| @@ -383,6 +387,8 @@ LIB_H += util/include/asm/swab.h | |||
| 383 | LIB_H += util/include/asm/system.h | 387 | LIB_H += util/include/asm/system.h |
| 384 | LIB_H += util/include/asm/uaccess.h | 388 | LIB_H += util/include/asm/uaccess.h |
| 385 | LIB_H += util/include/dwarf-regs.h | 389 | LIB_H += util/include/dwarf-regs.h |
| 390 | LIB_H += util/include/asm/dwarf2.h | ||
| 391 | LIB_H += util/include/asm/cpufeature.h | ||
| 386 | LIB_H += perf.h | 392 | LIB_H += perf.h |
| 387 | LIB_H += util/cache.h | 393 | LIB_H += util/cache.h |
| 388 | LIB_H += util/callchain.h | 394 | LIB_H += util/callchain.h |
| @@ -417,6 +423,7 @@ LIB_H += util/probe-finder.h | |||
| 417 | LIB_H += util/probe-event.h | 423 | LIB_H += util/probe-event.h |
| 418 | LIB_H += util/pstack.h | 424 | LIB_H += util/pstack.h |
| 419 | LIB_H += util/cpumap.h | 425 | LIB_H += util/cpumap.h |
| 426 | LIB_H += $(ARCH_INCLUDE) | ||
| 420 | 427 | ||
| 421 | LIB_OBJS += $(OUTPUT)util/abspath.o | 428 | LIB_OBJS += $(OUTPUT)util/abspath.o |
| 422 | LIB_OBJS += $(OUTPUT)util/alias.o | 429 | LIB_OBJS += $(OUTPUT)util/alias.o |
| @@ -472,6 +479,9 @@ BUILTIN_OBJS += $(OUTPUT)builtin-bench.o | |||
| 472 | # Benchmark modules | 479 | # Benchmark modules |
| 473 | BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o | 480 | BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o |
| 474 | BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o | 481 | BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o |
| 482 | ifeq ($(RAW_ARCH),x86_64) | ||
| 483 | BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o | ||
| 484 | endif | ||
| 475 | BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o | 485 | BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o |
| 476 | 486 | ||
| 477 | BUILTIN_OBJS += $(OUTPUT)builtin-diff.o | 487 | BUILTIN_OBJS += $(OUTPUT)builtin-diff.o |
| @@ -485,7 +495,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-report.o | |||
| 485 | BUILTIN_OBJS += $(OUTPUT)builtin-stat.o | 495 | BUILTIN_OBJS += $(OUTPUT)builtin-stat.o |
| 486 | BUILTIN_OBJS += $(OUTPUT)builtin-timechart.o | 496 | BUILTIN_OBJS += $(OUTPUT)builtin-timechart.o |
| 487 | BUILTIN_OBJS += $(OUTPUT)builtin-top.o | 497 | BUILTIN_OBJS += $(OUTPUT)builtin-top.o |
| 488 | BUILTIN_OBJS += $(OUTPUT)builtin-trace.o | 498 | BUILTIN_OBJS += $(OUTPUT)builtin-script.o |
| 489 | BUILTIN_OBJS += $(OUTPUT)builtin-probe.o | 499 | BUILTIN_OBJS += $(OUTPUT)builtin-probe.o |
| 490 | BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o | 500 | BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o |
| 491 | BUILTIN_OBJS += $(OUTPUT)builtin-lock.o | 501 | BUILTIN_OBJS += $(OUTPUT)builtin-lock.o |
| @@ -507,7 +517,7 @@ PERFLIBS = $(LIB_FILE) | |||
| 507 | -include config.mak | 517 | -include config.mak |
| 508 | 518 | ||
| 509 | ifndef NO_DWARF | 519 | ifndef NO_DWARF |
| 510 | FLAGS_DWARF=$(ALL_CFLAGS) -I/usr/include/elfutils -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS) | 520 | FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS) |
| 511 | ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y) | 521 | ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y) |
| 512 | msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); | 522 | msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); |
| 513 | NO_DWARF := 1 | 523 | NO_DWARF := 1 |
| @@ -554,7 +564,7 @@ ifndef NO_DWARF | |||
| 554 | ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) | 564 | ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) |
| 555 | msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); | 565 | msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); |
| 556 | else | 566 | else |
| 557 | BASIC_CFLAGS += -I/usr/include/elfutils -DDWARF_SUPPORT | 567 | BASIC_CFLAGS += -DDWARF_SUPPORT |
| 558 | EXTLIBS += -lelf -ldw | 568 | EXTLIBS += -lelf -ldw |
| 559 | LIB_OBJS += $(OUTPUT)util/probe-finder.o | 569 | LIB_OBJS += $(OUTPUT)util/probe-finder.o |
| 560 | endif # PERF_HAVE_DWARF_REGS | 570 | endif # PERF_HAVE_DWARF_REGS |
| @@ -891,13 +901,14 @@ prefix_SQ = $(subst ','\'',$(prefix)) | |||
| 891 | SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) | 901 | SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) |
| 892 | PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) | 902 | PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) |
| 893 | 903 | ||
| 894 | LIBS = $(PERFLIBS) $(EXTLIBS) | 904 | LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive $(EXTLIBS) |
| 895 | 905 | ||
| 896 | BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \ | 906 | BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \ |
| 897 | $(COMPAT_CFLAGS) | 907 | $(COMPAT_CFLAGS) |
| 898 | LIB_OBJS += $(COMPAT_OBJS) | 908 | LIB_OBJS += $(COMPAT_OBJS) |
| 899 | 909 | ||
| 900 | ALL_CFLAGS += $(BASIC_CFLAGS) | 910 | ALL_CFLAGS += $(BASIC_CFLAGS) |
| 911 | ALL_CFLAGS += $(ARCH_CFLAGS) | ||
| 901 | ALL_LDFLAGS += $(BASIC_LDFLAGS) | 912 | ALL_LDFLAGS += $(BASIC_LDFLAGS) |
| 902 | 913 | ||
| 903 | export TAR INSTALL DESTDIR SHELL_PATH | 914 | export TAR INSTALL DESTDIR SHELL_PATH |
diff --git a/tools/perf/bench/mem-memcpy-arch.h b/tools/perf/bench/mem-memcpy-arch.h new file mode 100644 index 000000000000..a72e36cb5394 --- /dev/null +++ b/tools/perf/bench/mem-memcpy-arch.h | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | |||
| 2 | #ifdef ARCH_X86_64 | ||
| 3 | |||
| 4 | #define MEMCPY_FN(fn, name, desc) \ | ||
| 5 | extern void *fn(void *, const void *, size_t); | ||
| 6 | |||
| 7 | #include "mem-memcpy-x86-64-asm-def.h" | ||
| 8 | |||
| 9 | #undef MEMCPY_FN | ||
| 10 | |||
| 11 | #endif | ||
| 12 | |||
diff --git a/tools/perf/bench/mem-memcpy-x86-64-asm-def.h b/tools/perf/bench/mem-memcpy-x86-64-asm-def.h new file mode 100644 index 000000000000..d588b87696fc --- /dev/null +++ b/tools/perf/bench/mem-memcpy-x86-64-asm-def.h | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | |||
| 2 | MEMCPY_FN(__memcpy, | ||
| 3 | "x86-64-unrolled", | ||
| 4 | "unrolled memcpy() in arch/x86/lib/memcpy_64.S") | ||
diff --git a/tools/perf/bench/mem-memcpy-x86-64-asm.S b/tools/perf/bench/mem-memcpy-x86-64-asm.S new file mode 100644 index 000000000000..a57b66e853c2 --- /dev/null +++ b/tools/perf/bench/mem-memcpy-x86-64-asm.S | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | |||
| 2 | #include "../../../arch/x86/lib/memcpy_64.S" | ||
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c index 38dae7465142..db82021f4b91 100644 --- a/tools/perf/bench/mem-memcpy.c +++ b/tools/perf/bench/mem-memcpy.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include "../util/parse-options.h" | 12 | #include "../util/parse-options.h" |
| 13 | #include "../util/header.h" | 13 | #include "../util/header.h" |
| 14 | #include "bench.h" | 14 | #include "bench.h" |
| 15 | #include "mem-memcpy-arch.h" | ||
| 15 | 16 | ||
| 16 | #include <stdio.h> | 17 | #include <stdio.h> |
| 17 | #include <stdlib.h> | 18 | #include <stdlib.h> |
| @@ -23,8 +24,10 @@ | |||
| 23 | 24 | ||
| 24 | static const char *length_str = "1MB"; | 25 | static const char *length_str = "1MB"; |
| 25 | static const char *routine = "default"; | 26 | static const char *routine = "default"; |
| 26 | static bool use_clock = false; | 27 | static bool use_clock; |
| 27 | static int clock_fd; | 28 | static int clock_fd; |
| 29 | static bool only_prefault; | ||
| 30 | static bool no_prefault; | ||
| 28 | 31 | ||
| 29 | static const struct option options[] = { | 32 | static const struct option options[] = { |
| 30 | OPT_STRING('l', "length", &length_str, "1MB", | 33 | OPT_STRING('l', "length", &length_str, "1MB", |
| @@ -34,19 +37,33 @@ static const struct option options[] = { | |||
| 34 | "Specify routine to copy"), | 37 | "Specify routine to copy"), |
| 35 | OPT_BOOLEAN('c', "clock", &use_clock, | 38 | OPT_BOOLEAN('c', "clock", &use_clock, |
| 36 | "Use CPU clock for measuring"), | 39 | "Use CPU clock for measuring"), |
| 40 | OPT_BOOLEAN('o', "only-prefault", &only_prefault, | ||
| 41 | "Show only the result with page faults before memcpy()"), | ||
| 42 | OPT_BOOLEAN('n', "no-prefault", &no_prefault, | ||
| 43 | "Show only the result without page faults before memcpy()"), | ||
| 37 | OPT_END() | 44 | OPT_END() |
| 38 | }; | 45 | }; |
| 39 | 46 | ||
| 47 | typedef void *(*memcpy_t)(void *, const void *, size_t); | ||
| 48 | |||
| 40 | struct routine { | 49 | struct routine { |
| 41 | const char *name; | 50 | const char *name; |
| 42 | const char *desc; | 51 | const char *desc; |
| 43 | void * (*fn)(void *dst, const void *src, size_t len); | 52 | memcpy_t fn; |
| 44 | }; | 53 | }; |
| 45 | 54 | ||
| 46 | struct routine routines[] = { | 55 | struct routine routines[] = { |
| 47 | { "default", | 56 | { "default", |
| 48 | "Default memcpy() provided by glibc", | 57 | "Default memcpy() provided by glibc", |
| 49 | memcpy }, | 58 | memcpy }, |
| 59 | #ifdef ARCH_X86_64 | ||
| 60 | |||
| 61 | #define MEMCPY_FN(fn, name, desc) { name, desc, fn }, | ||
| 62 | #include "mem-memcpy-x86-64-asm-def.h" | ||
| 63 | #undef MEMCPY_FN | ||
| 64 | |||
| 65 | #endif | ||
| 66 | |||
| 50 | { NULL, | 67 | { NULL, |
| 51 | NULL, | 68 | NULL, |
| 52 | NULL } | 69 | NULL } |
| @@ -89,29 +106,98 @@ static double timeval2double(struct timeval *ts) | |||
| 89 | (double)ts->tv_usec / (double)1000000; | 106 | (double)ts->tv_usec / (double)1000000; |
| 90 | } | 107 | } |
| 91 | 108 | ||
| 109 | static void alloc_mem(void **dst, void **src, size_t length) | ||
| 110 | { | ||
| 111 | *dst = zalloc(length); | ||
| 112 | if (!dst) | ||
| 113 | die("memory allocation failed - maybe length is too large?\n"); | ||
| 114 | |||
| 115 | *src = zalloc(length); | ||
| 116 | if (!src) | ||
| 117 | die("memory allocation failed - maybe length is too large?\n"); | ||
| 118 | } | ||
| 119 | |||
| 120 | static u64 do_memcpy_clock(memcpy_t fn, size_t len, bool prefault) | ||
| 121 | { | ||
| 122 | u64 clock_start = 0ULL, clock_end = 0ULL; | ||
| 123 | void *src = NULL, *dst = NULL; | ||
| 124 | |||
| 125 | alloc_mem(&src, &dst, len); | ||
| 126 | |||
| 127 | if (prefault) | ||
| 128 | fn(dst, src, len); | ||
| 129 | |||
| 130 | clock_start = get_clock(); | ||
| 131 | fn(dst, src, len); | ||
| 132 | clock_end = get_clock(); | ||
| 133 | |||
| 134 | free(src); | ||
| 135 | free(dst); | ||
| 136 | return clock_end - clock_start; | ||
| 137 | } | ||
| 138 | |||
| 139 | static double do_memcpy_gettimeofday(memcpy_t fn, size_t len, bool prefault) | ||
| 140 | { | ||
| 141 | struct timeval tv_start, tv_end, tv_diff; | ||
| 142 | void *src = NULL, *dst = NULL; | ||
| 143 | |||
| 144 | alloc_mem(&src, &dst, len); | ||
| 145 | |||
| 146 | if (prefault) | ||
| 147 | fn(dst, src, len); | ||
| 148 | |||
| 149 | BUG_ON(gettimeofday(&tv_start, NULL)); | ||
| 150 | fn(dst, src, len); | ||
| 151 | BUG_ON(gettimeofday(&tv_end, NULL)); | ||
| 152 | |||
| 153 | timersub(&tv_end, &tv_start, &tv_diff); | ||
| 154 | |||
| 155 | free(src); | ||
| 156 | free(dst); | ||
| 157 | return (double)((double)len / timeval2double(&tv_diff)); | ||
| 158 | } | ||
| 159 | |||
| 160 | #define pf (no_prefault ? 0 : 1) | ||
| 161 | |||
| 162 | #define print_bps(x) do { \ | ||
| 163 | if (x < K) \ | ||
| 164 | printf(" %14lf B/Sec", x); \ | ||
| 165 | else if (x < K * K) \ | ||
| 166 | printf(" %14lfd KB/Sec", x / K); \ | ||
| 167 | else if (x < K * K * K) \ | ||
| 168 | printf(" %14lf MB/Sec", x / K / K); \ | ||
| 169 | else \ | ||
| 170 | printf(" %14lf GB/Sec", x / K / K / K); \ | ||
| 171 | } while (0) | ||
| 172 | |||
| 92 | int bench_mem_memcpy(int argc, const char **argv, | 173 | int bench_mem_memcpy(int argc, const char **argv, |
| 93 | const char *prefix __used) | 174 | const char *prefix __used) |
| 94 | { | 175 | { |
| 95 | int i; | 176 | int i; |
| 96 | void *dst, *src; | 177 | size_t len; |
| 97 | size_t length; | 178 | double result_bps[2]; |
| 98 | double bps = 0.0; | 179 | u64 result_clock[2]; |
| 99 | struct timeval tv_start, tv_end, tv_diff; | ||
| 100 | u64 clock_start, clock_end, clock_diff; | ||
| 101 | 180 | ||
| 102 | clock_start = clock_end = clock_diff = 0ULL; | ||
| 103 | argc = parse_options(argc, argv, options, | 181 | argc = parse_options(argc, argv, options, |
| 104 | bench_mem_memcpy_usage, 0); | 182 | bench_mem_memcpy_usage, 0); |
| 105 | 183 | ||
| 106 | tv_diff.tv_sec = 0; | 184 | if (use_clock) |
| 107 | tv_diff.tv_usec = 0; | 185 | init_clock(); |
| 108 | length = (size_t)perf_atoll((char *)length_str); | 186 | |
| 187 | len = (size_t)perf_atoll((char *)length_str); | ||
| 109 | 188 | ||
| 110 | if ((s64)length <= 0) { | 189 | result_clock[0] = result_clock[1] = 0ULL; |
| 190 | result_bps[0] = result_bps[1] = 0.0; | ||
| 191 | |||
| 192 | if ((s64)len <= 0) { | ||
| 111 | fprintf(stderr, "Invalid length:%s\n", length_str); | 193 | fprintf(stderr, "Invalid length:%s\n", length_str); |
| 112 | return 1; | 194 | return 1; |
| 113 | } | 195 | } |
| 114 | 196 | ||
| 197 | /* same to without specifying either of prefault and no-prefault */ | ||
| 198 | if (only_prefault && no_prefault) | ||
| 199 | only_prefault = no_prefault = false; | ||
| 200 | |||
| 115 | for (i = 0; routines[i].name; i++) { | 201 | for (i = 0; routines[i].name; i++) { |
| 116 | if (!strcmp(routines[i].name, routine)) | 202 | if (!strcmp(routines[i].name, routine)) |
| 117 | break; | 203 | break; |
| @@ -126,61 +212,80 @@ int bench_mem_memcpy(int argc, const char **argv, | |||
| 126 | return 1; | 212 | return 1; |
| 127 | } | 213 | } |
| 128 | 214 | ||
| 129 | dst = zalloc(length); | 215 | if (bench_format == BENCH_FORMAT_DEFAULT) |
| 130 | if (!dst) | 216 | printf("# Copying %s Bytes ...\n\n", length_str); |
| 131 | die("memory allocation failed - maybe length is too large?\n"); | ||
| 132 | |||
| 133 | src = zalloc(length); | ||
| 134 | if (!src) | ||
| 135 | die("memory allocation failed - maybe length is too large?\n"); | ||
| 136 | |||
| 137 | if (bench_format == BENCH_FORMAT_DEFAULT) { | ||
| 138 | printf("# Copying %s Bytes from %p to %p ...\n\n", | ||
| 139 | length_str, src, dst); | ||
| 140 | } | ||
| 141 | |||
| 142 | if (use_clock) { | ||
| 143 | init_clock(); | ||
| 144 | clock_start = get_clock(); | ||
| 145 | } else { | ||
| 146 | BUG_ON(gettimeofday(&tv_start, NULL)); | ||
| 147 | } | ||
| 148 | |||
| 149 | routines[i].fn(dst, src, length); | ||
| 150 | 217 | ||
| 151 | if (use_clock) { | 218 | if (!only_prefault && !no_prefault) { |
| 152 | clock_end = get_clock(); | 219 | /* show both of results */ |
| 153 | clock_diff = clock_end - clock_start; | 220 | if (use_clock) { |
| 221 | result_clock[0] = | ||
| 222 | do_memcpy_clock(routines[i].fn, len, false); | ||
| 223 | result_clock[1] = | ||
| 224 | do_memcpy_clock(routines[i].fn, len, true); | ||
| 225 | } else { | ||
| 226 | result_bps[0] = | ||
| 227 | do_memcpy_gettimeofday(routines[i].fn, | ||
| 228 | len, false); | ||
| 229 | result_bps[1] = | ||
| 230 | do_memcpy_gettimeofday(routines[i].fn, | ||
| 231 | len, true); | ||
| 232 | } | ||
| 154 | } else { | 233 | } else { |
| 155 | BUG_ON(gettimeofday(&tv_end, NULL)); | 234 | if (use_clock) { |
| 156 | timersub(&tv_end, &tv_start, &tv_diff); | 235 | result_clock[pf] = |
| 157 | bps = (double)((double)length / timeval2double(&tv_diff)); | 236 | do_memcpy_clock(routines[i].fn, |
| 237 | len, only_prefault); | ||
| 238 | } else { | ||
| 239 | result_bps[pf] = | ||
| 240 | do_memcpy_gettimeofday(routines[i].fn, | ||
| 241 | len, only_prefault); | ||
| 242 | } | ||
| 158 | } | 243 | } |
| 159 | 244 | ||
| 160 | switch (bench_format) { | 245 | switch (bench_format) { |
| 161 | case BENCH_FORMAT_DEFAULT: | 246 | case BENCH_FORMAT_DEFAULT: |
| 162 | if (use_clock) { | 247 | if (!only_prefault && !no_prefault) { |
| 163 | printf(" %14lf Clock/Byte\n", | 248 | if (use_clock) { |
| 164 | (double)clock_diff / (double)length); | 249 | printf(" %14lf Clock/Byte\n", |
| 165 | } else { | 250 | (double)result_clock[0] |
| 166 | if (bps < K) | 251 | / (double)len); |
| 167 | printf(" %14lf B/Sec\n", bps); | 252 | printf(" %14lf Clock/Byte (with prefault)\n", |
| 168 | else if (bps < K * K) | 253 | (double)result_clock[1] |
| 169 | printf(" %14lfd KB/Sec\n", bps / 1024); | 254 | / (double)len); |
| 170 | else if (bps < K * K * K) | 255 | } else { |
| 171 | printf(" %14lf MB/Sec\n", bps / 1024 / 1024); | 256 | print_bps(result_bps[0]); |
| 172 | else { | 257 | printf("\n"); |
| 173 | printf(" %14lf GB/Sec\n", | 258 | print_bps(result_bps[1]); |
| 174 | bps / 1024 / 1024 / 1024); | 259 | printf(" (with prefault)\n"); |
| 175 | } | 260 | } |
| 261 | } else { | ||
| 262 | if (use_clock) { | ||
| 263 | printf(" %14lf Clock/Byte", | ||
| 264 | (double)result_clock[pf] | ||
| 265 | / (double)len); | ||
| 266 | } else | ||
| 267 | print_bps(result_bps[pf]); | ||
| 268 | |||
| 269 | printf("%s\n", only_prefault ? " (with prefault)" : ""); | ||
| 176 | } | 270 | } |
| 177 | break; | 271 | break; |
| 178 | case BENCH_FORMAT_SIMPLE: | 272 | case BENCH_FORMAT_SIMPLE: |
| 179 | if (use_clock) { | 273 | if (!only_prefault && !no_prefault) { |
| 180 | printf("%14lf\n", | 274 | if (use_clock) { |
| 181 | (double)clock_diff / (double)length); | 275 | printf("%lf %lf\n", |
| 182 | } else | 276 | (double)result_clock[0] / (double)len, |
| 183 | printf("%lf\n", bps); | 277 | (double)result_clock[1] / (double)len); |
| 278 | } else { | ||
| 279 | printf("%lf %lf\n", | ||
| 280 | result_bps[0], result_bps[1]); | ||
| 281 | } | ||
| 282 | } else { | ||
| 283 | if (use_clock) { | ||
| 284 | printf("%lf\n", (double)result_clock[pf] | ||
| 285 | / (double)len); | ||
| 286 | } else | ||
| 287 | printf("%lf\n", result_bps[pf]); | ||
| 288 | } | ||
| 184 | break; | 289 | break; |
| 185 | default: | 290 | default: |
| 186 | /* reaching this means there's some disaster: */ | 291 | /* reaching this means there's some disaster: */ |
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 6d5604d8df95..569a2761b90a 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
| @@ -58,12 +58,12 @@ static int hists__add_entry(struct hists *self, struct addr_location *al) | |||
| 58 | return hist_entry__inc_addr_samples(he, al->addr); | 58 | return hist_entry__inc_addr_samples(he, al->addr); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | static int process_sample_event(event_t *event, struct perf_session *session) | 61 | static int process_sample_event(event_t *event, struct sample_data *sample, |
| 62 | struct perf_session *session) | ||
| 62 | { | 63 | { |
| 63 | struct addr_location al; | 64 | struct addr_location al; |
| 64 | struct sample_data data; | ||
| 65 | 65 | ||
| 66 | if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) { | 66 | if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) { |
| 67 | pr_warning("problem processing %d event, skipping it.\n", | 67 | pr_warning("problem processing %d event, skipping it.\n", |
| 68 | event->header.type); | 68 | event->header.type); |
| 69 | return -1; | 69 | return -1; |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index fca1d4402910..5e1a043aae03 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
| @@ -30,12 +30,13 @@ static int hists__add_entry(struct hists *self, | |||
| 30 | return -ENOMEM; | 30 | return -ENOMEM; |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | static int diff__process_sample_event(event_t *event, struct perf_session *session) | 33 | static int diff__process_sample_event(event_t *event, |
| 34 | struct sample_data *sample, | ||
| 35 | struct perf_session *session) | ||
| 34 | { | 36 | { |
| 35 | struct addr_location al; | 37 | struct addr_location al; |
| 36 | struct sample_data data = { .period = 1, }; | ||
| 37 | 38 | ||
| 38 | if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) { | 39 | if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) { |
| 39 | pr_warning("problem processing %d event, skipping it.\n", | 40 | pr_warning("problem processing %d event, skipping it.\n", |
| 40 | event->header.type); | 41 | event->header.type); |
| 41 | return -1; | 42 | return -1; |
| @@ -44,12 +45,12 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi | |||
| 44 | if (al.filtered || al.sym == NULL) | 45 | if (al.filtered || al.sym == NULL) |
| 45 | return 0; | 46 | return 0; |
| 46 | 47 | ||
| 47 | if (hists__add_entry(&session->hists, &al, data.period)) { | 48 | if (hists__add_entry(&session->hists, &al, sample->period)) { |
| 48 | pr_warning("problem incrementing symbol period, skipping event\n"); | 49 | pr_warning("problem incrementing symbol period, skipping event\n"); |
| 49 | return -1; | 50 | return -1; |
| 50 | } | 51 | } |
| 51 | 52 | ||
| 52 | session->hists.stats.total_period += data.period; | 53 | session->hists.stats.total_period += sample->period; |
| 53 | return 0; | 54 | return 0; |
| 54 | } | 55 | } |
| 55 | 56 | ||
| @@ -173,7 +174,7 @@ static const char * const diff_usage[] = { | |||
| 173 | static const struct option options[] = { | 174 | static const struct option options[] = { |
| 174 | OPT_INCR('v', "verbose", &verbose, | 175 | OPT_INCR('v', "verbose", &verbose, |
| 175 | "be more verbose (show symbol address, etc)"), | 176 | "be more verbose (show symbol address, etc)"), |
| 176 | OPT_BOOLEAN('m', "displacement", &show_displacement, | 177 | OPT_BOOLEAN('M', "displacement", &show_displacement, |
| 177 | "Show position displacement relative to baseline"), | 178 | "Show position displacement relative to baseline"), |
| 178 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, | 179 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, |
| 179 | "dump raw trace in ASCII"), | 180 | "dump raw trace in ASCII"), |
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 8e3e47b064ce..4b66b8579410 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c | |||
| @@ -16,8 +16,8 @@ | |||
| 16 | static char const *input_name = "-"; | 16 | static char const *input_name = "-"; |
| 17 | static bool inject_build_ids; | 17 | static bool inject_build_ids; |
| 18 | 18 | ||
| 19 | static int event__repipe(event_t *event __used, | 19 | static int event__repipe_synth(event_t *event, |
| 20 | struct perf_session *session __used) | 20 | struct perf_session *session __used) |
| 21 | { | 21 | { |
| 22 | uint32_t size; | 22 | uint32_t size; |
| 23 | void *buf = event; | 23 | void *buf = event; |
| @@ -36,22 +36,30 @@ static int event__repipe(event_t *event __used, | |||
| 36 | return 0; | 36 | return 0; |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | static int event__repipe_mmap(event_t *self, struct perf_session *session) | 39 | static int event__repipe(event_t *event, struct sample_data *sample __used, |
| 40 | struct perf_session *session) | ||
| 41 | { | ||
| 42 | return event__repipe_synth(event, session); | ||
| 43 | } | ||
| 44 | |||
| 45 | static int event__repipe_mmap(event_t *self, struct sample_data *sample, | ||
| 46 | struct perf_session *session) | ||
| 40 | { | 47 | { |
| 41 | int err; | 48 | int err; |
| 42 | 49 | ||
| 43 | err = event__process_mmap(self, session); | 50 | err = event__process_mmap(self, sample, session); |
| 44 | event__repipe(self, session); | 51 | event__repipe(self, sample, session); |
| 45 | 52 | ||
| 46 | return err; | 53 | return err; |
| 47 | } | 54 | } |
| 48 | 55 | ||
| 49 | static int event__repipe_task(event_t *self, struct perf_session *session) | 56 | static int event__repipe_task(event_t *self, struct sample_data *sample, |
| 57 | struct perf_session *session) | ||
| 50 | { | 58 | { |
| 51 | int err; | 59 | int err; |
| 52 | 60 | ||
| 53 | err = event__process_task(self, session); | 61 | err = event__process_task(self, sample, session); |
| 54 | event__repipe(self, session); | 62 | event__repipe(self, sample, session); |
| 55 | 63 | ||
| 56 | return err; | 64 | return err; |
| 57 | } | 65 | } |
| @@ -61,7 +69,7 @@ static int event__repipe_tracing_data(event_t *self, | |||
| 61 | { | 69 | { |
| 62 | int err; | 70 | int err; |
| 63 | 71 | ||
| 64 | event__repipe(self, session); | 72 | event__repipe_synth(self, session); |
| 65 | err = event__process_tracing_data(self, session); | 73 | err = event__process_tracing_data(self, session); |
| 66 | 74 | ||
| 67 | return err; | 75 | return err; |
| @@ -111,7 +119,8 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session) | |||
| 111 | return 0; | 119 | return 0; |
| 112 | } | 120 | } |
| 113 | 121 | ||
| 114 | static int event__inject_buildid(event_t *event, struct perf_session *session) | 122 | static int event__inject_buildid(event_t *event, struct sample_data *sample, |
| 123 | struct perf_session *session) | ||
| 115 | { | 124 | { |
| 116 | struct addr_location al; | 125 | struct addr_location al; |
| 117 | struct thread *thread; | 126 | struct thread *thread; |
| @@ -146,7 +155,7 @@ static int event__inject_buildid(event_t *event, struct perf_session *session) | |||
| 146 | } | 155 | } |
| 147 | 156 | ||
| 148 | repipe: | 157 | repipe: |
| 149 | event__repipe(event, session); | 158 | event__repipe(event, sample, session); |
| 150 | return 0; | 159 | return 0; |
| 151 | } | 160 | } |
| 152 | 161 | ||
| @@ -160,10 +169,10 @@ struct perf_event_ops inject_ops = { | |||
| 160 | .read = event__repipe, | 169 | .read = event__repipe, |
| 161 | .throttle = event__repipe, | 170 | .throttle = event__repipe, |
| 162 | .unthrottle = event__repipe, | 171 | .unthrottle = event__repipe, |
| 163 | .attr = event__repipe, | 172 | .attr = event__repipe_synth, |
| 164 | .event_type = event__repipe, | 173 | .event_type = event__repipe_synth, |
| 165 | .tracing_data = event__repipe, | 174 | .tracing_data = event__repipe_synth, |
| 166 | .build_id = event__repipe, | 175 | .build_id = event__repipe_synth, |
| 167 | }; | 176 | }; |
| 168 | 177 | ||
| 169 | extern volatile int session_done; | 178 | extern volatile int session_done; |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 31f60a2535e0..c9620ff6496f 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
| @@ -304,22 +304,11 @@ process_raw_event(event_t *raw_event __used, void *data, | |||
| 304 | } | 304 | } |
| 305 | } | 305 | } |
| 306 | 306 | ||
| 307 | static int process_sample_event(event_t *event, struct perf_session *session) | 307 | static int process_sample_event(event_t *event, struct sample_data *sample, |
| 308 | struct perf_session *session) | ||
| 308 | { | 309 | { |
| 309 | struct sample_data data; | 310 | struct thread *thread = perf_session__findnew(session, event->ip.pid); |
| 310 | struct thread *thread; | ||
| 311 | 311 | ||
| 312 | memset(&data, 0, sizeof(data)); | ||
| 313 | data.time = -1; | ||
| 314 | data.cpu = -1; | ||
| 315 | data.period = 1; | ||
| 316 | |||
| 317 | event__parse_sample(event, session->sample_type, &data); | ||
| 318 | |||
| 319 | dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc, | ||
| 320 | data.pid, data.tid, data.ip, data.period); | ||
| 321 | |||
| 322 | thread = perf_session__findnew(session, event->ip.pid); | ||
| 323 | if (thread == NULL) { | 312 | if (thread == NULL) { |
| 324 | pr_debug("problem processing %d event, skipping it.\n", | 313 | pr_debug("problem processing %d event, skipping it.\n", |
| 325 | event->header.type); | 314 | event->header.type); |
| @@ -328,8 +317,8 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
| 328 | 317 | ||
| 329 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | 318 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); |
| 330 | 319 | ||
| 331 | process_raw_event(event, data.raw_data, data.cpu, | 320 | process_raw_event(event, sample->raw_data, sample->cpu, |
| 332 | data.time, thread); | 321 | sample->time, thread); |
| 333 | 322 | ||
| 334 | return 0; | 323 | return 0; |
| 335 | } | 324 | } |
| @@ -747,6 +736,9 @@ static int __cmd_record(int argc, const char **argv) | |||
| 747 | rec_argc = ARRAY_SIZE(record_args) + argc - 1; | 736 | rec_argc = ARRAY_SIZE(record_args) + argc - 1; |
| 748 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 737 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
| 749 | 738 | ||
| 739 | if (rec_argv == NULL) | ||
| 740 | return -ENOMEM; | ||
| 741 | |||
| 750 | for (i = 0; i < ARRAY_SIZE(record_args); i++) | 742 | for (i = 0; i < ARRAY_SIZE(record_args); i++) |
| 751 | rec_argv[i] = strdup(record_args[i]); | 743 | rec_argv[i] = strdup(record_args[i]); |
| 752 | 744 | ||
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 821c1586a22b..b41b4492b1cc 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c | |||
| @@ -834,22 +834,18 @@ static void dump_info(void) | |||
| 834 | die("Unknown type of information\n"); | 834 | die("Unknown type of information\n"); |
| 835 | } | 835 | } |
| 836 | 836 | ||
| 837 | static int process_sample_event(event_t *self, struct perf_session *s) | 837 | static int process_sample_event(event_t *self, struct sample_data *sample, |
| 838 | struct perf_session *s) | ||
| 838 | { | 839 | { |
| 839 | struct sample_data data; | 840 | struct thread *thread = perf_session__findnew(s, sample->tid); |
| 840 | struct thread *thread; | ||
| 841 | 841 | ||
| 842 | bzero(&data, sizeof(data)); | ||
| 843 | event__parse_sample(self, s->sample_type, &data); | ||
| 844 | |||
| 845 | thread = perf_session__findnew(s, data.tid); | ||
| 846 | if (thread == NULL) { | 842 | if (thread == NULL) { |
| 847 | pr_debug("problem processing %d event, skipping it.\n", | 843 | pr_debug("problem processing %d event, skipping it.\n", |
| 848 | self->header.type); | 844 | self->header.type); |
| 849 | return -1; | 845 | return -1; |
| 850 | } | 846 | } |
| 851 | 847 | ||
| 852 | process_raw_event(data.raw_data, data.cpu, data.time, thread); | 848 | process_raw_event(sample->raw_data, sample->cpu, sample->time, thread); |
| 853 | 849 | ||
| 854 | return 0; | 850 | return 0; |
| 855 | } | 851 | } |
| @@ -947,6 +943,9 @@ static int __cmd_record(int argc, const char **argv) | |||
| 947 | rec_argc = ARRAY_SIZE(record_args) + argc - 1; | 943 | rec_argc = ARRAY_SIZE(record_args) + argc - 1; |
| 948 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 944 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
| 949 | 945 | ||
| 946 | if (rec_argv == NULL) | ||
| 947 | return -ENOMEM; | ||
| 948 | |||
| 950 | for (i = 0; i < ARRAY_SIZE(record_args); i++) | 949 | for (i = 0; i < ARRAY_SIZE(record_args); i++) |
| 951 | rec_argv[i] = strdup(record_args[i]); | 950 | rec_argv[i] = strdup(record_args[i]); |
| 952 | 951 | ||
| @@ -982,9 +981,9 @@ int cmd_lock(int argc, const char **argv, const char *prefix __used) | |||
| 982 | usage_with_options(report_usage, report_options); | 981 | usage_with_options(report_usage, report_options); |
| 983 | } | 982 | } |
| 984 | __cmd_report(); | 983 | __cmd_report(); |
| 985 | } else if (!strcmp(argv[0], "trace")) { | 984 | } else if (!strcmp(argv[0], "script")) { |
| 986 | /* Aliased to 'perf trace' */ | 985 | /* Aliased to 'perf script' */ |
| 987 | return cmd_trace(argc, argv, prefix); | 986 | return cmd_script(argc, argv, prefix); |
| 988 | } else if (!strcmp(argv[0], "info")) { | 987 | } else if (!strcmp(argv[0], "info")) { |
| 989 | if (argc) { | 988 | if (argc) { |
| 990 | argc = parse_options(argc, argv, | 989 | argc = parse_options(argc, argv, |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 564491fa18b2..e9be6ae87a27 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
| @@ -36,6 +36,7 @@ static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; | |||
| 36 | 36 | ||
| 37 | static u64 user_interval = ULLONG_MAX; | 37 | static u64 user_interval = ULLONG_MAX; |
| 38 | static u64 default_interval = 0; | 38 | static u64 default_interval = 0; |
| 39 | static u64 sample_type; | ||
| 39 | 40 | ||
| 40 | static int nr_cpus = 0; | 41 | static int nr_cpus = 0; |
| 41 | static unsigned int page_size; | 42 | static unsigned int page_size; |
| @@ -48,6 +49,7 @@ static const char *output_name = "perf.data"; | |||
| 48 | static int group = 0; | 49 | static int group = 0; |
| 49 | static int realtime_prio = 0; | 50 | static int realtime_prio = 0; |
| 50 | static bool raw_samples = false; | 51 | static bool raw_samples = false; |
| 52 | static bool sample_id_all_avail = true; | ||
| 51 | static bool system_wide = false; | 53 | static bool system_wide = false; |
| 52 | static pid_t target_pid = -1; | 54 | static pid_t target_pid = -1; |
| 53 | static pid_t target_tid = -1; | 55 | static pid_t target_tid = -1; |
| @@ -60,7 +62,9 @@ static bool call_graph = false; | |||
| 60 | static bool inherit_stat = false; | 62 | static bool inherit_stat = false; |
| 61 | static bool no_samples = false; | 63 | static bool no_samples = false; |
| 62 | static bool sample_address = false; | 64 | static bool sample_address = false; |
| 65 | static bool sample_time = false; | ||
| 63 | static bool no_buildid = false; | 66 | static bool no_buildid = false; |
| 67 | static bool no_buildid_cache = false; | ||
| 64 | 68 | ||
| 65 | static long samples = 0; | 69 | static long samples = 0; |
| 66 | static u64 bytes_written = 0; | 70 | static u64 bytes_written = 0; |
| @@ -128,6 +132,7 @@ static void write_output(void *buf, size_t size) | |||
| 128 | } | 132 | } |
| 129 | 133 | ||
| 130 | static int process_synthesized_event(event_t *event, | 134 | static int process_synthesized_event(event_t *event, |
| 135 | struct sample_data *sample __used, | ||
| 131 | struct perf_session *self __used) | 136 | struct perf_session *self __used) |
| 132 | { | 137 | { |
| 133 | write_output(event, event->header.size); | 138 | write_output(event, event->header.size); |
| @@ -280,12 +285,18 @@ static void create_counter(int counter, int cpu) | |||
| 280 | if (system_wide) | 285 | if (system_wide) |
| 281 | attr->sample_type |= PERF_SAMPLE_CPU; | 286 | attr->sample_type |= PERF_SAMPLE_CPU; |
| 282 | 287 | ||
| 288 | if (sample_time) | ||
| 289 | attr->sample_type |= PERF_SAMPLE_TIME; | ||
| 290 | |||
| 283 | if (raw_samples) { | 291 | if (raw_samples) { |
| 284 | attr->sample_type |= PERF_SAMPLE_TIME; | 292 | attr->sample_type |= PERF_SAMPLE_TIME; |
| 285 | attr->sample_type |= PERF_SAMPLE_RAW; | 293 | attr->sample_type |= PERF_SAMPLE_RAW; |
| 286 | attr->sample_type |= PERF_SAMPLE_CPU; | 294 | attr->sample_type |= PERF_SAMPLE_CPU; |
| 287 | } | 295 | } |
| 288 | 296 | ||
| 297 | if (!sample_type) | ||
| 298 | sample_type = attr->sample_type; | ||
| 299 | |||
| 289 | attr->mmap = track; | 300 | attr->mmap = track; |
| 290 | attr->comm = track; | 301 | attr->comm = track; |
| 291 | attr->inherit = !no_inherit; | 302 | attr->inherit = !no_inherit; |
| @@ -293,6 +304,8 @@ static void create_counter(int counter, int cpu) | |||
| 293 | attr->disabled = 1; | 304 | attr->disabled = 1; |
| 294 | attr->enable_on_exec = 1; | 305 | attr->enable_on_exec = 1; |
| 295 | } | 306 | } |
| 307 | retry_sample_id: | ||
| 308 | attr->sample_id_all = sample_id_all_avail ? 1 : 0; | ||
| 296 | 309 | ||
| 297 | for (thread_index = 0; thread_index < thread_num; thread_index++) { | 310 | for (thread_index = 0; thread_index < thread_num; thread_index++) { |
| 298 | try_again: | 311 | try_again: |
| @@ -309,6 +322,12 @@ try_again: | |||
| 309 | else if (err == ENODEV && cpu_list) { | 322 | else if (err == ENODEV && cpu_list) { |
| 310 | die("No such device - did you specify" | 323 | die("No such device - did you specify" |
| 311 | " an out-of-range profile CPU?\n"); | 324 | " an out-of-range profile CPU?\n"); |
| 325 | } else if (err == EINVAL && sample_id_all_avail) { | ||
| 326 | /* | ||
| 327 | * Old kernel, no attr->sample_id_type_all field | ||
| 328 | */ | ||
| 329 | sample_id_all_avail = false; | ||
| 330 | goto retry_sample_id; | ||
| 312 | } | 331 | } |
| 313 | 332 | ||
| 314 | /* | 333 | /* |
| @@ -326,7 +345,7 @@ try_again: | |||
| 326 | goto try_again; | 345 | goto try_again; |
| 327 | } | 346 | } |
| 328 | printf("\n"); | 347 | printf("\n"); |
| 329 | error("perfcounter syscall returned with %d (%s)\n", | 348 | error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", |
| 330 | fd[nr_cpu][counter][thread_index], strerror(err)); | 349 | fd[nr_cpu][counter][thread_index], strerror(err)); |
| 331 | 350 | ||
| 332 | #if defined(__i386__) || defined(__x86_64__) | 351 | #if defined(__i386__) || defined(__x86_64__) |
| @@ -437,7 +456,8 @@ static void atexit_header(void) | |||
| 437 | if (!pipe_output) { | 456 | if (!pipe_output) { |
| 438 | session->header.data_size += bytes_written; | 457 | session->header.data_size += bytes_written; |
| 439 | 458 | ||
| 440 | process_buildids(); | 459 | if (!no_buildid) |
| 460 | process_buildids(); | ||
| 441 | perf_header__write(&session->header, output, true); | 461 | perf_header__write(&session->header, output, true); |
| 442 | perf_session__delete(session); | 462 | perf_session__delete(session); |
| 443 | symbol__exit(); | 463 | symbol__exit(); |
| @@ -558,6 +578,9 @@ static int __cmd_record(int argc, const char **argv) | |||
| 558 | return -1; | 578 | return -1; |
| 559 | } | 579 | } |
| 560 | 580 | ||
| 581 | if (!no_buildid) | ||
| 582 | perf_header__set_feat(&session->header, HEADER_BUILD_ID); | ||
| 583 | |||
| 561 | if (!file_new) { | 584 | if (!file_new) { |
| 562 | err = perf_header__read(session, output); | 585 | err = perf_header__read(session, output); |
| 563 | if (err < 0) | 586 | if (err < 0) |
| @@ -639,6 +662,8 @@ static int __cmd_record(int argc, const char **argv) | |||
| 639 | open_counters(cpumap[i]); | 662 | open_counters(cpumap[i]); |
| 640 | } | 663 | } |
| 641 | 664 | ||
| 665 | perf_session__set_sample_type(session, sample_type); | ||
| 666 | |||
| 642 | if (pipe_output) { | 667 | if (pipe_output) { |
| 643 | err = perf_header__write_pipe(output); | 668 | err = perf_header__write_pipe(output); |
| 644 | if (err < 0) | 669 | if (err < 0) |
| @@ -651,6 +676,8 @@ static int __cmd_record(int argc, const char **argv) | |||
| 651 | 676 | ||
| 652 | post_processing_offset = lseek(output, 0, SEEK_CUR); | 677 | post_processing_offset = lseek(output, 0, SEEK_CUR); |
| 653 | 678 | ||
| 679 | perf_session__set_sample_id_all(session, sample_id_all_avail); | ||
| 680 | |||
| 654 | if (pipe_output) { | 681 | if (pipe_output) { |
| 655 | err = event__synthesize_attrs(&session->header, | 682 | err = event__synthesize_attrs(&session->header, |
| 656 | process_synthesized_event, | 683 | process_synthesized_event, |
| @@ -831,10 +858,13 @@ const struct option record_options[] = { | |||
| 831 | "per thread counts"), | 858 | "per thread counts"), |
| 832 | OPT_BOOLEAN('d', "data", &sample_address, | 859 | OPT_BOOLEAN('d', "data", &sample_address, |
| 833 | "Sample addresses"), | 860 | "Sample addresses"), |
| 861 | OPT_BOOLEAN('T', "timestamp", &sample_time, "Sample timestamps"), | ||
| 834 | OPT_BOOLEAN('n', "no-samples", &no_samples, | 862 | OPT_BOOLEAN('n', "no-samples", &no_samples, |
| 835 | "don't sample"), | 863 | "don't sample"), |
| 836 | OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid, | 864 | OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache, |
| 837 | "do not update the buildid cache"), | 865 | "do not update the buildid cache"), |
| 866 | OPT_BOOLEAN('B', "no-buildid", &no_buildid, | ||
| 867 | "do not collect buildids in perf.data"), | ||
| 838 | OPT_END() | 868 | OPT_END() |
| 839 | }; | 869 | }; |
| 840 | 870 | ||
| @@ -859,7 +889,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
| 859 | } | 889 | } |
| 860 | 890 | ||
| 861 | symbol__init(); | 891 | symbol__init(); |
| 862 | if (no_buildid) | 892 | |
| 893 | if (no_buildid_cache || no_buildid) | ||
| 863 | disable_buildid_cache(); | 894 | disable_buildid_cache(); |
| 864 | 895 | ||
| 865 | if (!nr_counters) { | 896 | if (!nr_counters) { |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 5de405d45230..b6a2a899aa8f 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -150,13 +150,13 @@ static int add_event_total(struct perf_session *session, | |||
| 150 | return 0; | 150 | return 0; |
| 151 | } | 151 | } |
| 152 | 152 | ||
| 153 | static int process_sample_event(event_t *event, struct perf_session *session) | 153 | static int process_sample_event(event_t *event, struct sample_data *sample, |
| 154 | struct perf_session *session) | ||
| 154 | { | 155 | { |
| 155 | struct sample_data data = { .period = 1, }; | ||
| 156 | struct addr_location al; | 156 | struct addr_location al; |
| 157 | struct perf_event_attr *attr; | 157 | struct perf_event_attr *attr; |
| 158 | 158 | ||
| 159 | if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) { | 159 | if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) { |
| 160 | fprintf(stderr, "problem processing %d event, skipping it.\n", | 160 | fprintf(stderr, "problem processing %d event, skipping it.\n", |
| 161 | event->header.type); | 161 | event->header.type); |
| 162 | return -1; | 162 | return -1; |
| @@ -165,14 +165,14 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
| 165 | if (al.filtered || (hide_unresolved && al.sym == NULL)) | 165 | if (al.filtered || (hide_unresolved && al.sym == NULL)) |
| 166 | return 0; | 166 | return 0; |
| 167 | 167 | ||
| 168 | if (perf_session__add_hist_entry(session, &al, &data)) { | 168 | if (perf_session__add_hist_entry(session, &al, sample)) { |
| 169 | pr_debug("problem incrementing symbol period, skipping event\n"); | 169 | pr_debug("problem incrementing symbol period, skipping event\n"); |
| 170 | return -1; | 170 | return -1; |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | attr = perf_header__find_attr(data.id, &session->header); | 173 | attr = perf_header__find_attr(sample->id, &session->header); |
| 174 | 174 | ||
| 175 | if (add_event_total(session, &data, attr)) { | 175 | if (add_event_total(session, sample, attr)) { |
| 176 | pr_debug("problem adding event period\n"); | 176 | pr_debug("problem adding event period\n"); |
| 177 | return -1; | 177 | return -1; |
| 178 | } | 178 | } |
| @@ -180,7 +180,8 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
| 180 | return 0; | 180 | return 0; |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | static int process_read_event(event_t *event, struct perf_session *session __used) | 183 | static int process_read_event(event_t *event, struct sample_data *sample __used, |
| 184 | struct perf_session *session __used) | ||
| 184 | { | 185 | { |
| 185 | struct perf_event_attr *attr; | 186 | struct perf_event_attr *attr; |
| 186 | 187 | ||
| @@ -442,6 +443,8 @@ static const struct option options[] = { | |||
| 442 | "dump raw trace in ASCII"), | 443 | "dump raw trace in ASCII"), |
| 443 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 444 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
| 444 | "file", "vmlinux pathname"), | 445 | "file", "vmlinux pathname"), |
| 446 | OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, | ||
| 447 | "file", "kallsyms pathname"), | ||
| 445 | OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), | 448 | OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), |
| 446 | OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, | 449 | OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, |
| 447 | "load module symbols - WARNING: use only with -k and LIVE kernel"), | 450 | "load module symbols - WARNING: use only with -k and LIVE kernel"), |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 55f3b5dcc731..c7753940aea0 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
| @@ -1606,25 +1606,15 @@ process_raw_event(event_t *raw_event __used, struct perf_session *session, | |||
| 1606 | process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread); | 1606 | process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread); |
| 1607 | } | 1607 | } |
| 1608 | 1608 | ||
| 1609 | static int process_sample_event(event_t *event, struct perf_session *session) | 1609 | static int process_sample_event(event_t *event, struct sample_data *sample, |
| 1610 | struct perf_session *session) | ||
| 1610 | { | 1611 | { |
| 1611 | struct sample_data data; | ||
| 1612 | struct thread *thread; | 1612 | struct thread *thread; |
| 1613 | 1613 | ||
| 1614 | if (!(session->sample_type & PERF_SAMPLE_RAW)) | 1614 | if (!(session->sample_type & PERF_SAMPLE_RAW)) |
| 1615 | return 0; | 1615 | return 0; |
| 1616 | 1616 | ||
| 1617 | memset(&data, 0, sizeof(data)); | 1617 | thread = perf_session__findnew(session, sample->pid); |
| 1618 | data.time = -1; | ||
| 1619 | data.cpu = -1; | ||
| 1620 | data.period = -1; | ||
| 1621 | |||
| 1622 | event__parse_sample(event, session->sample_type, &data); | ||
| 1623 | |||
| 1624 | dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc, | ||
| 1625 | data.pid, data.tid, data.ip, data.period); | ||
| 1626 | |||
| 1627 | thread = perf_session__findnew(session, data.pid); | ||
| 1628 | if (thread == NULL) { | 1618 | if (thread == NULL) { |
| 1629 | pr_debug("problem processing %d event, skipping it.\n", | 1619 | pr_debug("problem processing %d event, skipping it.\n", |
| 1630 | event->header.type); | 1620 | event->header.type); |
| @@ -1633,10 +1623,11 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
| 1633 | 1623 | ||
| 1634 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | 1624 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); |
| 1635 | 1625 | ||
| 1636 | if (profile_cpu != -1 && profile_cpu != (int)data.cpu) | 1626 | if (profile_cpu != -1 && profile_cpu != (int)sample->cpu) |
| 1637 | return 0; | 1627 | return 0; |
| 1638 | 1628 | ||
| 1639 | process_raw_event(event, session, data.raw_data, data.cpu, data.time, thread); | 1629 | process_raw_event(event, session, sample->raw_data, sample->cpu, |
| 1630 | sample->time, thread); | ||
| 1640 | 1631 | ||
| 1641 | return 0; | 1632 | return 0; |
| 1642 | } | 1633 | } |
| @@ -1869,6 +1860,9 @@ static int __cmd_record(int argc, const char **argv) | |||
| 1869 | rec_argc = ARRAY_SIZE(record_args) + argc - 1; | 1860 | rec_argc = ARRAY_SIZE(record_args) + argc - 1; |
| 1870 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 1861 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
| 1871 | 1862 | ||
| 1863 | if (rec_argv) | ||
| 1864 | return -ENOMEM; | ||
| 1865 | |||
| 1872 | for (i = 0; i < ARRAY_SIZE(record_args); i++) | 1866 | for (i = 0; i < ARRAY_SIZE(record_args); i++) |
| 1873 | rec_argv[i] = strdup(record_args[i]); | 1867 | rec_argv[i] = strdup(record_args[i]); |
| 1874 | 1868 | ||
| @@ -1888,10 +1882,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __used) | |||
| 1888 | usage_with_options(sched_usage, sched_options); | 1882 | usage_with_options(sched_usage, sched_options); |
| 1889 | 1883 | ||
| 1890 | /* | 1884 | /* |
| 1891 | * Aliased to 'perf trace' for now: | 1885 | * Aliased to 'perf script' for now: |
| 1892 | */ | 1886 | */ |
| 1893 | if (!strcmp(argv[0], "trace")) | 1887 | if (!strcmp(argv[0], "script")) |
| 1894 | return cmd_trace(argc, argv, prefix); | 1888 | return cmd_script(argc, argv, prefix); |
| 1895 | 1889 | ||
| 1896 | symbol__init(); | 1890 | symbol__init(); |
| 1897 | if (!strncmp(argv[0], "rec", 3)) { | 1891 | if (!strncmp(argv[0], "rec", 3)) { |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-script.c index 86cfe3800e6b..54f1ea808db5 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-script.c | |||
| @@ -56,29 +56,18 @@ static void setup_scripting(void) | |||
| 56 | 56 | ||
| 57 | static int cleanup_scripting(void) | 57 | static int cleanup_scripting(void) |
| 58 | { | 58 | { |
| 59 | pr_debug("\nperf trace script stopped\n"); | 59 | pr_debug("\nperf script stopped\n"); |
| 60 | 60 | ||
| 61 | return scripting_ops->stop_script(); | 61 | return scripting_ops->stop_script(); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static char const *input_name = "perf.data"; | 64 | static char const *input_name = "perf.data"; |
| 65 | 65 | ||
| 66 | static int process_sample_event(event_t *event, struct perf_session *session) | 66 | static int process_sample_event(event_t *event, struct sample_data *sample, |
| 67 | struct perf_session *session) | ||
| 67 | { | 68 | { |
| 68 | struct sample_data data; | 69 | struct thread *thread = perf_session__findnew(session, event->ip.pid); |
| 69 | struct thread *thread; | ||
| 70 | 70 | ||
| 71 | memset(&data, 0, sizeof(data)); | ||
| 72 | data.time = -1; | ||
| 73 | data.cpu = -1; | ||
| 74 | data.period = 1; | ||
| 75 | |||
| 76 | event__parse_sample(event, session->sample_type, &data); | ||
| 77 | |||
| 78 | dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc, | ||
| 79 | data.pid, data.tid, data.ip, data.period); | ||
| 80 | |||
| 81 | thread = perf_session__findnew(session, event->ip.pid); | ||
| 82 | if (thread == NULL) { | 71 | if (thread == NULL) { |
| 83 | pr_debug("problem processing %d event, skipping it.\n", | 72 | pr_debug("problem processing %d event, skipping it.\n", |
| 84 | event->header.type); | 73 | event->header.type); |
| @@ -87,13 +76,13 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
| 87 | 76 | ||
| 88 | if (session->sample_type & PERF_SAMPLE_RAW) { | 77 | if (session->sample_type & PERF_SAMPLE_RAW) { |
| 89 | if (debug_mode) { | 78 | if (debug_mode) { |
| 90 | if (data.time < last_timestamp) { | 79 | if (sample->time < last_timestamp) { |
| 91 | pr_err("Samples misordered, previous: %llu " | 80 | pr_err("Samples misordered, previous: %llu " |
| 92 | "this: %llu\n", last_timestamp, | 81 | "this: %llu\n", last_timestamp, |
| 93 | data.time); | 82 | sample->time); |
| 94 | nr_unordered++; | 83 | nr_unordered++; |
| 95 | } | 84 | } |
| 96 | last_timestamp = data.time; | 85 | last_timestamp = sample->time; |
| 97 | return 0; | 86 | return 0; |
| 98 | } | 87 | } |
| 99 | /* | 88 | /* |
| @@ -101,18 +90,19 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
| 101 | * field, although it should be the same than this perf | 90 | * field, although it should be the same than this perf |
| 102 | * event pid | 91 | * event pid |
| 103 | */ | 92 | */ |
| 104 | scripting_ops->process_event(data.cpu, data.raw_data, | 93 | scripting_ops->process_event(sample->cpu, sample->raw_data, |
| 105 | data.raw_size, | 94 | sample->raw_size, |
| 106 | data.time, thread->comm); | 95 | sample->time, thread->comm); |
| 107 | } | 96 | } |
| 108 | 97 | ||
| 109 | session->hists.stats.total_period += data.period; | 98 | session->hists.stats.total_period += sample->period; |
| 110 | return 0; | 99 | return 0; |
| 111 | } | 100 | } |
| 112 | 101 | ||
| 113 | static u64 nr_lost; | 102 | static u64 nr_lost; |
| 114 | 103 | ||
| 115 | static int process_lost_event(event_t *event, struct perf_session *session __used) | 104 | static int process_lost_event(event_t *event, struct sample_data *sample __used, |
| 105 | struct perf_session *session __used) | ||
| 116 | { | 106 | { |
| 117 | nr_lost += event->lost.lost; | 107 | nr_lost += event->lost.lost; |
| 118 | 108 | ||
| @@ -137,7 +127,7 @@ static void sig_handler(int sig __unused) | |||
| 137 | session_done = 1; | 127 | session_done = 1; |
| 138 | } | 128 | } |
| 139 | 129 | ||
| 140 | static int __cmd_trace(struct perf_session *session) | 130 | static int __cmd_script(struct perf_session *session) |
| 141 | { | 131 | { |
| 142 | int ret; | 132 | int ret; |
| 143 | 133 | ||
| @@ -247,7 +237,7 @@ static void list_available_languages(void) | |||
| 247 | 237 | ||
| 248 | fprintf(stderr, "\n"); | 238 | fprintf(stderr, "\n"); |
| 249 | fprintf(stderr, "Scripting language extensions (used in " | 239 | fprintf(stderr, "Scripting language extensions (used in " |
| 250 | "perf trace -s [spec:]script.[spec]):\n\n"); | 240 | "perf script -s [spec:]script.[spec]):\n\n"); |
| 251 | 241 | ||
| 252 | list_for_each_entry(s, &script_specs, node) | 242 | list_for_each_entry(s, &script_specs, node) |
| 253 | fprintf(stderr, " %-42s [%s]\n", s->spec, s->ops->name); | 243 | fprintf(stderr, " %-42s [%s]\n", s->spec, s->ops->name); |
| @@ -301,17 +291,34 @@ static int parse_scriptname(const struct option *opt __used, | |||
| 301 | return 0; | 291 | return 0; |
| 302 | } | 292 | } |
| 303 | 293 | ||
| 304 | #define for_each_lang(scripts_dir, lang_dirent, lang_next) \ | 294 | /* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */ |
| 295 | static int is_directory(const char *base_path, const struct dirent *dent) | ||
| 296 | { | ||
| 297 | char path[PATH_MAX]; | ||
| 298 | struct stat st; | ||
| 299 | |||
| 300 | sprintf(path, "%s/%s", base_path, dent->d_name); | ||
| 301 | if (stat(path, &st)) | ||
| 302 | return 0; | ||
| 303 | |||
| 304 | return S_ISDIR(st.st_mode); | ||
| 305 | } | ||
| 306 | |||
| 307 | #define for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next)\ | ||
| 305 | while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) && \ | 308 | while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) && \ |
| 306 | lang_next) \ | 309 | lang_next) \ |
| 307 | if (lang_dirent.d_type == DT_DIR && \ | 310 | if ((lang_dirent.d_type == DT_DIR || \ |
| 311 | (lang_dirent.d_type == DT_UNKNOWN && \ | ||
| 312 | is_directory(scripts_path, &lang_dirent))) && \ | ||
| 308 | (strcmp(lang_dirent.d_name, ".")) && \ | 313 | (strcmp(lang_dirent.d_name, ".")) && \ |
| 309 | (strcmp(lang_dirent.d_name, ".."))) | 314 | (strcmp(lang_dirent.d_name, ".."))) |
| 310 | 315 | ||
| 311 | #define for_each_script(lang_dir, script_dirent, script_next) \ | 316 | #define for_each_script(lang_path, lang_dir, script_dirent, script_next)\ |
| 312 | while (!readdir_r(lang_dir, &script_dirent, &script_next) && \ | 317 | while (!readdir_r(lang_dir, &script_dirent, &script_next) && \ |
| 313 | script_next) \ | 318 | script_next) \ |
| 314 | if (script_dirent.d_type != DT_DIR) | 319 | if (script_dirent.d_type != DT_DIR && \ |
| 320 | (script_dirent.d_type != DT_UNKNOWN || \ | ||
| 321 | !is_directory(lang_path, &script_dirent))) | ||
| 315 | 322 | ||
| 316 | 323 | ||
| 317 | #define RECORD_SUFFIX "-record" | 324 | #define RECORD_SUFFIX "-record" |
| @@ -380,10 +387,10 @@ out_delete_desc: | |||
| 380 | return NULL; | 387 | return NULL; |
| 381 | } | 388 | } |
| 382 | 389 | ||
| 383 | static char *ends_with(char *str, const char *suffix) | 390 | static const char *ends_with(const char *str, const char *suffix) |
| 384 | { | 391 | { |
| 385 | size_t suffix_len = strlen(suffix); | 392 | size_t suffix_len = strlen(suffix); |
| 386 | char *p = str; | 393 | const char *p = str; |
| 387 | 394 | ||
| 388 | if (strlen(str) > suffix_len) { | 395 | if (strlen(str) > suffix_len) { |
| 389 | p = str + strlen(str) - suffix_len; | 396 | p = str + strlen(str) - suffix_len; |
| @@ -466,16 +473,16 @@ static int list_available_scripts(const struct option *opt __used, | |||
| 466 | if (!scripts_dir) | 473 | if (!scripts_dir) |
| 467 | return -1; | 474 | return -1; |
| 468 | 475 | ||
| 469 | for_each_lang(scripts_dir, lang_dirent, lang_next) { | 476 | for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) { |
| 470 | snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, | 477 | snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, |
| 471 | lang_dirent.d_name); | 478 | lang_dirent.d_name); |
| 472 | lang_dir = opendir(lang_path); | 479 | lang_dir = opendir(lang_path); |
| 473 | if (!lang_dir) | 480 | if (!lang_dir) |
| 474 | continue; | 481 | continue; |
| 475 | 482 | ||
| 476 | for_each_script(lang_dir, script_dirent, script_next) { | 483 | for_each_script(lang_path, lang_dir, script_dirent, script_next) { |
| 477 | script_root = strdup(script_dirent.d_name); | 484 | script_root = strdup(script_dirent.d_name); |
| 478 | str = ends_with(script_root, REPORT_SUFFIX); | 485 | str = (char *)ends_with(script_root, REPORT_SUFFIX); |
| 479 | if (str) { | 486 | if (str) { |
| 480 | *str = '\0'; | 487 | *str = '\0'; |
| 481 | desc = script_desc__findnew(script_root); | 488 | desc = script_desc__findnew(script_root); |
| @@ -514,16 +521,16 @@ static char *get_script_path(const char *script_root, const char *suffix) | |||
| 514 | if (!scripts_dir) | 521 | if (!scripts_dir) |
| 515 | return NULL; | 522 | return NULL; |
| 516 | 523 | ||
| 517 | for_each_lang(scripts_dir, lang_dirent, lang_next) { | 524 | for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) { |
| 518 | snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, | 525 | snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, |
| 519 | lang_dirent.d_name); | 526 | lang_dirent.d_name); |
| 520 | lang_dir = opendir(lang_path); | 527 | lang_dir = opendir(lang_path); |
| 521 | if (!lang_dir) | 528 | if (!lang_dir) |
| 522 | continue; | 529 | continue; |
| 523 | 530 | ||
| 524 | for_each_script(lang_dir, script_dirent, script_next) { | 531 | for_each_script(lang_path, lang_dir, script_dirent, script_next) { |
| 525 | __script_root = strdup(script_dirent.d_name); | 532 | __script_root = strdup(script_dirent.d_name); |
| 526 | str = ends_with(__script_root, suffix); | 533 | str = (char *)ends_with(__script_root, suffix); |
| 527 | if (str) { | 534 | if (str) { |
| 528 | *str = '\0'; | 535 | *str = '\0'; |
| 529 | if (strcmp(__script_root, script_root)) | 536 | if (strcmp(__script_root, script_root)) |
| @@ -543,7 +550,7 @@ static char *get_script_path(const char *script_root, const char *suffix) | |||
| 543 | 550 | ||
| 544 | static bool is_top_script(const char *script_path) | 551 | static bool is_top_script(const char *script_path) |
| 545 | { | 552 | { |
| 546 | return ends_with((char *)script_path, "top") == NULL ? false : true; | 553 | return ends_with(script_path, "top") == NULL ? false : true; |
| 547 | } | 554 | } |
| 548 | 555 | ||
| 549 | static int has_required_arg(char *script_path) | 556 | static int has_required_arg(char *script_path) |
| @@ -569,12 +576,12 @@ out: | |||
| 569 | return n_args; | 576 | return n_args; |
| 570 | } | 577 | } |
| 571 | 578 | ||
| 572 | static const char * const trace_usage[] = { | 579 | static const char * const script_usage[] = { |
| 573 | "perf trace [<options>]", | 580 | "perf script [<options>]", |
| 574 | "perf trace [<options>] record <script> [<record-options>] <command>", | 581 | "perf script [<options>] record <script> [<record-options>] <command>", |
| 575 | "perf trace [<options>] report <script> [script-args]", | 582 | "perf script [<options>] report <script> [script-args]", |
| 576 | "perf trace [<options>] <script> [<record-options>] <command>", | 583 | "perf script [<options>] <script> [<record-options>] <command>", |
| 577 | "perf trace [<options>] <top-script> [script-args]", | 584 | "perf script [<options>] <top-script> [script-args]", |
| 578 | NULL | 585 | NULL |
| 579 | }; | 586 | }; |
| 580 | 587 | ||
| @@ -591,7 +598,7 @@ static const struct option options[] = { | |||
| 591 | "script file name (lang:script name, script name, or *)", | 598 | "script file name (lang:script name, script name, or *)", |
| 592 | parse_scriptname), | 599 | parse_scriptname), |
| 593 | OPT_STRING('g', "gen-script", &generate_script_lang, "lang", | 600 | OPT_STRING('g', "gen-script", &generate_script_lang, "lang", |
| 594 | "generate perf-trace.xx script in specified language"), | 601 | "generate perf-script.xx script in specified language"), |
| 595 | OPT_STRING('i', "input", &input_name, "file", | 602 | OPT_STRING('i', "input", &input_name, "file", |
| 596 | "input file name"), | 603 | "input file name"), |
| 597 | OPT_BOOLEAN('d', "debug-mode", &debug_mode, | 604 | OPT_BOOLEAN('d', "debug-mode", &debug_mode, |
| @@ -614,7 +621,7 @@ static bool have_cmd(int argc, const char **argv) | |||
| 614 | return argc != 0; | 621 | return argc != 0; |
| 615 | } | 622 | } |
| 616 | 623 | ||
| 617 | int cmd_trace(int argc, const char **argv, const char *prefix __used) | 624 | int cmd_script(int argc, const char **argv, const char *prefix __used) |
| 618 | { | 625 | { |
| 619 | char *rec_script_path = NULL; | 626 | char *rec_script_path = NULL; |
| 620 | char *rep_script_path = NULL; | 627 | char *rep_script_path = NULL; |
| @@ -626,7 +633,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) | |||
| 626 | 633 | ||
| 627 | setup_scripting(); | 634 | setup_scripting(); |
| 628 | 635 | ||
| 629 | argc = parse_options(argc, argv, options, trace_usage, | 636 | argc = parse_options(argc, argv, options, script_usage, |
| 630 | PARSE_OPT_STOP_AT_NON_OPTION); | 637 | PARSE_OPT_STOP_AT_NON_OPTION); |
| 631 | 638 | ||
| 632 | if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) { | 639 | if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) { |
| @@ -640,7 +647,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) | |||
| 640 | if (!rep_script_path) { | 647 | if (!rep_script_path) { |
| 641 | fprintf(stderr, | 648 | fprintf(stderr, |
| 642 | "Please specify a valid report script" | 649 | "Please specify a valid report script" |
| 643 | "(see 'perf trace -l' for listing)\n"); | 650 | "(see 'perf script -l' for listing)\n"); |
| 644 | return -1; | 651 | return -1; |
| 645 | } | 652 | } |
| 646 | } | 653 | } |
| @@ -658,8 +665,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) | |||
| 658 | 665 | ||
| 659 | if (!rec_script_path && !rep_script_path) { | 666 | if (!rec_script_path && !rep_script_path) { |
| 660 | fprintf(stderr, " Couldn't find script %s\n\n See perf" | 667 | fprintf(stderr, " Couldn't find script %s\n\n See perf" |
| 661 | " trace -l for available scripts.\n", argv[0]); | 668 | " script -l for available scripts.\n", argv[0]); |
| 662 | usage_with_options(trace_usage, options); | 669 | usage_with_options(script_usage, options); |
| 663 | } | 670 | } |
| 664 | 671 | ||
| 665 | if (is_top_script(argv[0])) { | 672 | if (is_top_script(argv[0])) { |
| @@ -671,9 +678,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) | |||
| 671 | rec_args = (argc - 1) - rep_args; | 678 | rec_args = (argc - 1) - rep_args; |
| 672 | if (rec_args < 0) { | 679 | if (rec_args < 0) { |
| 673 | fprintf(stderr, " %s script requires options." | 680 | fprintf(stderr, " %s script requires options." |
| 674 | "\n\n See perf trace -l for available " | 681 | "\n\n See perf script -l for available " |
| 675 | "scripts and options.\n", argv[0]); | 682 | "scripts and options.\n", argv[0]); |
| 676 | usage_with_options(trace_usage, options); | 683 | usage_with_options(script_usage, options); |
| 677 | } | 684 | } |
| 678 | } | 685 | } |
| 679 | 686 | ||
| @@ -806,7 +813,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) | |||
| 806 | return -1; | 813 | return -1; |
| 807 | } | 814 | } |
| 808 | 815 | ||
| 809 | err = scripting_ops->generate_script("perf-trace"); | 816 | err = scripting_ops->generate_script("perf-script"); |
| 810 | goto out; | 817 | goto out; |
| 811 | } | 818 | } |
| 812 | 819 | ||
| @@ -814,10 +821,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) | |||
| 814 | err = scripting_ops->start_script(script_name, argc, argv); | 821 | err = scripting_ops->start_script(script_name, argc, argv); |
| 815 | if (err) | 822 | if (err) |
| 816 | goto out; | 823 | goto out; |
| 817 | pr_debug("perf trace started with script %s\n\n", script_name); | 824 | pr_debug("perf script started with script %s\n\n", script_name); |
| 818 | } | 825 | } |
| 819 | 826 | ||
| 820 | err = __cmd_trace(session); | 827 | err = __cmd_script(session); |
| 821 | 828 | ||
| 822 | perf_session__delete(session); | 829 | perf_session__delete(session); |
| 823 | cleanup_scripting(); | 830 | cleanup_scripting(); |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index a6b4d44f9502..7ff746da7e6c 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
| @@ -52,6 +52,8 @@ | |||
| 52 | #include <math.h> | 52 | #include <math.h> |
| 53 | #include <locale.h> | 53 | #include <locale.h> |
| 54 | 54 | ||
| 55 | #define DEFAULT_SEPARATOR " " | ||
| 56 | |||
| 55 | static struct perf_event_attr default_attrs[] = { | 57 | static struct perf_event_attr default_attrs[] = { |
| 56 | 58 | ||
| 57 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, | 59 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, |
| @@ -75,20 +77,30 @@ static int run_idx = 0; | |||
| 75 | static int run_count = 1; | 77 | static int run_count = 1; |
| 76 | static bool no_inherit = false; | 78 | static bool no_inherit = false; |
| 77 | static bool scale = true; | 79 | static bool scale = true; |
| 80 | static bool no_aggr = false; | ||
| 78 | static pid_t target_pid = -1; | 81 | static pid_t target_pid = -1; |
| 79 | static pid_t target_tid = -1; | 82 | static pid_t target_tid = -1; |
| 80 | static pid_t *all_tids = NULL; | 83 | static pid_t *all_tids = NULL; |
| 81 | static int thread_num = 0; | 84 | static int thread_num = 0; |
| 82 | static pid_t child_pid = -1; | 85 | static pid_t child_pid = -1; |
| 83 | static bool null_run = false; | 86 | static bool null_run = false; |
| 84 | static bool big_num = false; | 87 | static bool big_num = true; |
| 88 | static int big_num_opt = -1; | ||
| 85 | static const char *cpu_list; | 89 | static const char *cpu_list; |
| 90 | static const char *csv_sep = NULL; | ||
| 91 | static bool csv_output = false; | ||
| 86 | 92 | ||
| 87 | 93 | ||
| 88 | static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; | 94 | static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; |
| 89 | 95 | ||
| 90 | static int event_scaled[MAX_COUNTERS]; | 96 | static int event_scaled[MAX_COUNTERS]; |
| 91 | 97 | ||
| 98 | static struct { | ||
| 99 | u64 val; | ||
| 100 | u64 ena; | ||
| 101 | u64 run; | ||
| 102 | } cpu_counts[MAX_NR_CPUS][MAX_COUNTERS]; | ||
| 103 | |||
| 92 | static volatile int done = 0; | 104 | static volatile int done = 0; |
| 93 | 105 | ||
| 94 | struct stats | 106 | struct stats |
| @@ -136,19 +148,19 @@ static double stddev_stats(struct stats *stats) | |||
| 136 | } | 148 | } |
| 137 | 149 | ||
| 138 | struct stats event_res_stats[MAX_COUNTERS][3]; | 150 | struct stats event_res_stats[MAX_COUNTERS][3]; |
| 139 | struct stats runtime_nsecs_stats; | 151 | struct stats runtime_nsecs_stats[MAX_NR_CPUS]; |
| 152 | struct stats runtime_cycles_stats[MAX_NR_CPUS]; | ||
| 153 | struct stats runtime_branches_stats[MAX_NR_CPUS]; | ||
| 140 | struct stats walltime_nsecs_stats; | 154 | struct stats walltime_nsecs_stats; |
| 141 | struct stats runtime_cycles_stats; | ||
| 142 | struct stats runtime_branches_stats; | ||
| 143 | 155 | ||
| 144 | #define MATCH_EVENT(t, c, counter) \ | 156 | #define MATCH_EVENT(t, c, counter) \ |
| 145 | (attrs[counter].type == PERF_TYPE_##t && \ | 157 | (attrs[counter].type == PERF_TYPE_##t && \ |
| 146 | attrs[counter].config == PERF_COUNT_##c) | 158 | attrs[counter].config == PERF_COUNT_##c) |
| 147 | 159 | ||
| 148 | #define ERR_PERF_OPEN \ | 160 | #define ERR_PERF_OPEN \ |
| 149 | "Error: counter %d, sys_perf_event_open() syscall returned with %d (%s)\n" | 161 | "counter %d, sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information." |
| 150 | 162 | ||
| 151 | static int create_perf_stat_counter(int counter) | 163 | static int create_perf_stat_counter(int counter, bool *perm_err) |
| 152 | { | 164 | { |
| 153 | struct perf_event_attr *attr = attrs + counter; | 165 | struct perf_event_attr *attr = attrs + counter; |
| 154 | int thread; | 166 | int thread; |
| @@ -164,11 +176,14 @@ static int create_perf_stat_counter(int counter) | |||
| 164 | for (cpu = 0; cpu < nr_cpus; cpu++) { | 176 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
| 165 | fd[cpu][counter][0] = sys_perf_event_open(attr, | 177 | fd[cpu][counter][0] = sys_perf_event_open(attr, |
| 166 | -1, cpumap[cpu], -1, 0); | 178 | -1, cpumap[cpu], -1, 0); |
| 167 | if (fd[cpu][counter][0] < 0) | 179 | if (fd[cpu][counter][0] < 0) { |
| 168 | pr_debug(ERR_PERF_OPEN, counter, | 180 | if (errno == EPERM || errno == EACCES) |
| 181 | *perm_err = true; | ||
| 182 | error(ERR_PERF_OPEN, counter, | ||
| 169 | fd[cpu][counter][0], strerror(errno)); | 183 | fd[cpu][counter][0], strerror(errno)); |
| 170 | else | 184 | } else { |
| 171 | ++ncreated; | 185 | ++ncreated; |
| 186 | } | ||
| 172 | } | 187 | } |
| 173 | } else { | 188 | } else { |
| 174 | attr->inherit = !no_inherit; | 189 | attr->inherit = !no_inherit; |
| @@ -179,12 +194,15 @@ static int create_perf_stat_counter(int counter) | |||
| 179 | for (thread = 0; thread < thread_num; thread++) { | 194 | for (thread = 0; thread < thread_num; thread++) { |
| 180 | fd[0][counter][thread] = sys_perf_event_open(attr, | 195 | fd[0][counter][thread] = sys_perf_event_open(attr, |
| 181 | all_tids[thread], -1, -1, 0); | 196 | all_tids[thread], -1, -1, 0); |
| 182 | if (fd[0][counter][thread] < 0) | 197 | if (fd[0][counter][thread] < 0) { |
| 183 | pr_debug(ERR_PERF_OPEN, counter, | 198 | if (errno == EPERM || errno == EACCES) |
| 199 | *perm_err = true; | ||
| 200 | error(ERR_PERF_OPEN, counter, | ||
| 184 | fd[0][counter][thread], | 201 | fd[0][counter][thread], |
| 185 | strerror(errno)); | 202 | strerror(errno)); |
| 186 | else | 203 | } else { |
| 187 | ++ncreated; | 204 | ++ncreated; |
| 205 | } | ||
| 188 | } | 206 | } |
| 189 | } | 207 | } |
| 190 | 208 | ||
| @@ -205,8 +223,9 @@ static inline int nsec_counter(int counter) | |||
| 205 | 223 | ||
| 206 | /* | 224 | /* |
| 207 | * Read out the results of a single counter: | 225 | * Read out the results of a single counter: |
| 226 | * aggregate counts across CPUs in system-wide mode | ||
| 208 | */ | 227 | */ |
| 209 | static void read_counter(int counter) | 228 | static void read_counter_aggr(int counter) |
| 210 | { | 229 | { |
| 211 | u64 count[3], single_count[3]; | 230 | u64 count[3], single_count[3]; |
| 212 | int cpu; | 231 | int cpu; |
| @@ -264,11 +283,58 @@ static void read_counter(int counter) | |||
| 264 | * Save the full runtime - to allow normalization during printout: | 283 | * Save the full runtime - to allow normalization during printout: |
| 265 | */ | 284 | */ |
| 266 | if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) | 285 | if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) |
| 267 | update_stats(&runtime_nsecs_stats, count[0]); | 286 | update_stats(&runtime_nsecs_stats[0], count[0]); |
| 268 | if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter)) | 287 | if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter)) |
| 269 | update_stats(&runtime_cycles_stats, count[0]); | 288 | update_stats(&runtime_cycles_stats[0], count[0]); |
| 270 | if (MATCH_EVENT(HARDWARE, HW_BRANCH_INSTRUCTIONS, counter)) | 289 | if (MATCH_EVENT(HARDWARE, HW_BRANCH_INSTRUCTIONS, counter)) |
| 271 | update_stats(&runtime_branches_stats, count[0]); | 290 | update_stats(&runtime_branches_stats[0], count[0]); |
| 291 | } | ||
| 292 | |||
| 293 | /* | ||
| 294 | * Read out the results of a single counter: | ||
| 295 | * do not aggregate counts across CPUs in system-wide mode | ||
| 296 | */ | ||
| 297 | static void read_counter(int counter) | ||
| 298 | { | ||
| 299 | u64 count[3]; | ||
| 300 | int cpu; | ||
| 301 | size_t res, nv; | ||
| 302 | |||
| 303 | count[0] = count[1] = count[2] = 0; | ||
| 304 | |||
| 305 | nv = scale ? 3 : 1; | ||
| 306 | |||
| 307 | for (cpu = 0; cpu < nr_cpus; cpu++) { | ||
| 308 | |||
| 309 | if (fd[cpu][counter][0] < 0) | ||
| 310 | continue; | ||
| 311 | |||
| 312 | res = read(fd[cpu][counter][0], count, nv * sizeof(u64)); | ||
| 313 | |||
| 314 | assert(res == nv * sizeof(u64)); | ||
| 315 | |||
| 316 | close(fd[cpu][counter][0]); | ||
| 317 | fd[cpu][counter][0] = -1; | ||
| 318 | |||
| 319 | if (scale) { | ||
| 320 | if (count[2] == 0) { | ||
| 321 | count[0] = 0; | ||
| 322 | } else if (count[2] < count[1]) { | ||
| 323 | count[0] = (unsigned long long) | ||
| 324 | ((double)count[0] * count[1] / count[2] + 0.5); | ||
| 325 | } | ||
| 326 | } | ||
| 327 | cpu_counts[cpu][counter].val = count[0]; /* scaled count */ | ||
| 328 | cpu_counts[cpu][counter].ena = count[1]; | ||
| 329 | cpu_counts[cpu][counter].run = count[2]; | ||
| 330 | |||
| 331 | if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) | ||
| 332 | update_stats(&runtime_nsecs_stats[cpu], count[0]); | ||
| 333 | if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter)) | ||
| 334 | update_stats(&runtime_cycles_stats[cpu], count[0]); | ||
| 335 | if (MATCH_EVENT(HARDWARE, HW_BRANCH_INSTRUCTIONS, counter)) | ||
| 336 | update_stats(&runtime_branches_stats[cpu], count[0]); | ||
| 337 | } | ||
| 272 | } | 338 | } |
| 273 | 339 | ||
| 274 | static int run_perf_stat(int argc __used, const char **argv) | 340 | static int run_perf_stat(int argc __used, const char **argv) |
| @@ -277,6 +343,7 @@ static int run_perf_stat(int argc __used, const char **argv) | |||
| 277 | int status = 0; | 343 | int status = 0; |
| 278 | int counter, ncreated = 0; | 344 | int counter, ncreated = 0; |
| 279 | int child_ready_pipe[2], go_pipe[2]; | 345 | int child_ready_pipe[2], go_pipe[2]; |
| 346 | bool perm_err = false; | ||
| 280 | const bool forks = (argc > 0); | 347 | const bool forks = (argc > 0); |
| 281 | char buf; | 348 | char buf; |
| 282 | 349 | ||
| @@ -335,12 +402,15 @@ static int run_perf_stat(int argc __used, const char **argv) | |||
| 335 | } | 402 | } |
| 336 | 403 | ||
| 337 | for (counter = 0; counter < nr_counters; counter++) | 404 | for (counter = 0; counter < nr_counters; counter++) |
| 338 | ncreated += create_perf_stat_counter(counter); | 405 | ncreated += create_perf_stat_counter(counter, &perm_err); |
| 339 | 406 | ||
| 340 | if (ncreated == 0) { | 407 | if (ncreated < nr_counters) { |
| 341 | pr_err("No permission to collect %sstats.\n" | 408 | if (perm_err) |
| 342 | "Consider tweaking /proc/sys/kernel/perf_event_paranoid.\n", | 409 | error("You may not have permission to collect %sstats.\n" |
| 343 | system_wide ? "system-wide " : ""); | 410 | "\t Consider tweaking" |
| 411 | " /proc/sys/kernel/perf_event_paranoid or running as root.", | ||
| 412 | system_wide ? "system-wide " : ""); | ||
| 413 | die("Not all events could be opened.\n"); | ||
| 344 | if (child_pid != -1) | 414 | if (child_pid != -1) |
| 345 | kill(child_pid, SIGTERM); | 415 | kill(child_pid, SIGTERM); |
| 346 | return -1; | 416 | return -1; |
| @@ -362,9 +432,13 @@ static int run_perf_stat(int argc __used, const char **argv) | |||
| 362 | 432 | ||
| 363 | update_stats(&walltime_nsecs_stats, t1 - t0); | 433 | update_stats(&walltime_nsecs_stats, t1 - t0); |
| 364 | 434 | ||
| 365 | for (counter = 0; counter < nr_counters; counter++) | 435 | if (no_aggr) { |
| 366 | read_counter(counter); | 436 | for (counter = 0; counter < nr_counters; counter++) |
| 367 | 437 | read_counter(counter); | |
| 438 | } else { | ||
| 439 | for (counter = 0; counter < nr_counters; counter++) | ||
| 440 | read_counter_aggr(counter); | ||
| 441 | } | ||
| 368 | return WEXITSTATUS(status); | 442 | return WEXITSTATUS(status); |
| 369 | } | 443 | } |
| 370 | 444 | ||
| @@ -377,11 +451,21 @@ static void print_noise(int counter, double avg) | |||
| 377 | 100 * stddev_stats(&event_res_stats[counter][0]) / avg); | 451 | 100 * stddev_stats(&event_res_stats[counter][0]) / avg); |
| 378 | } | 452 | } |
| 379 | 453 | ||
| 380 | static void nsec_printout(int counter, double avg) | 454 | static void nsec_printout(int cpu, int counter, double avg) |
| 381 | { | 455 | { |
| 382 | double msecs = avg / 1e6; | 456 | double msecs = avg / 1e6; |
| 457 | char cpustr[16] = { '\0', }; | ||
| 458 | const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-24s"; | ||
| 459 | |||
| 460 | if (no_aggr) | ||
| 461 | sprintf(cpustr, "CPU%*d%s", | ||
| 462 | csv_output ? 0 : -4, | ||
| 463 | cpumap[cpu], csv_sep); | ||
| 383 | 464 | ||
| 384 | fprintf(stderr, " %18.6f %-24s", msecs, event_name(counter)); | 465 | fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(counter)); |
| 466 | |||
| 467 | if (csv_output) | ||
| 468 | return; | ||
| 385 | 469 | ||
| 386 | if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) { | 470 | if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) { |
| 387 | fprintf(stderr, " # %10.3f CPUs ", | 471 | fprintf(stderr, " # %10.3f CPUs ", |
| @@ -389,33 +473,49 @@ static void nsec_printout(int counter, double avg) | |||
| 389 | } | 473 | } |
| 390 | } | 474 | } |
| 391 | 475 | ||
| 392 | static void abs_printout(int counter, double avg) | 476 | static void abs_printout(int cpu, int counter, double avg) |
| 393 | { | 477 | { |
| 394 | double total, ratio = 0.0; | 478 | double total, ratio = 0.0; |
| 479 | char cpustr[16] = { '\0', }; | ||
| 480 | const char *fmt; | ||
| 481 | |||
| 482 | if (csv_output) | ||
| 483 | fmt = "%s%.0f%s%s"; | ||
| 484 | else if (big_num) | ||
| 485 | fmt = "%s%'18.0f%s%-24s"; | ||
| 486 | else | ||
| 487 | fmt = "%s%18.0f%s%-24s"; | ||
| 395 | 488 | ||
| 396 | if (big_num) | 489 | if (no_aggr) |
| 397 | fprintf(stderr, " %'18.0f %-24s", avg, event_name(counter)); | 490 | sprintf(cpustr, "CPU%*d%s", |
| 491 | csv_output ? 0 : -4, | ||
| 492 | cpumap[cpu], csv_sep); | ||
| 398 | else | 493 | else |
| 399 | fprintf(stderr, " %18.0f %-24s", avg, event_name(counter)); | 494 | cpu = 0; |
| 495 | |||
| 496 | fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(counter)); | ||
| 497 | |||
| 498 | if (csv_output) | ||
| 499 | return; | ||
| 400 | 500 | ||
| 401 | if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) { | 501 | if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) { |
| 402 | total = avg_stats(&runtime_cycles_stats); | 502 | total = avg_stats(&runtime_cycles_stats[cpu]); |
| 403 | 503 | ||
| 404 | if (total) | 504 | if (total) |
| 405 | ratio = avg / total; | 505 | ratio = avg / total; |
| 406 | 506 | ||
| 407 | fprintf(stderr, " # %10.3f IPC ", ratio); | 507 | fprintf(stderr, " # %10.3f IPC ", ratio); |
| 408 | } else if (MATCH_EVENT(HARDWARE, HW_BRANCH_MISSES, counter) && | 508 | } else if (MATCH_EVENT(HARDWARE, HW_BRANCH_MISSES, counter) && |
| 409 | runtime_branches_stats.n != 0) { | 509 | runtime_branches_stats[cpu].n != 0) { |
| 410 | total = avg_stats(&runtime_branches_stats); | 510 | total = avg_stats(&runtime_branches_stats[cpu]); |
| 411 | 511 | ||
| 412 | if (total) | 512 | if (total) |
| 413 | ratio = avg * 100 / total; | 513 | ratio = avg * 100 / total; |
| 414 | 514 | ||
| 415 | fprintf(stderr, " # %10.3f %% ", ratio); | 515 | fprintf(stderr, " # %10.3f %% ", ratio); |
| 416 | 516 | ||
| 417 | } else if (runtime_nsecs_stats.n != 0) { | 517 | } else if (runtime_nsecs_stats[cpu].n != 0) { |
| 418 | total = avg_stats(&runtime_nsecs_stats); | 518 | total = avg_stats(&runtime_nsecs_stats[cpu]); |
| 419 | 519 | ||
| 420 | if (total) | 520 | if (total) |
| 421 | ratio = 1000.0 * avg / total; | 521 | ratio = 1000.0 * avg / total; |
| @@ -426,22 +526,29 @@ static void abs_printout(int counter, double avg) | |||
| 426 | 526 | ||
| 427 | /* | 527 | /* |
| 428 | * Print out the results of a single counter: | 528 | * Print out the results of a single counter: |
| 529 | * aggregated counts in system-wide mode | ||
| 429 | */ | 530 | */ |
| 430 | static void print_counter(int counter) | 531 | static void print_counter_aggr(int counter) |
| 431 | { | 532 | { |
| 432 | double avg = avg_stats(&event_res_stats[counter][0]); | 533 | double avg = avg_stats(&event_res_stats[counter][0]); |
| 433 | int scaled = event_scaled[counter]; | 534 | int scaled = event_scaled[counter]; |
| 434 | 535 | ||
| 435 | if (scaled == -1) { | 536 | if (scaled == -1) { |
| 436 | fprintf(stderr, " %18s %-24s\n", | 537 | fprintf(stderr, "%*s%s%-24s\n", |
| 437 | "<not counted>", event_name(counter)); | 538 | csv_output ? 0 : 18, |
| 539 | "<not counted>", csv_sep, event_name(counter)); | ||
| 438 | return; | 540 | return; |
| 439 | } | 541 | } |
| 440 | 542 | ||
| 441 | if (nsec_counter(counter)) | 543 | if (nsec_counter(counter)) |
| 442 | nsec_printout(counter, avg); | 544 | nsec_printout(-1, counter, avg); |
| 443 | else | 545 | else |
| 444 | abs_printout(counter, avg); | 546 | abs_printout(-1, counter, avg); |
| 547 | |||
| 548 | if (csv_output) { | ||
| 549 | fputc('\n', stderr); | ||
| 550 | return; | ||
| 551 | } | ||
| 445 | 552 | ||
| 446 | print_noise(counter, avg); | 553 | print_noise(counter, avg); |
| 447 | 554 | ||
| @@ -458,40 +565,91 @@ static void print_counter(int counter) | |||
| 458 | fprintf(stderr, "\n"); | 565 | fprintf(stderr, "\n"); |
| 459 | } | 566 | } |
| 460 | 567 | ||
| 568 | /* | ||
| 569 | * Print out the results of a single counter: | ||
| 570 | * does not use aggregated count in system-wide | ||
| 571 | */ | ||
| 572 | static void print_counter(int counter) | ||
| 573 | { | ||
| 574 | u64 ena, run, val; | ||
| 575 | int cpu; | ||
| 576 | |||
| 577 | for (cpu = 0; cpu < nr_cpus; cpu++) { | ||
| 578 | val = cpu_counts[cpu][counter].val; | ||
| 579 | ena = cpu_counts[cpu][counter].ena; | ||
| 580 | run = cpu_counts[cpu][counter].run; | ||
| 581 | if (run == 0 || ena == 0) { | ||
| 582 | fprintf(stderr, "CPU%*d%s%*s%s%-24s", | ||
| 583 | csv_output ? 0 : -4, | ||
| 584 | cpumap[cpu], csv_sep, | ||
| 585 | csv_output ? 0 : 18, | ||
| 586 | "<not counted>", csv_sep, | ||
| 587 | event_name(counter)); | ||
| 588 | |||
| 589 | fprintf(stderr, "\n"); | ||
| 590 | continue; | ||
| 591 | } | ||
| 592 | |||
| 593 | if (nsec_counter(counter)) | ||
| 594 | nsec_printout(cpu, counter, val); | ||
| 595 | else | ||
| 596 | abs_printout(cpu, counter, val); | ||
| 597 | |||
| 598 | if (!csv_output) { | ||
| 599 | print_noise(counter, 1.0); | ||
| 600 | |||
| 601 | if (run != ena) { | ||
| 602 | fprintf(stderr, " (scaled from %.2f%%)", | ||
| 603 | 100.0 * run / ena); | ||
| 604 | } | ||
| 605 | } | ||
| 606 | fprintf(stderr, "\n"); | ||
| 607 | } | ||
| 608 | } | ||
| 609 | |||
| 461 | static void print_stat(int argc, const char **argv) | 610 | static void print_stat(int argc, const char **argv) |
| 462 | { | 611 | { |
| 463 | int i, counter; | 612 | int i, counter; |
| 464 | 613 | ||
| 465 | fflush(stdout); | 614 | fflush(stdout); |
| 466 | 615 | ||
| 467 | fprintf(stderr, "\n"); | 616 | if (!csv_output) { |
| 468 | fprintf(stderr, " Performance counter stats for "); | 617 | fprintf(stderr, "\n"); |
| 469 | if(target_pid == -1 && target_tid == -1) { | 618 | fprintf(stderr, " Performance counter stats for "); |
| 470 | fprintf(stderr, "\'%s", argv[0]); | 619 | if(target_pid == -1 && target_tid == -1) { |
| 471 | for (i = 1; i < argc; i++) | 620 | fprintf(stderr, "\'%s", argv[0]); |
| 472 | fprintf(stderr, " %s", argv[i]); | 621 | for (i = 1; i < argc; i++) |
| 473 | } else if (target_pid != -1) | 622 | fprintf(stderr, " %s", argv[i]); |
| 474 | fprintf(stderr, "process id \'%d", target_pid); | 623 | } else if (target_pid != -1) |
| 475 | else | 624 | fprintf(stderr, "process id \'%d", target_pid); |
| 476 | fprintf(stderr, "thread id \'%d", target_tid); | 625 | else |
| 477 | 626 | fprintf(stderr, "thread id \'%d", target_tid); | |
| 478 | fprintf(stderr, "\'"); | 627 | |
| 479 | if (run_count > 1) | 628 | fprintf(stderr, "\'"); |
| 480 | fprintf(stderr, " (%d runs)", run_count); | 629 | if (run_count > 1) |
| 481 | fprintf(stderr, ":\n\n"); | 630 | fprintf(stderr, " (%d runs)", run_count); |
| 631 | fprintf(stderr, ":\n\n"); | ||
| 632 | } | ||
| 482 | 633 | ||
| 483 | for (counter = 0; counter < nr_counters; counter++) | 634 | if (no_aggr) { |
| 484 | print_counter(counter); | 635 | for (counter = 0; counter < nr_counters; counter++) |
| 636 | print_counter(counter); | ||
| 637 | } else { | ||
| 638 | for (counter = 0; counter < nr_counters; counter++) | ||
| 639 | print_counter_aggr(counter); | ||
| 640 | } | ||
| 485 | 641 | ||
| 486 | fprintf(stderr, "\n"); | 642 | if (!csv_output) { |
| 487 | fprintf(stderr, " %18.9f seconds time elapsed", | 643 | fprintf(stderr, "\n"); |
| 488 | avg_stats(&walltime_nsecs_stats)/1e9); | 644 | fprintf(stderr, " %18.9f seconds time elapsed", |
| 489 | if (run_count > 1) { | 645 | avg_stats(&walltime_nsecs_stats)/1e9); |
| 490 | fprintf(stderr, " ( +- %7.3f%% )", | 646 | if (run_count > 1) { |
| 647 | fprintf(stderr, " ( +- %7.3f%% )", | ||
| 491 | 100*stddev_stats(&walltime_nsecs_stats) / | 648 | 100*stddev_stats(&walltime_nsecs_stats) / |
| 492 | avg_stats(&walltime_nsecs_stats)); | 649 | avg_stats(&walltime_nsecs_stats)); |
| 650 | } | ||
| 651 | fprintf(stderr, "\n\n"); | ||
| 493 | } | 652 | } |
| 494 | fprintf(stderr, "\n\n"); | ||
| 495 | } | 653 | } |
| 496 | 654 | ||
| 497 | static volatile int signr = -1; | 655 | static volatile int signr = -1; |
| @@ -521,6 +679,13 @@ static const char * const stat_usage[] = { | |||
| 521 | NULL | 679 | NULL |
| 522 | }; | 680 | }; |
| 523 | 681 | ||
| 682 | static int stat__set_big_num(const struct option *opt __used, | ||
| 683 | const char *s __used, int unset) | ||
| 684 | { | ||
| 685 | big_num_opt = unset ? 0 : 1; | ||
| 686 | return 0; | ||
| 687 | } | ||
| 688 | |||
| 524 | static const struct option options[] = { | 689 | static const struct option options[] = { |
| 525 | OPT_CALLBACK('e', "event", NULL, "event", | 690 | OPT_CALLBACK('e', "event", NULL, "event", |
| 526 | "event selector. use 'perf list' to list available events", | 691 | "event selector. use 'perf list' to list available events", |
| @@ -541,10 +706,15 @@ static const struct option options[] = { | |||
| 541 | "repeat command and print average + stddev (max: 100)"), | 706 | "repeat command and print average + stddev (max: 100)"), |
| 542 | OPT_BOOLEAN('n', "null", &null_run, | 707 | OPT_BOOLEAN('n', "null", &null_run, |
| 543 | "null run - dont start any counters"), | 708 | "null run - dont start any counters"), |
| 544 | OPT_BOOLEAN('B', "big-num", &big_num, | 709 | OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, |
| 545 | "print large numbers with thousands\' separators"), | 710 | "print large numbers with thousands\' separators", |
| 711 | stat__set_big_num), | ||
| 546 | OPT_STRING('C', "cpu", &cpu_list, "cpu", | 712 | OPT_STRING('C', "cpu", &cpu_list, "cpu", |
| 547 | "list of cpus to monitor in system-wide"), | 713 | "list of cpus to monitor in system-wide"), |
| 714 | OPT_BOOLEAN('A', "no-aggr", &no_aggr, | ||
| 715 | "disable CPU count aggregation"), | ||
| 716 | OPT_STRING('x', "field-separator", &csv_sep, "separator", | ||
| 717 | "print counts with custom separator"), | ||
| 548 | OPT_END() | 718 | OPT_END() |
| 549 | }; | 719 | }; |
| 550 | 720 | ||
| @@ -557,11 +727,34 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) | |||
| 557 | 727 | ||
| 558 | argc = parse_options(argc, argv, options, stat_usage, | 728 | argc = parse_options(argc, argv, options, stat_usage, |
| 559 | PARSE_OPT_STOP_AT_NON_OPTION); | 729 | PARSE_OPT_STOP_AT_NON_OPTION); |
| 730 | |||
| 731 | if (csv_sep) | ||
| 732 | csv_output = true; | ||
| 733 | else | ||
| 734 | csv_sep = DEFAULT_SEPARATOR; | ||
| 735 | |||
| 736 | /* | ||
| 737 | * let the spreadsheet do the pretty-printing | ||
| 738 | */ | ||
| 739 | if (csv_output) { | ||
| 740 | /* User explicitely passed -B? */ | ||
| 741 | if (big_num_opt == 1) { | ||
| 742 | fprintf(stderr, "-B option not supported with -x\n"); | ||
| 743 | usage_with_options(stat_usage, options); | ||
| 744 | } else /* Nope, so disable big number formatting */ | ||
| 745 | big_num = false; | ||
| 746 | } else if (big_num_opt == 0) /* User passed --no-big-num */ | ||
| 747 | big_num = false; | ||
| 748 | |||
| 560 | if (!argc && target_pid == -1 && target_tid == -1) | 749 | if (!argc && target_pid == -1 && target_tid == -1) |
| 561 | usage_with_options(stat_usage, options); | 750 | usage_with_options(stat_usage, options); |
| 562 | if (run_count <= 0) | 751 | if (run_count <= 0) |
| 563 | usage_with_options(stat_usage, options); | 752 | usage_with_options(stat_usage, options); |
| 564 | 753 | ||
| 754 | /* no_aggr is for system-wide only */ | ||
| 755 | if (no_aggr && !system_wide) | ||
| 756 | usage_with_options(stat_usage, options); | ||
| 757 | |||
| 565 | /* Set attrs and nr_counters if no event is selected and !null_run */ | 758 | /* Set attrs and nr_counters if no event is selected and !null_run */ |
| 566 | if (!null_run && !nr_counters) { | 759 | if (!null_run && !nr_counters) { |
| 567 | memcpy(attrs, default_attrs, sizeof(default_attrs)); | 760 | memcpy(attrs, default_attrs, sizeof(default_attrs)); |
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 9bcc38f0b706..d2fc46103f83 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
| @@ -272,19 +272,22 @@ static int cpus_cstate_state[MAX_CPUS]; | |||
| 272 | static u64 cpus_pstate_start_times[MAX_CPUS]; | 272 | static u64 cpus_pstate_start_times[MAX_CPUS]; |
| 273 | static u64 cpus_pstate_state[MAX_CPUS]; | 273 | static u64 cpus_pstate_state[MAX_CPUS]; |
| 274 | 274 | ||
| 275 | static int process_comm_event(event_t *event, struct perf_session *session __used) | 275 | static int process_comm_event(event_t *event, struct sample_data *sample __used, |
| 276 | struct perf_session *session __used) | ||
| 276 | { | 277 | { |
| 277 | pid_set_comm(event->comm.tid, event->comm.comm); | 278 | pid_set_comm(event->comm.tid, event->comm.comm); |
| 278 | return 0; | 279 | return 0; |
| 279 | } | 280 | } |
| 280 | 281 | ||
| 281 | static int process_fork_event(event_t *event, struct perf_session *session __used) | 282 | static int process_fork_event(event_t *event, struct sample_data *sample __used, |
| 283 | struct perf_session *session __used) | ||
| 282 | { | 284 | { |
| 283 | pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); | 285 | pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); |
| 284 | return 0; | 286 | return 0; |
| 285 | } | 287 | } |
| 286 | 288 | ||
| 287 | static int process_exit_event(event_t *event, struct perf_session *session __used) | 289 | static int process_exit_event(event_t *event, struct sample_data *sample __used, |
| 290 | struct perf_session *session __used) | ||
| 288 | { | 291 | { |
| 289 | pid_exit(event->fork.pid, event->fork.time); | 292 | pid_exit(event->fork.pid, event->fork.time); |
| 290 | return 0; | 293 | return 0; |
| @@ -470,24 +473,21 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) | |||
| 470 | } | 473 | } |
| 471 | 474 | ||
| 472 | 475 | ||
| 473 | static int process_sample_event(event_t *event, struct perf_session *session) | 476 | static int process_sample_event(event_t *event __used, |
| 477 | struct sample_data *sample, | ||
| 478 | struct perf_session *session) | ||
| 474 | { | 479 | { |
| 475 | struct sample_data data; | ||
| 476 | struct trace_entry *te; | 480 | struct trace_entry *te; |
| 477 | 481 | ||
| 478 | memset(&data, 0, sizeof(data)); | ||
| 479 | |||
| 480 | event__parse_sample(event, session->sample_type, &data); | ||
| 481 | |||
| 482 | if (session->sample_type & PERF_SAMPLE_TIME) { | 482 | if (session->sample_type & PERF_SAMPLE_TIME) { |
| 483 | if (!first_time || first_time > data.time) | 483 | if (!first_time || first_time > sample->time) |
| 484 | first_time = data.time; | 484 | first_time = sample->time; |
| 485 | if (last_time < data.time) | 485 | if (last_time < sample->time) |
| 486 | last_time = data.time; | 486 | last_time = sample->time; |
| 487 | } | 487 | } |
| 488 | 488 | ||
| 489 | te = (void *)data.raw_data; | 489 | te = (void *)sample->raw_data; |
| 490 | if (session->sample_type & PERF_SAMPLE_RAW && data.raw_size > 0) { | 490 | if (session->sample_type & PERF_SAMPLE_RAW && sample->raw_size > 0) { |
| 491 | char *event_str; | 491 | char *event_str; |
| 492 | struct power_entry *pe; | 492 | struct power_entry *pe; |
| 493 | 493 | ||
| @@ -499,19 +499,19 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
| 499 | return 0; | 499 | return 0; |
| 500 | 500 | ||
| 501 | if (strcmp(event_str, "power:power_start") == 0) | 501 | if (strcmp(event_str, "power:power_start") == 0) |
| 502 | c_state_start(pe->cpu_id, data.time, pe->value); | 502 | c_state_start(pe->cpu_id, sample->time, pe->value); |
| 503 | 503 | ||
| 504 | if (strcmp(event_str, "power:power_end") == 0) | 504 | if (strcmp(event_str, "power:power_end") == 0) |
| 505 | c_state_end(pe->cpu_id, data.time); | 505 | c_state_end(pe->cpu_id, sample->time); |
| 506 | 506 | ||
| 507 | if (strcmp(event_str, "power:power_frequency") == 0) | 507 | if (strcmp(event_str, "power:power_frequency") == 0) |
| 508 | p_state_change(pe->cpu_id, data.time, pe->value); | 508 | p_state_change(pe->cpu_id, sample->time, pe->value); |
| 509 | 509 | ||
| 510 | if (strcmp(event_str, "sched:sched_wakeup") == 0) | 510 | if (strcmp(event_str, "sched:sched_wakeup") == 0) |
| 511 | sched_wakeup(data.cpu, data.time, data.pid, te); | 511 | sched_wakeup(sample->cpu, sample->time, sample->pid, te); |
| 512 | 512 | ||
| 513 | if (strcmp(event_str, "sched:sched_switch") == 0) | 513 | if (strcmp(event_str, "sched:sched_switch") == 0) |
| 514 | sched_switch(data.cpu, data.time, te); | 514 | sched_switch(sample->cpu, sample->time, te); |
| 515 | } | 515 | } |
| 516 | return 0; | 516 | return 0; |
| 517 | } | 517 | } |
| @@ -989,6 +989,9 @@ static int __cmd_record(int argc, const char **argv) | |||
| 989 | rec_argc = ARRAY_SIZE(record_args) + argc - 1; | 989 | rec_argc = ARRAY_SIZE(record_args) + argc - 1; |
| 990 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 990 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
| 991 | 991 | ||
| 992 | if (rec_argv == NULL) | ||
| 993 | return -ENOMEM; | ||
| 994 | |||
| 992 | for (i = 0; i < ARRAY_SIZE(record_args); i++) | 995 | for (i = 0; i < ARRAY_SIZE(record_args); i++) |
| 993 | rec_argv[i] = strdup(record_args[i]); | 996 | rec_argv[i] = strdup(record_args[i]); |
| 994 | 997 | ||
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index dd625808c2a5..0515ce9d3d3e 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -977,12 +977,12 @@ static int symbol_filter(struct map *map, struct symbol *sym) | |||
| 977 | } | 977 | } |
| 978 | 978 | ||
| 979 | static void event__process_sample(const event_t *self, | 979 | static void event__process_sample(const event_t *self, |
| 980 | struct perf_session *session, int counter) | 980 | struct sample_data *sample, |
| 981 | struct perf_session *session, int counter) | ||
| 981 | { | 982 | { |
| 982 | u64 ip = self->ip.ip; | 983 | u64 ip = self->ip.ip; |
| 983 | struct sym_entry *syme; | 984 | struct sym_entry *syme; |
| 984 | struct addr_location al; | 985 | struct addr_location al; |
| 985 | struct sample_data data; | ||
| 986 | struct machine *machine; | 986 | struct machine *machine; |
| 987 | u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 987 | u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
| 988 | 988 | ||
| @@ -1025,7 +1025,7 @@ static void event__process_sample(const event_t *self, | |||
| 1025 | if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) | 1025 | if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) |
| 1026 | exact_samples++; | 1026 | exact_samples++; |
| 1027 | 1027 | ||
| 1028 | if (event__preprocess_sample(self, session, &al, &data, | 1028 | if (event__preprocess_sample(self, session, &al, sample, |
| 1029 | symbol_filter) < 0 || | 1029 | symbol_filter) < 0 || |
| 1030 | al.filtered) | 1030 | al.filtered) |
| 1031 | return; | 1031 | return; |
| @@ -1105,6 +1105,7 @@ static void perf_session__mmap_read_counter(struct perf_session *self, | |||
| 1105 | unsigned int head = mmap_read_head(md); | 1105 | unsigned int head = mmap_read_head(md); |
| 1106 | unsigned int old = md->prev; | 1106 | unsigned int old = md->prev; |
| 1107 | unsigned char *data = md->base + page_size; | 1107 | unsigned char *data = md->base + page_size; |
| 1108 | struct sample_data sample; | ||
| 1108 | int diff; | 1109 | int diff; |
| 1109 | 1110 | ||
| 1110 | /* | 1111 | /* |
| @@ -1152,10 +1153,11 @@ static void perf_session__mmap_read_counter(struct perf_session *self, | |||
| 1152 | event = &event_copy; | 1153 | event = &event_copy; |
| 1153 | } | 1154 | } |
| 1154 | 1155 | ||
| 1156 | event__parse_sample(event, self, &sample); | ||
| 1155 | if (event->header.type == PERF_RECORD_SAMPLE) | 1157 | if (event->header.type == PERF_RECORD_SAMPLE) |
| 1156 | event__process_sample(event, self, md->counter); | 1158 | event__process_sample(event, &sample, self, md->counter); |
| 1157 | else | 1159 | else |
| 1158 | event__process(event, self); | 1160 | event__process(event, &sample, self); |
| 1159 | old += size; | 1161 | old += size; |
| 1160 | } | 1162 | } |
| 1161 | 1163 | ||
| @@ -1214,7 +1216,9 @@ try_again: | |||
| 1214 | int err = errno; | 1216 | int err = errno; |
| 1215 | 1217 | ||
| 1216 | if (err == EPERM || err == EACCES) | 1218 | if (err == EPERM || err == EACCES) |
| 1217 | die("No permission - are you root?\n"); | 1219 | die("Permission error - are you root?\n" |
| 1220 | "\t Consider tweaking" | ||
| 1221 | " /proc/sys/kernel/perf_event_paranoid.\n"); | ||
| 1218 | /* | 1222 | /* |
| 1219 | * If it's cycles then fall back to hrtimer | 1223 | * If it's cycles then fall back to hrtimer |
| 1220 | * based cpu-clock-tick sw counter, which | 1224 | * based cpu-clock-tick sw counter, which |
| @@ -1231,7 +1235,7 @@ try_again: | |||
| 1231 | goto try_again; | 1235 | goto try_again; |
| 1232 | } | 1236 | } |
| 1233 | printf("\n"); | 1237 | printf("\n"); |
| 1234 | error("perfcounter syscall returned with %d (%s)\n", | 1238 | error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", |
| 1235 | fd[i][counter][thread_index], strerror(err)); | 1239 | fd[i][counter][thread_index], strerror(err)); |
| 1236 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); | 1240 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); |
| 1237 | exit(-1); | 1241 | exit(-1); |
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h index 921245b28583..c7798c7f24ed 100644 --- a/tools/perf/builtin.h +++ b/tools/perf/builtin.h | |||
| @@ -27,7 +27,7 @@ extern int cmd_report(int argc, const char **argv, const char *prefix); | |||
| 27 | extern int cmd_stat(int argc, const char **argv, const char *prefix); | 27 | extern int cmd_stat(int argc, const char **argv, const char *prefix); |
| 28 | extern int cmd_timechart(int argc, const char **argv, const char *prefix); | 28 | extern int cmd_timechart(int argc, const char **argv, const char *prefix); |
| 29 | extern int cmd_top(int argc, const char **argv, const char *prefix); | 29 | extern int cmd_top(int argc, const char **argv, const char *prefix); |
| 30 | extern int cmd_trace(int argc, const char **argv, const char *prefix); | 30 | extern int cmd_script(int argc, const char **argv, const char *prefix); |
| 31 | extern int cmd_version(int argc, const char **argv, const char *prefix); | 31 | extern int cmd_version(int argc, const char **argv, const char *prefix); |
| 32 | extern int cmd_probe(int argc, const char **argv, const char *prefix); | 32 | extern int cmd_probe(int argc, const char **argv, const char *prefix); |
| 33 | extern int cmd_kmem(int argc, const char **argv, const char *prefix); | 33 | extern int cmd_kmem(int argc, const char **argv, const char *prefix); |
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt index 949d77fc0b97..16b5088cf8f4 100644 --- a/tools/perf/command-list.txt +++ b/tools/perf/command-list.txt | |||
| @@ -16,7 +16,7 @@ perf-report mainporcelain common | |||
| 16 | perf-stat mainporcelain common | 16 | perf-stat mainporcelain common |
| 17 | perf-timechart mainporcelain common | 17 | perf-timechart mainporcelain common |
| 18 | perf-top mainporcelain common | 18 | perf-top mainporcelain common |
| 19 | perf-trace mainporcelain common | 19 | perf-script mainporcelain common |
| 20 | perf-probe mainporcelain common | 20 | perf-probe mainporcelain common |
| 21 | perf-kmem mainporcelain common | 21 | perf-kmem mainporcelain common |
| 22 | perf-lock mainporcelain common | 22 | perf-lock mainporcelain common |
diff --git a/tools/perf/feature-tests.mak b/tools/perf/feature-tests.mak index b253db634f04..b041ca67a2cb 100644 --- a/tools/perf/feature-tests.mak +++ b/tools/perf/feature-tests.mak | |||
| @@ -9,8 +9,8 @@ endef | |||
| 9 | ifndef NO_DWARF | 9 | ifndef NO_DWARF |
| 10 | define SOURCE_DWARF | 10 | define SOURCE_DWARF |
| 11 | #include <dwarf.h> | 11 | #include <dwarf.h> |
| 12 | #include <libdw.h> | 12 | #include <elfutils/libdw.h> |
| 13 | #include <version.h> | 13 | #include <elfutils/version.h> |
| 14 | #ifndef _ELFUTILS_PREREQ | 14 | #ifndef _ELFUTILS_PREREQ |
| 15 | #error | 15 | #error |
| 16 | #endif | 16 | #endif |
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index cdd6c03f1e14..595d0f4a7103 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
| @@ -323,7 +323,7 @@ static void handle_internal_command(int argc, const char **argv) | |||
| 323 | { "top", cmd_top, 0 }, | 323 | { "top", cmd_top, 0 }, |
| 324 | { "annotate", cmd_annotate, 0 }, | 324 | { "annotate", cmd_annotate, 0 }, |
| 325 | { "version", cmd_version, 0 }, | 325 | { "version", cmd_version, 0 }, |
| 326 | { "trace", cmd_trace, 0 }, | 326 | { "script", cmd_script, 0 }, |
| 327 | { "sched", cmd_sched, 0 }, | 327 | { "sched", cmd_sched, 0 }, |
| 328 | { "probe", cmd_probe, 0 }, | 328 | { "probe", cmd_probe, 0 }, |
| 329 | { "kmem", cmd_kmem, 0 }, | 329 | { "kmem", cmd_kmem, 0 }, |
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Context.c b/tools/perf/scripts/python/Perf-Trace-Util/Context.c index 957085dd5d8d..315067b8f552 100644 --- a/tools/perf/scripts/python/Perf-Trace-Util/Context.c +++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Context.c. Python interfaces for perf trace. | 2 | * Context.c. Python interfaces for perf script. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2010 Tom Zanussi <tzanussi@gmail.com> | 4 | * Copyright (C) 2010 Tom Zanussi <tzanussi@gmail.com> |
| 5 | * | 5 | * |
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index e437edb72417..deffb8c96071 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c | |||
| @@ -14,7 +14,9 @@ | |||
| 14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
| 15 | #include "debug.h" | 15 | #include "debug.h" |
| 16 | 16 | ||
| 17 | static int build_id__mark_dso_hit(event_t *event, struct perf_session *session) | 17 | static int build_id__mark_dso_hit(event_t *event, |
| 18 | struct sample_data *sample __used, | ||
| 19 | struct perf_session *session) | ||
| 18 | { | 20 | { |
| 19 | struct addr_location al; | 21 | struct addr_location al; |
| 20 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 22 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
| @@ -35,7 +37,8 @@ static int build_id__mark_dso_hit(event_t *event, struct perf_session *session) | |||
| 35 | return 0; | 37 | return 0; |
| 36 | } | 38 | } |
| 37 | 39 | ||
| 38 | static int event__exit_del_thread(event_t *self, struct perf_session *session) | 40 | static int event__exit_del_thread(event_t *self, struct sample_data *sample __used, |
| 41 | struct perf_session *session) | ||
| 39 | { | 42 | { |
| 40 | struct thread *thread = perf_session__findnew(session, self->fork.tid); | 43 | struct thread *thread = perf_session__findnew(session, self->fork.tid); |
| 41 | 44 | ||
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index c8d81b00089d..01bbe8ecec3f 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c | |||
| @@ -46,20 +46,16 @@ int dump_printf(const char *fmt, ...) | |||
| 46 | return ret; | 46 | return ret; |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | static int dump_printf_color(const char *fmt, const char *color, ...) | 49 | #ifdef NO_NEWT_SUPPORT |
| 50 | void ui__warning(const char *format, ...) | ||
| 50 | { | 51 | { |
| 51 | va_list args; | 52 | va_list args; |
| 52 | int ret = 0; | ||
| 53 | 53 | ||
| 54 | if (dump_trace) { | 54 | va_start(args, format); |
| 55 | va_start(args, color); | 55 | vfprintf(stderr, format, args); |
| 56 | ret = color_vfprintf(stdout, color, fmt, args); | 56 | va_end(args); |
| 57 | va_end(args); | ||
| 58 | } | ||
| 59 | |||
| 60 | return ret; | ||
| 61 | } | 57 | } |
| 62 | 58 | #endif | |
| 63 | 59 | ||
| 64 | void trace_event(event_t *event) | 60 | void trace_event(event_t *event) |
| 65 | { | 61 | { |
| @@ -70,29 +66,29 @@ void trace_event(event_t *event) | |||
| 70 | if (!dump_trace) | 66 | if (!dump_trace) |
| 71 | return; | 67 | return; |
| 72 | 68 | ||
| 73 | dump_printf("."); | 69 | printf("."); |
| 74 | dump_printf_color("\n. ... raw event: size %d bytes\n", color, | 70 | color_fprintf(stdout, color, "\n. ... raw event: size %d bytes\n", |
| 75 | event->header.size); | 71 | event->header.size); |
| 76 | 72 | ||
| 77 | for (i = 0; i < event->header.size; i++) { | 73 | for (i = 0; i < event->header.size; i++) { |
| 78 | if ((i & 15) == 0) { | 74 | if ((i & 15) == 0) { |
| 79 | dump_printf("."); | 75 | printf("."); |
| 80 | dump_printf_color(" %04x: ", color, i); | 76 | color_fprintf(stdout, color, " %04x: ", i); |
| 81 | } | 77 | } |
| 82 | 78 | ||
| 83 | dump_printf_color(" %02x", color, raw_event[i]); | 79 | color_fprintf(stdout, color, " %02x", raw_event[i]); |
| 84 | 80 | ||
| 85 | if (((i & 15) == 15) || i == event->header.size-1) { | 81 | if (((i & 15) == 15) || i == event->header.size-1) { |
| 86 | dump_printf_color(" ", color); | 82 | color_fprintf(stdout, color, " "); |
| 87 | for (j = 0; j < 15-(i & 15); j++) | 83 | for (j = 0; j < 15-(i & 15); j++) |
| 88 | dump_printf_color(" ", color); | 84 | color_fprintf(stdout, color, " "); |
| 89 | for (j = i & ~15; j <= i; j++) { | 85 | for (j = i & ~15; j <= i; j++) { |
| 90 | dump_printf_color("%c", color, | 86 | color_fprintf(stdout, color, "%c", |
| 91 | isprint(raw_event[j]) ? | 87 | isprint(raw_event[j]) ? |
| 92 | raw_event[j] : '.'); | 88 | raw_event[j] : '.'); |
| 93 | } | 89 | } |
| 94 | dump_printf_color("\n", color); | 90 | color_fprintf(stdout, color, "\n"); |
| 95 | } | 91 | } |
| 96 | } | 92 | } |
| 97 | dump_printf(".\n"); | 93 | printf(".\n"); |
| 98 | } | 94 | } |
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 7b514082bbaf..ca35fd66b5df 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
| @@ -35,4 +35,6 @@ int ui_helpline__show_help(const char *format, va_list ap); | |||
| 35 | #include "ui/progress.h" | 35 | #include "ui/progress.h" |
| 36 | #endif | 36 | #endif |
| 37 | 37 | ||
| 38 | void ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); | ||
| 39 | |||
| 38 | #endif /* __PERF_DEBUG_H */ | 40 | #endif /* __PERF_DEBUG_H */ |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index dab9e754a281..183aedd4db83 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | #include "strlist.h" | 7 | #include "strlist.h" |
| 8 | #include "thread.h" | 8 | #include "thread.h" |
| 9 | 9 | ||
| 10 | const char *event__name[] = { | 10 | static const char *event__name[] = { |
| 11 | [0] = "TOTAL", | 11 | [0] = "TOTAL", |
| 12 | [PERF_RECORD_MMAP] = "MMAP", | 12 | [PERF_RECORD_MMAP] = "MMAP", |
| 13 | [PERF_RECORD_LOST] = "LOST", | 13 | [PERF_RECORD_LOST] = "LOST", |
| @@ -22,13 +22,31 @@ const char *event__name[] = { | |||
| 22 | [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE", | 22 | [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE", |
| 23 | [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", | 23 | [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", |
| 24 | [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID", | 24 | [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID", |
| 25 | [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND", | ||
| 25 | }; | 26 | }; |
| 26 | 27 | ||
| 27 | static pid_t event__synthesize_comm(pid_t pid, int full, | 28 | const char *event__get_event_name(unsigned int id) |
| 29 | { | ||
| 30 | if (id >= ARRAY_SIZE(event__name)) | ||
| 31 | return "INVALID"; | ||
| 32 | if (!event__name[id]) | ||
| 33 | return "UNKNOWN"; | ||
| 34 | return event__name[id]; | ||
| 35 | } | ||
| 36 | |||
| 37 | static struct sample_data synth_sample = { | ||
| 38 | .pid = -1, | ||
| 39 | .tid = -1, | ||
| 40 | .time = -1, | ||
| 41 | .stream_id = -1, | ||
| 42 | .cpu = -1, | ||
| 43 | .period = 1, | ||
| 44 | }; | ||
| 45 | |||
| 46 | static pid_t event__synthesize_comm(event_t *event, pid_t pid, int full, | ||
| 28 | event__handler_t process, | 47 | event__handler_t process, |
| 29 | struct perf_session *session) | 48 | struct perf_session *session) |
| 30 | { | 49 | { |
| 31 | event_t ev; | ||
| 32 | char filename[PATH_MAX]; | 50 | char filename[PATH_MAX]; |
| 33 | char bf[BUFSIZ]; | 51 | char bf[BUFSIZ]; |
| 34 | FILE *fp; | 52 | FILE *fp; |
| @@ -49,34 +67,39 @@ out_race: | |||
| 49 | return 0; | 67 | return 0; |
| 50 | } | 68 | } |
| 51 | 69 | ||
| 52 | memset(&ev.comm, 0, sizeof(ev.comm)); | 70 | memset(&event->comm, 0, sizeof(event->comm)); |
| 53 | while (!ev.comm.comm[0] || !ev.comm.pid) { | 71 | |
| 54 | if (fgets(bf, sizeof(bf), fp) == NULL) | 72 | while (!event->comm.comm[0] || !event->comm.pid) { |
| 55 | goto out_failure; | 73 | if (fgets(bf, sizeof(bf), fp) == NULL) { |
| 74 | pr_warning("couldn't get COMM and pgid, malformed %s\n", filename); | ||
| 75 | goto out; | ||
| 76 | } | ||
| 56 | 77 | ||
| 57 | if (memcmp(bf, "Name:", 5) == 0) { | 78 | if (memcmp(bf, "Name:", 5) == 0) { |
| 58 | char *name = bf + 5; | 79 | char *name = bf + 5; |
| 59 | while (*name && isspace(*name)) | 80 | while (*name && isspace(*name)) |
| 60 | ++name; | 81 | ++name; |
| 61 | size = strlen(name) - 1; | 82 | size = strlen(name) - 1; |
| 62 | memcpy(ev.comm.comm, name, size++); | 83 | memcpy(event->comm.comm, name, size++); |
| 63 | } else if (memcmp(bf, "Tgid:", 5) == 0) { | 84 | } else if (memcmp(bf, "Tgid:", 5) == 0) { |
| 64 | char *tgids = bf + 5; | 85 | char *tgids = bf + 5; |
| 65 | while (*tgids && isspace(*tgids)) | 86 | while (*tgids && isspace(*tgids)) |
| 66 | ++tgids; | 87 | ++tgids; |
| 67 | tgid = ev.comm.pid = atoi(tgids); | 88 | tgid = event->comm.pid = atoi(tgids); |
| 68 | } | 89 | } |
| 69 | } | 90 | } |
| 70 | 91 | ||
| 71 | ev.comm.header.type = PERF_RECORD_COMM; | 92 | event->comm.header.type = PERF_RECORD_COMM; |
| 72 | size = ALIGN(size, sizeof(u64)); | 93 | size = ALIGN(size, sizeof(u64)); |
| 73 | ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size); | 94 | memset(event->comm.comm + size, 0, session->id_hdr_size); |
| 74 | 95 | event->comm.header.size = (sizeof(event->comm) - | |
| 96 | (sizeof(event->comm.comm) - size) + | ||
| 97 | session->id_hdr_size); | ||
| 75 | if (!full) { | 98 | if (!full) { |
| 76 | ev.comm.tid = pid; | 99 | event->comm.tid = pid; |
| 77 | 100 | ||
| 78 | process(&ev, session); | 101 | process(event, &synth_sample, session); |
| 79 | goto out_fclose; | 102 | goto out; |
| 80 | } | 103 | } |
| 81 | 104 | ||
| 82 | snprintf(filename, sizeof(filename), "/proc/%d/task", pid); | 105 | snprintf(filename, sizeof(filename), "/proc/%d/task", pid); |
| @@ -91,22 +114,19 @@ out_race: | |||
| 91 | if (*end) | 114 | if (*end) |
| 92 | continue; | 115 | continue; |
| 93 | 116 | ||
| 94 | ev.comm.tid = pid; | 117 | event->comm.tid = pid; |
| 95 | 118 | ||
| 96 | process(&ev, session); | 119 | process(event, &synth_sample, session); |
| 97 | } | 120 | } |
| 98 | closedir(tasks); | ||
| 99 | 121 | ||
| 100 | out_fclose: | 122 | closedir(tasks); |
| 123 | out: | ||
| 101 | fclose(fp); | 124 | fclose(fp); |
| 102 | return tgid; | ||
| 103 | 125 | ||
| 104 | out_failure: | 126 | return tgid; |
| 105 | pr_warning("couldn't get COMM and pgid, malformed %s\n", filename); | ||
| 106 | return -1; | ||
| 107 | } | 127 | } |
| 108 | 128 | ||
| 109 | static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, | 129 | static int event__synthesize_mmap_events(event_t *event, pid_t pid, pid_t tgid, |
| 110 | event__handler_t process, | 130 | event__handler_t process, |
| 111 | struct perf_session *session) | 131 | struct perf_session *session) |
| 112 | { | 132 | { |
| @@ -124,29 +144,25 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, | |||
| 124 | return -1; | 144 | return -1; |
| 125 | } | 145 | } |
| 126 | 146 | ||
| 147 | event->header.type = PERF_RECORD_MMAP; | ||
| 148 | /* | ||
| 149 | * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c | ||
| 150 | */ | ||
| 151 | event->header.misc = PERF_RECORD_MISC_USER; | ||
| 152 | |||
| 127 | while (1) { | 153 | while (1) { |
| 128 | char bf[BUFSIZ], *pbf = bf; | 154 | char bf[BUFSIZ], *pbf = bf; |
| 129 | event_t ev = { | ||
| 130 | .header = { | ||
| 131 | .type = PERF_RECORD_MMAP, | ||
| 132 | /* | ||
| 133 | * Just like the kernel, see __perf_event_mmap | ||
| 134 | * in kernel/perf_event.c | ||
| 135 | */ | ||
| 136 | .misc = PERF_RECORD_MISC_USER, | ||
| 137 | }, | ||
| 138 | }; | ||
| 139 | int n; | 155 | int n; |
| 140 | size_t size; | 156 | size_t size; |
| 141 | if (fgets(bf, sizeof(bf), fp) == NULL) | 157 | if (fgets(bf, sizeof(bf), fp) == NULL) |
| 142 | break; | 158 | break; |
| 143 | 159 | ||
| 144 | /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ | 160 | /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ |
| 145 | n = hex2u64(pbf, &ev.mmap.start); | 161 | n = hex2u64(pbf, &event->mmap.start); |
| 146 | if (n < 0) | 162 | if (n < 0) |
| 147 | continue; | 163 | continue; |
| 148 | pbf += n + 1; | 164 | pbf += n + 1; |
| 149 | n = hex2u64(pbf, &ev.mmap.len); | 165 | n = hex2u64(pbf, &event->mmap.len); |
| 150 | if (n < 0) | 166 | if (n < 0) |
| 151 | continue; | 167 | continue; |
| 152 | pbf += n + 3; | 168 | pbf += n + 3; |
| @@ -161,19 +177,21 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, | |||
| 161 | continue; | 177 | continue; |
| 162 | 178 | ||
| 163 | pbf += 3; | 179 | pbf += 3; |
| 164 | n = hex2u64(pbf, &ev.mmap.pgoff); | 180 | n = hex2u64(pbf, &event->mmap.pgoff); |
| 165 | 181 | ||
| 166 | size = strlen(execname); | 182 | size = strlen(execname); |
| 167 | execname[size - 1] = '\0'; /* Remove \n */ | 183 | execname[size - 1] = '\0'; /* Remove \n */ |
| 168 | memcpy(ev.mmap.filename, execname, size); | 184 | memcpy(event->mmap.filename, execname, size); |
| 169 | size = ALIGN(size, sizeof(u64)); | 185 | size = ALIGN(size, sizeof(u64)); |
| 170 | ev.mmap.len -= ev.mmap.start; | 186 | event->mmap.len -= event->mmap.start; |
| 171 | ev.mmap.header.size = (sizeof(ev.mmap) - | 187 | event->mmap.header.size = (sizeof(event->mmap) - |
| 172 | (sizeof(ev.mmap.filename) - size)); | 188 | (sizeof(event->mmap.filename) - size)); |
| 173 | ev.mmap.pid = tgid; | 189 | memset(event->mmap.filename + size, 0, session->id_hdr_size); |
| 174 | ev.mmap.tid = pid; | 190 | event->mmap.header.size += session->id_hdr_size; |
| 175 | 191 | event->mmap.pid = tgid; | |
| 176 | process(&ev, session); | 192 | event->mmap.tid = pid; |
| 193 | |||
| 194 | process(event, &synth_sample, session); | ||
| 177 | } | 195 | } |
| 178 | } | 196 | } |
| 179 | 197 | ||
| @@ -187,20 +205,27 @@ int event__synthesize_modules(event__handler_t process, | |||
| 187 | { | 205 | { |
| 188 | struct rb_node *nd; | 206 | struct rb_node *nd; |
| 189 | struct map_groups *kmaps = &machine->kmaps; | 207 | struct map_groups *kmaps = &machine->kmaps; |
| 190 | u16 misc; | 208 | event_t *event = zalloc(sizeof(event->mmap) + session->id_hdr_size); |
| 209 | |||
| 210 | if (event == NULL) { | ||
| 211 | pr_debug("Not enough memory synthesizing mmap event " | ||
| 212 | "for kernel modules\n"); | ||
| 213 | return -1; | ||
| 214 | } | ||
| 215 | |||
| 216 | event->header.type = PERF_RECORD_MMAP; | ||
| 191 | 217 | ||
| 192 | /* | 218 | /* |
| 193 | * kernel uses 0 for user space maps, see kernel/perf_event.c | 219 | * kernel uses 0 for user space maps, see kernel/perf_event.c |
| 194 | * __perf_event_mmap | 220 | * __perf_event_mmap |
| 195 | */ | 221 | */ |
| 196 | if (machine__is_host(machine)) | 222 | if (machine__is_host(machine)) |
| 197 | misc = PERF_RECORD_MISC_KERNEL; | 223 | event->header.misc = PERF_RECORD_MISC_KERNEL; |
| 198 | else | 224 | else |
| 199 | misc = PERF_RECORD_MISC_GUEST_KERNEL; | 225 | event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; |
| 200 | 226 | ||
| 201 | for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]); | 227 | for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]); |
| 202 | nd; nd = rb_next(nd)) { | 228 | nd; nd = rb_next(nd)) { |
| 203 | event_t ev; | ||
| 204 | size_t size; | 229 | size_t size; |
| 205 | struct map *pos = rb_entry(nd, struct map, rb_node); | 230 | struct map *pos = rb_entry(nd, struct map, rb_node); |
| 206 | 231 | ||
| @@ -208,39 +233,78 @@ int event__synthesize_modules(event__handler_t process, | |||
| 208 | continue; | 233 | continue; |
| 209 | 234 | ||
| 210 | size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); | 235 | size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); |
| 211 | memset(&ev, 0, sizeof(ev)); | 236 | event->mmap.header.type = PERF_RECORD_MMAP; |
| 212 | ev.mmap.header.misc = misc; | 237 | event->mmap.header.size = (sizeof(event->mmap) - |
| 213 | ev.mmap.header.type = PERF_RECORD_MMAP; | 238 | (sizeof(event->mmap.filename) - size)); |
| 214 | ev.mmap.header.size = (sizeof(ev.mmap) - | 239 | memset(event->mmap.filename + size, 0, session->id_hdr_size); |
| 215 | (sizeof(ev.mmap.filename) - size)); | 240 | event->mmap.header.size += session->id_hdr_size; |
| 216 | ev.mmap.start = pos->start; | 241 | event->mmap.start = pos->start; |
| 217 | ev.mmap.len = pos->end - pos->start; | 242 | event->mmap.len = pos->end - pos->start; |
| 218 | ev.mmap.pid = machine->pid; | 243 | event->mmap.pid = machine->pid; |
| 219 | 244 | ||
| 220 | memcpy(ev.mmap.filename, pos->dso->long_name, | 245 | memcpy(event->mmap.filename, pos->dso->long_name, |
| 221 | pos->dso->long_name_len + 1); | 246 | pos->dso->long_name_len + 1); |
| 222 | process(&ev, session); | 247 | process(event, &synth_sample, session); |
| 223 | } | 248 | } |
| 224 | 249 | ||
| 250 | free(event); | ||
| 225 | return 0; | 251 | return 0; |
| 226 | } | 252 | } |
| 227 | 253 | ||
| 228 | int event__synthesize_thread(pid_t pid, event__handler_t process, | 254 | static int __event__synthesize_thread(event_t *comm_event, event_t *mmap_event, |
| 229 | struct perf_session *session) | 255 | pid_t pid, event__handler_t process, |
| 256 | struct perf_session *session) | ||
| 230 | { | 257 | { |
| 231 | pid_t tgid = event__synthesize_comm(pid, 1, process, session); | 258 | pid_t tgid = event__synthesize_comm(comm_event, pid, 1, process, |
| 259 | session); | ||
| 232 | if (tgid == -1) | 260 | if (tgid == -1) |
| 233 | return -1; | 261 | return -1; |
| 234 | return event__synthesize_mmap_events(pid, tgid, process, session); | 262 | return event__synthesize_mmap_events(mmap_event, pid, tgid, |
| 263 | process, session); | ||
| 264 | } | ||
| 265 | |||
| 266 | int event__synthesize_thread(pid_t pid, event__handler_t process, | ||
| 267 | struct perf_session *session) | ||
| 268 | { | ||
| 269 | event_t *comm_event, *mmap_event; | ||
| 270 | int err = -1; | ||
| 271 | |||
| 272 | comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size); | ||
| 273 | if (comm_event == NULL) | ||
| 274 | goto out; | ||
| 275 | |||
| 276 | mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size); | ||
| 277 | if (mmap_event == NULL) | ||
| 278 | goto out_free_comm; | ||
| 279 | |||
| 280 | err = __event__synthesize_thread(comm_event, mmap_event, pid, | ||
| 281 | process, session); | ||
| 282 | free(mmap_event); | ||
| 283 | out_free_comm: | ||
| 284 | free(comm_event); | ||
| 285 | out: | ||
| 286 | return err; | ||
| 235 | } | 287 | } |
| 236 | 288 | ||
| 237 | void event__synthesize_threads(event__handler_t process, | 289 | int event__synthesize_threads(event__handler_t process, |
| 238 | struct perf_session *session) | 290 | struct perf_session *session) |
| 239 | { | 291 | { |
| 240 | DIR *proc; | 292 | DIR *proc; |
| 241 | struct dirent dirent, *next; | 293 | struct dirent dirent, *next; |
| 294 | event_t *comm_event, *mmap_event; | ||
| 295 | int err = -1; | ||
| 296 | |||
| 297 | comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size); | ||
| 298 | if (comm_event == NULL) | ||
| 299 | goto out; | ||
| 300 | |||
| 301 | mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size); | ||
| 302 | if (mmap_event == NULL) | ||
| 303 | goto out_free_comm; | ||
| 242 | 304 | ||
| 243 | proc = opendir("/proc"); | 305 | proc = opendir("/proc"); |
| 306 | if (proc == NULL) | ||
| 307 | goto out_free_mmap; | ||
| 244 | 308 | ||
| 245 | while (!readdir_r(proc, &dirent, &next) && next) { | 309 | while (!readdir_r(proc, &dirent, &next) && next) { |
| 246 | char *end; | 310 | char *end; |
| @@ -249,10 +313,18 @@ void event__synthesize_threads(event__handler_t process, | |||
| 249 | if (*end) /* only interested in proper numerical dirents */ | 313 | if (*end) /* only interested in proper numerical dirents */ |
| 250 | continue; | 314 | continue; |
| 251 | 315 | ||
| 252 | event__synthesize_thread(pid, process, session); | 316 | __event__synthesize_thread(comm_event, mmap_event, pid, |
| 317 | process, session); | ||
| 253 | } | 318 | } |
| 254 | 319 | ||
| 255 | closedir(proc); | 320 | closedir(proc); |
| 321 | err = 0; | ||
| 322 | out_free_mmap: | ||
| 323 | free(mmap_event); | ||
| 324 | out_free_comm: | ||
| 325 | free(comm_event); | ||
| 326 | out: | ||
| 327 | return err; | ||
| 256 | } | 328 | } |
| 257 | 329 | ||
| 258 | struct process_symbol_args { | 330 | struct process_symbol_args { |
| @@ -286,18 +358,20 @@ int event__synthesize_kernel_mmap(event__handler_t process, | |||
| 286 | char path[PATH_MAX]; | 358 | char path[PATH_MAX]; |
| 287 | char name_buff[PATH_MAX]; | 359 | char name_buff[PATH_MAX]; |
| 288 | struct map *map; | 360 | struct map *map; |
| 289 | 361 | int err; | |
| 290 | event_t ev = { | ||
| 291 | .header = { | ||
| 292 | .type = PERF_RECORD_MMAP, | ||
| 293 | }, | ||
| 294 | }; | ||
| 295 | /* | 362 | /* |
| 296 | * We should get this from /sys/kernel/sections/.text, but till that is | 363 | * We should get this from /sys/kernel/sections/.text, but till that is |
| 297 | * available use this, and after it is use this as a fallback for older | 364 | * available use this, and after it is use this as a fallback for older |
| 298 | * kernels. | 365 | * kernels. |
| 299 | */ | 366 | */ |
| 300 | struct process_symbol_args args = { .name = symbol_name, }; | 367 | struct process_symbol_args args = { .name = symbol_name, }; |
| 368 | event_t *event = zalloc(sizeof(event->mmap) + session->id_hdr_size); | ||
| 369 | |||
| 370 | if (event == NULL) { | ||
| 371 | pr_debug("Not enough memory synthesizing mmap event " | ||
| 372 | "for kernel modules\n"); | ||
| 373 | return -1; | ||
| 374 | } | ||
| 301 | 375 | ||
| 302 | mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff)); | 376 | mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff)); |
| 303 | if (machine__is_host(machine)) { | 377 | if (machine__is_host(machine)) { |
| @@ -305,10 +379,10 @@ int event__synthesize_kernel_mmap(event__handler_t process, | |||
| 305 | * kernel uses PERF_RECORD_MISC_USER for user space maps, | 379 | * kernel uses PERF_RECORD_MISC_USER for user space maps, |
| 306 | * see kernel/perf_event.c __perf_event_mmap | 380 | * see kernel/perf_event.c __perf_event_mmap |
| 307 | */ | 381 | */ |
| 308 | ev.header.misc = PERF_RECORD_MISC_KERNEL; | 382 | event->header.misc = PERF_RECORD_MISC_KERNEL; |
| 309 | filename = "/proc/kallsyms"; | 383 | filename = "/proc/kallsyms"; |
| 310 | } else { | 384 | } else { |
| 311 | ev.header.misc = PERF_RECORD_MISC_GUEST_KERNEL; | 385 | event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; |
| 312 | if (machine__is_default_guest(machine)) | 386 | if (machine__is_default_guest(machine)) |
| 313 | filename = (char *) symbol_conf.default_guest_kallsyms; | 387 | filename = (char *) symbol_conf.default_guest_kallsyms; |
| 314 | else { | 388 | else { |
| @@ -321,17 +395,21 @@ int event__synthesize_kernel_mmap(event__handler_t process, | |||
| 321 | return -ENOENT; | 395 | return -ENOENT; |
| 322 | 396 | ||
| 323 | map = machine->vmlinux_maps[MAP__FUNCTION]; | 397 | map = machine->vmlinux_maps[MAP__FUNCTION]; |
| 324 | size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename), | 398 | size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), |
| 325 | "%s%s", mmap_name, symbol_name) + 1; | 399 | "%s%s", mmap_name, symbol_name) + 1; |
| 326 | size = ALIGN(size, sizeof(u64)); | 400 | size = ALIGN(size, sizeof(u64)); |
| 327 | ev.mmap.header.size = (sizeof(ev.mmap) - | 401 | event->mmap.header.type = PERF_RECORD_MMAP; |
| 328 | (sizeof(ev.mmap.filename) - size)); | 402 | event->mmap.header.size = (sizeof(event->mmap) - |
| 329 | ev.mmap.pgoff = args.start; | 403 | (sizeof(event->mmap.filename) - size) + session->id_hdr_size); |
| 330 | ev.mmap.start = map->start; | 404 | event->mmap.pgoff = args.start; |
| 331 | ev.mmap.len = map->end - ev.mmap.start; | 405 | event->mmap.start = map->start; |
| 332 | ev.mmap.pid = machine->pid; | 406 | event->mmap.len = map->end - event->mmap.start; |
| 333 | 407 | event->mmap.pid = machine->pid; | |
| 334 | return process(&ev, session); | 408 | |
| 409 | err = process(event, &synth_sample, session); | ||
| 410 | free(event); | ||
| 411 | |||
| 412 | return err; | ||
| 335 | } | 413 | } |
| 336 | 414 | ||
| 337 | static void thread__comm_adjust(struct thread *self, struct hists *hists) | 415 | static void thread__comm_adjust(struct thread *self, struct hists *hists) |
| @@ -361,7 +439,8 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm, | |||
| 361 | return 0; | 439 | return 0; |
| 362 | } | 440 | } |
| 363 | 441 | ||
| 364 | int event__process_comm(event_t *self, struct perf_session *session) | 442 | int event__process_comm(event_t *self, struct sample_data *sample __used, |
| 443 | struct perf_session *session) | ||
| 365 | { | 444 | { |
| 366 | struct thread *thread = perf_session__findnew(session, self->comm.tid); | 445 | struct thread *thread = perf_session__findnew(session, self->comm.tid); |
| 367 | 446 | ||
| @@ -376,7 +455,8 @@ int event__process_comm(event_t *self, struct perf_session *session) | |||
| 376 | return 0; | 455 | return 0; |
| 377 | } | 456 | } |
| 378 | 457 | ||
| 379 | int event__process_lost(event_t *self, struct perf_session *session) | 458 | int event__process_lost(event_t *self, struct sample_data *sample __used, |
| 459 | struct perf_session *session) | ||
| 380 | { | 460 | { |
| 381 | dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost); | 461 | dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost); |
| 382 | session->hists.stats.total_lost += self->lost.lost; | 462 | session->hists.stats.total_lost += self->lost.lost; |
| @@ -392,7 +472,7 @@ static void event_set_kernel_mmap_len(struct map **maps, event_t *self) | |||
| 392 | * a zero sized synthesized MMAP event for the kernel. | 472 | * a zero sized synthesized MMAP event for the kernel. |
| 393 | */ | 473 | */ |
| 394 | if (maps[MAP__FUNCTION]->end == 0) | 474 | if (maps[MAP__FUNCTION]->end == 0) |
| 395 | maps[MAP__FUNCTION]->end = ~0UL; | 475 | maps[MAP__FUNCTION]->end = ~0ULL; |
| 396 | } | 476 | } |
| 397 | 477 | ||
| 398 | static int event__process_kernel_mmap(event_t *self, | 478 | static int event__process_kernel_mmap(event_t *self, |
| @@ -485,7 +565,8 @@ out_problem: | |||
| 485 | return -1; | 565 | return -1; |
| 486 | } | 566 | } |
| 487 | 567 | ||
| 488 | int event__process_mmap(event_t *self, struct perf_session *session) | 568 | int event__process_mmap(event_t *self, struct sample_data *sample __used, |
| 569 | struct perf_session *session) | ||
| 489 | { | 570 | { |
| 490 | struct machine *machine; | 571 | struct machine *machine; |
| 491 | struct thread *thread; | 572 | struct thread *thread; |
| @@ -526,7 +607,8 @@ out_problem: | |||
| 526 | return 0; | 607 | return 0; |
| 527 | } | 608 | } |
| 528 | 609 | ||
| 529 | int event__process_task(event_t *self, struct perf_session *session) | 610 | int event__process_task(event_t *self, struct sample_data *sample __used, |
| 611 | struct perf_session *session) | ||
| 530 | { | 612 | { |
| 531 | struct thread *thread = perf_session__findnew(session, self->fork.tid); | 613 | struct thread *thread = perf_session__findnew(session, self->fork.tid); |
| 532 | struct thread *parent = perf_session__findnew(session, self->fork.ptid); | 614 | struct thread *parent = perf_session__findnew(session, self->fork.ptid); |
| @@ -548,18 +630,19 @@ int event__process_task(event_t *self, struct perf_session *session) | |||
| 548 | return 0; | 630 | return 0; |
| 549 | } | 631 | } |
| 550 | 632 | ||
| 551 | int event__process(event_t *event, struct perf_session *session) | 633 | int event__process(event_t *event, struct sample_data *sample, |
| 634 | struct perf_session *session) | ||
| 552 | { | 635 | { |
| 553 | switch (event->header.type) { | 636 | switch (event->header.type) { |
| 554 | case PERF_RECORD_COMM: | 637 | case PERF_RECORD_COMM: |
| 555 | event__process_comm(event, session); | 638 | event__process_comm(event, sample, session); |
| 556 | break; | 639 | break; |
| 557 | case PERF_RECORD_MMAP: | 640 | case PERF_RECORD_MMAP: |
| 558 | event__process_mmap(event, session); | 641 | event__process_mmap(event, sample, session); |
| 559 | break; | 642 | break; |
| 560 | case PERF_RECORD_FORK: | 643 | case PERF_RECORD_FORK: |
| 561 | case PERF_RECORD_EXIT: | 644 | case PERF_RECORD_EXIT: |
| 562 | event__process_task(event, session); | 645 | event__process_task(event, sample, session); |
| 563 | break; | 646 | break; |
| 564 | default: | 647 | default: |
| 565 | break; | 648 | break; |
| @@ -674,32 +757,8 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session, | |||
| 674 | symbol_filter_t filter) | 757 | symbol_filter_t filter) |
| 675 | { | 758 | { |
| 676 | u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 759 | u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
| 677 | struct thread *thread; | 760 | struct thread *thread = perf_session__findnew(session, self->ip.pid); |
| 678 | |||
| 679 | event__parse_sample(self, session->sample_type, data); | ||
| 680 | |||
| 681 | dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld cpu:%d\n", | ||
| 682 | self->header.misc, data->pid, data->tid, data->ip, | ||
| 683 | data->period, data->cpu); | ||
| 684 | |||
| 685 | if (session->sample_type & PERF_SAMPLE_CALLCHAIN) { | ||
| 686 | unsigned int i; | ||
| 687 | |||
| 688 | dump_printf("... chain: nr:%Lu\n", data->callchain->nr); | ||
| 689 | 761 | ||
| 690 | if (!ip_callchain__valid(data->callchain, self)) { | ||
| 691 | pr_debug("call-chain problem with event, " | ||
| 692 | "skipping it.\n"); | ||
| 693 | goto out_filtered; | ||
| 694 | } | ||
| 695 | |||
| 696 | if (dump_trace) { | ||
| 697 | for (i = 0; i < data->callchain->nr; i++) | ||
| 698 | dump_printf("..... %2d: %016Lx\n", | ||
| 699 | i, data->callchain->ips[i]); | ||
| 700 | } | ||
| 701 | } | ||
| 702 | thread = perf_session__findnew(session, self->ip.pid); | ||
| 703 | if (thread == NULL) | 762 | if (thread == NULL) |
| 704 | return -1; | 763 | return -1; |
| 705 | 764 | ||
| @@ -766,9 +825,65 @@ out_filtered: | |||
| 766 | return 0; | 825 | return 0; |
| 767 | } | 826 | } |
| 768 | 827 | ||
| 769 | int event__parse_sample(const event_t *event, u64 type, struct sample_data *data) | 828 | static int event__parse_id_sample(const event_t *event, |
| 829 | struct perf_session *session, | ||
| 830 | struct sample_data *sample) | ||
| 770 | { | 831 | { |
| 771 | const u64 *array = event->sample.array; | 832 | const u64 *array; |
| 833 | u64 type; | ||
| 834 | |||
| 835 | sample->cpu = sample->pid = sample->tid = -1; | ||
| 836 | sample->stream_id = sample->id = sample->time = -1ULL; | ||
| 837 | |||
| 838 | if (!session->sample_id_all) | ||
| 839 | return 0; | ||
| 840 | |||
| 841 | array = event->sample.array; | ||
| 842 | array += ((event->header.size - | ||
| 843 | sizeof(event->header)) / sizeof(u64)) - 1; | ||
| 844 | type = session->sample_type; | ||
| 845 | |||
| 846 | if (type & PERF_SAMPLE_CPU) { | ||
| 847 | u32 *p = (u32 *)array; | ||
| 848 | sample->cpu = *p; | ||
| 849 | array--; | ||
| 850 | } | ||
| 851 | |||
| 852 | if (type & PERF_SAMPLE_STREAM_ID) { | ||
| 853 | sample->stream_id = *array; | ||
| 854 | array--; | ||
| 855 | } | ||
| 856 | |||
| 857 | if (type & PERF_SAMPLE_ID) { | ||
| 858 | sample->id = *array; | ||
| 859 | array--; | ||
| 860 | } | ||
| 861 | |||
| 862 | if (type & PERF_SAMPLE_TIME) { | ||
| 863 | sample->time = *array; | ||
| 864 | array--; | ||
| 865 | } | ||
| 866 | |||
| 867 | if (type & PERF_SAMPLE_TID) { | ||
| 868 | u32 *p = (u32 *)array; | ||
| 869 | sample->pid = p[0]; | ||
| 870 | sample->tid = p[1]; | ||
| 871 | } | ||
| 872 | |||
| 873 | return 0; | ||
| 874 | } | ||
| 875 | |||
| 876 | int event__parse_sample(const event_t *event, struct perf_session *session, | ||
| 877 | struct sample_data *data) | ||
| 878 | { | ||
| 879 | const u64 *array; | ||
| 880 | u64 type; | ||
| 881 | |||
| 882 | if (event->header.type != PERF_RECORD_SAMPLE) | ||
| 883 | return event__parse_id_sample(event, session, data); | ||
| 884 | |||
| 885 | array = event->sample.array; | ||
| 886 | type = session->sample_type; | ||
| 772 | 887 | ||
| 773 | if (type & PERF_SAMPLE_IP) { | 888 | if (type & PERF_SAMPLE_IP) { |
| 774 | data->ip = event->ip.ip; | 889 | data->ip = event->ip.ip; |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 8e790dae7026..2b7e91902f10 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
| @@ -85,6 +85,7 @@ struct build_id_event { | |||
| 85 | }; | 85 | }; |
| 86 | 86 | ||
| 87 | enum perf_user_event_type { /* above any possible kernel type */ | 87 | enum perf_user_event_type { /* above any possible kernel type */ |
| 88 | PERF_RECORD_USER_TYPE_START = 64, | ||
| 88 | PERF_RECORD_HEADER_ATTR = 64, | 89 | PERF_RECORD_HEADER_ATTR = 64, |
| 89 | PERF_RECORD_HEADER_EVENT_TYPE = 65, | 90 | PERF_RECORD_HEADER_EVENT_TYPE = 65, |
| 90 | PERF_RECORD_HEADER_TRACING_DATA = 66, | 91 | PERF_RECORD_HEADER_TRACING_DATA = 66, |
| @@ -135,12 +136,15 @@ void event__print_totals(void); | |||
| 135 | 136 | ||
| 136 | struct perf_session; | 137 | struct perf_session; |
| 137 | 138 | ||
| 138 | typedef int (*event__handler_t)(event_t *event, struct perf_session *session); | 139 | typedef int (*event__handler_synth_t)(event_t *event, |
| 140 | struct perf_session *session); | ||
| 141 | typedef int (*event__handler_t)(event_t *event, struct sample_data *sample, | ||
| 142 | struct perf_session *session); | ||
| 139 | 143 | ||
| 140 | int event__synthesize_thread(pid_t pid, event__handler_t process, | 144 | int event__synthesize_thread(pid_t pid, event__handler_t process, |
| 141 | struct perf_session *session); | 145 | struct perf_session *session); |
| 142 | void event__synthesize_threads(event__handler_t process, | 146 | int event__synthesize_threads(event__handler_t process, |
| 143 | struct perf_session *session); | 147 | struct perf_session *session); |
| 144 | int event__synthesize_kernel_mmap(event__handler_t process, | 148 | int event__synthesize_kernel_mmap(event__handler_t process, |
| 145 | struct perf_session *session, | 149 | struct perf_session *session, |
| 146 | struct machine *machine, | 150 | struct machine *machine, |
| @@ -150,18 +154,24 @@ int event__synthesize_modules(event__handler_t process, | |||
| 150 | struct perf_session *session, | 154 | struct perf_session *session, |
| 151 | struct machine *machine); | 155 | struct machine *machine); |
| 152 | 156 | ||
| 153 | int event__process_comm(event_t *self, struct perf_session *session); | 157 | int event__process_comm(event_t *self, struct sample_data *sample, |
| 154 | int event__process_lost(event_t *self, struct perf_session *session); | 158 | struct perf_session *session); |
| 155 | int event__process_mmap(event_t *self, struct perf_session *session); | 159 | int event__process_lost(event_t *self, struct sample_data *sample, |
| 156 | int event__process_task(event_t *self, struct perf_session *session); | 160 | struct perf_session *session); |
| 157 | int event__process(event_t *event, struct perf_session *session); | 161 | int event__process_mmap(event_t *self, struct sample_data *sample, |
| 162 | struct perf_session *session); | ||
| 163 | int event__process_task(event_t *self, struct sample_data *sample, | ||
| 164 | struct perf_session *session); | ||
| 165 | int event__process(event_t *event, struct sample_data *sample, | ||
| 166 | struct perf_session *session); | ||
| 158 | 167 | ||
| 159 | struct addr_location; | 168 | struct addr_location; |
| 160 | int event__preprocess_sample(const event_t *self, struct perf_session *session, | 169 | int event__preprocess_sample(const event_t *self, struct perf_session *session, |
| 161 | struct addr_location *al, struct sample_data *data, | 170 | struct addr_location *al, struct sample_data *data, |
| 162 | symbol_filter_t filter); | 171 | symbol_filter_t filter); |
| 163 | int event__parse_sample(const event_t *event, u64 type, struct sample_data *data); | 172 | int event__parse_sample(const event_t *event, struct perf_session *session, |
| 173 | struct sample_data *sample); | ||
| 164 | 174 | ||
| 165 | extern const char *event__name[]; | 175 | const char *event__get_event_name(unsigned int id); |
| 166 | 176 | ||
| 167 | #endif /* __PERF_RECORD_H */ | 177 | #endif /* __PERF_RECORD_H */ |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 64a85bafde63..16a16021eaa6 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
| @@ -152,6 +152,11 @@ void perf_header__set_feat(struct perf_header *self, int feat) | |||
| 152 | set_bit(feat, self->adds_features); | 152 | set_bit(feat, self->adds_features); |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | void perf_header__clear_feat(struct perf_header *self, int feat) | ||
| 156 | { | ||
| 157 | clear_bit(feat, self->adds_features); | ||
| 158 | } | ||
| 159 | |||
| 155 | bool perf_header__has_feat(const struct perf_header *self, int feat) | 160 | bool perf_header__has_feat(const struct perf_header *self, int feat) |
| 156 | { | 161 | { |
| 157 | return test_bit(feat, self->adds_features); | 162 | return test_bit(feat, self->adds_features); |
| @@ -431,8 +436,10 @@ static int perf_header__adds_write(struct perf_header *self, int fd) | |||
| 431 | int idx = 0, err; | 436 | int idx = 0, err; |
| 432 | 437 | ||
| 433 | session = container_of(self, struct perf_session, header); | 438 | session = container_of(self, struct perf_session, header); |
| 434 | if (perf_session__read_build_ids(session, true)) | 439 | |
| 435 | perf_header__set_feat(self, HEADER_BUILD_ID); | 440 | if (perf_header__has_feat(self, HEADER_BUILD_ID && |
| 441 | !perf_session__read_build_ids(session, true))) | ||
| 442 | perf_header__clear_feat(self, HEADER_BUILD_ID); | ||
| 436 | 443 | ||
| 437 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); | 444 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); |
| 438 | if (!nr_sections) | 445 | if (!nr_sections) |
| @@ -939,6 +946,24 @@ u64 perf_header__sample_type(struct perf_header *header) | |||
| 939 | return type; | 946 | return type; |
| 940 | } | 947 | } |
| 941 | 948 | ||
| 949 | bool perf_header__sample_id_all(const struct perf_header *header) | ||
| 950 | { | ||
| 951 | bool value = false, first = true; | ||
| 952 | int i; | ||
| 953 | |||
| 954 | for (i = 0; i < header->attrs; i++) { | ||
| 955 | struct perf_header_attr *attr = header->attr[i]; | ||
| 956 | |||
| 957 | if (first) { | ||
| 958 | value = attr->attr.sample_id_all; | ||
| 959 | first = false; | ||
| 960 | } else if (value != attr->attr.sample_id_all) | ||
| 961 | die("non matching sample_id_all"); | ||
| 962 | } | ||
| 963 | |||
| 964 | return value; | ||
| 965 | } | ||
| 966 | |||
| 942 | struct perf_event_attr * | 967 | struct perf_event_attr * |
| 943 | perf_header__find_attr(u64 id, struct perf_header *header) | 968 | perf_header__find_attr(u64 id, struct perf_header *header) |
| 944 | { | 969 | { |
| @@ -985,21 +1010,23 @@ int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, | |||
| 985 | 1010 | ||
| 986 | ev = malloc(size); | 1011 | ev = malloc(size); |
| 987 | 1012 | ||
| 1013 | if (ev == NULL) | ||
| 1014 | return -ENOMEM; | ||
| 1015 | |||
| 988 | ev->attr.attr = *attr; | 1016 | ev->attr.attr = *attr; |
| 989 | memcpy(ev->attr.id, id, ids * sizeof(u64)); | 1017 | memcpy(ev->attr.id, id, ids * sizeof(u64)); |
| 990 | 1018 | ||
| 991 | ev->attr.header.type = PERF_RECORD_HEADER_ATTR; | 1019 | ev->attr.header.type = PERF_RECORD_HEADER_ATTR; |
| 992 | ev->attr.header.size = size; | 1020 | ev->attr.header.size = size; |
| 993 | 1021 | ||
| 994 | err = process(ev, session); | 1022 | err = process(ev, NULL, session); |
| 995 | 1023 | ||
| 996 | free(ev); | 1024 | free(ev); |
| 997 | 1025 | ||
| 998 | return err; | 1026 | return err; |
| 999 | } | 1027 | } |
| 1000 | 1028 | ||
| 1001 | int event__synthesize_attrs(struct perf_header *self, | 1029 | int event__synthesize_attrs(struct perf_header *self, event__handler_t process, |
| 1002 | event__handler_t process, | ||
| 1003 | struct perf_session *session) | 1030 | struct perf_session *session) |
| 1004 | { | 1031 | { |
| 1005 | struct perf_header_attr *attr; | 1032 | struct perf_header_attr *attr; |
| @@ -1069,7 +1096,7 @@ int event__synthesize_event_type(u64 event_id, char *name, | |||
| 1069 | ev.event_type.header.size = sizeof(ev.event_type) - | 1096 | ev.event_type.header.size = sizeof(ev.event_type) - |
| 1070 | (sizeof(ev.event_type.event_type.name) - size); | 1097 | (sizeof(ev.event_type.event_type.name) - size); |
| 1071 | 1098 | ||
| 1072 | err = process(&ev, session); | 1099 | err = process(&ev, NULL, session); |
| 1073 | 1100 | ||
| 1074 | return err; | 1101 | return err; |
| 1075 | } | 1102 | } |
| @@ -1124,7 +1151,7 @@ int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs, | |||
| 1124 | ev.tracing_data.header.size = sizeof(ev.tracing_data); | 1151 | ev.tracing_data.header.size = sizeof(ev.tracing_data); |
| 1125 | ev.tracing_data.size = aligned_size; | 1152 | ev.tracing_data.size = aligned_size; |
| 1126 | 1153 | ||
| 1127 | process(&ev, session); | 1154 | process(&ev, NULL, session); |
| 1128 | 1155 | ||
| 1129 | err = read_tracing_data(fd, pattrs, nb_events); | 1156 | err = read_tracing_data(fd, pattrs, nb_events); |
| 1130 | write_padded(fd, NULL, 0, padding); | 1157 | write_padded(fd, NULL, 0, padding); |
| @@ -1184,7 +1211,7 @@ int event__synthesize_build_id(struct dso *pos, u16 misc, | |||
| 1184 | ev.build_id.header.size = sizeof(ev.build_id) + len; | 1211 | ev.build_id.header.size = sizeof(ev.build_id) + len; |
| 1185 | memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); | 1212 | memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); |
| 1186 | 1213 | ||
| 1187 | err = process(&ev, session); | 1214 | err = process(&ev, NULL, session); |
| 1188 | 1215 | ||
| 1189 | return err; | 1216 | return err; |
| 1190 | } | 1217 | } |
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 402ac2454cf8..6335965e1f93 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
| @@ -81,9 +81,11 @@ void perf_header_attr__delete(struct perf_header_attr *self); | |||
| 81 | int perf_header_attr__add_id(struct perf_header_attr *self, u64 id); | 81 | int perf_header_attr__add_id(struct perf_header_attr *self, u64 id); |
| 82 | 82 | ||
| 83 | u64 perf_header__sample_type(struct perf_header *header); | 83 | u64 perf_header__sample_type(struct perf_header *header); |
| 84 | bool perf_header__sample_id_all(const struct perf_header *header); | ||
| 84 | struct perf_event_attr * | 85 | struct perf_event_attr * |
| 85 | perf_header__find_attr(u64 id, struct perf_header *header); | 86 | perf_header__find_attr(u64 id, struct perf_header *header); |
| 86 | void perf_header__set_feat(struct perf_header *self, int feat); | 87 | void perf_header__set_feat(struct perf_header *self, int feat); |
| 88 | void perf_header__clear_feat(struct perf_header *self, int feat); | ||
| 87 | bool perf_header__has_feat(const struct perf_header *self, int feat); | 89 | bool perf_header__has_feat(const struct perf_header *self, int feat); |
| 88 | 90 | ||
| 89 | int perf_header__process_sections(struct perf_header *self, int fd, | 91 | int perf_header__process_sections(struct perf_header *self, int fd, |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 2022e8740994..a3b84160c42e 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
| @@ -1168,10 +1168,13 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp) | |||
| 1168 | size_t ret = 0; | 1168 | size_t ret = 0; |
| 1169 | 1169 | ||
| 1170 | for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { | 1170 | for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { |
| 1171 | if (!event__name[i]) | 1171 | const char *name = event__get_event_name(i); |
| 1172 | |||
| 1173 | if (!strcmp(name, "UNKNOWN")) | ||
| 1172 | continue; | 1174 | continue; |
| 1173 | ret += fprintf(fp, "%10s events: %10d\n", | 1175 | |
| 1174 | event__name[i], self->stats.nr_events[i]); | 1176 | ret += fprintf(fp, "%16s events: %10d\n", name, |
| 1177 | self->stats.nr_events[i]); | ||
| 1175 | } | 1178 | } |
| 1176 | 1179 | ||
| 1177 | return ret; | 1180 | return ret; |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 587d375d3430..ee789856a8c9 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
| @@ -52,8 +52,10 @@ struct sym_priv { | |||
| 52 | struct events_stats { | 52 | struct events_stats { |
| 53 | u64 total_period; | 53 | u64 total_period; |
| 54 | u64 total_lost; | 54 | u64 total_lost; |
| 55 | u64 total_invalid_chains; | ||
| 55 | u32 nr_events[PERF_RECORD_HEADER_MAX]; | 56 | u32 nr_events[PERF_RECORD_HEADER_MAX]; |
| 56 | u32 nr_unknown_events; | 57 | u32 nr_unknown_events; |
| 58 | u32 nr_invalid_chains; | ||
| 57 | }; | 59 | }; |
| 58 | 60 | ||
| 59 | enum hist_column { | 61 | enum hist_column { |
diff --git a/tools/perf/util/include/asm/cpufeature.h b/tools/perf/util/include/asm/cpufeature.h new file mode 100644 index 000000000000..acffd5e4d1d4 --- /dev/null +++ b/tools/perf/util/include/asm/cpufeature.h | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | |||
| 2 | #ifndef PERF_CPUFEATURE_H | ||
| 3 | #define PERF_CPUFEATURE_H | ||
| 4 | |||
| 5 | /* cpufeature.h ... dummy header file for including arch/x86/lib/memcpy_64.S */ | ||
| 6 | |||
| 7 | #define X86_FEATURE_REP_GOOD 0 | ||
| 8 | |||
| 9 | #endif /* PERF_CPUFEATURE_H */ | ||
diff --git a/tools/perf/util/include/asm/dwarf2.h b/tools/perf/util/include/asm/dwarf2.h new file mode 100644 index 000000000000..bb4198e7837a --- /dev/null +++ b/tools/perf/util/include/asm/dwarf2.h | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | |||
| 2 | #ifndef PERF_DWARF2_H | ||
| 3 | #define PERF_DWARF2_H | ||
| 4 | |||
| 5 | /* dwarf2.h ... dummy header file for including arch/x86/lib/memcpy_64.S */ | ||
| 6 | |||
| 7 | #define CFI_STARTPROC | ||
| 8 | #define CFI_ENDPROC | ||
| 9 | |||
| 10 | #endif /* PERF_DWARF2_H */ | ||
| 11 | |||
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h index bb4ac2e05385..8be0b968ca0b 100644 --- a/tools/perf/util/include/linux/bitops.h +++ b/tools/perf/util/include/linux/bitops.h | |||
| @@ -13,6 +13,11 @@ static inline void set_bit(int nr, unsigned long *addr) | |||
| 13 | addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG); | 13 | addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG); |
| 14 | } | 14 | } |
| 15 | 15 | ||
| 16 | static inline void clear_bit(int nr, unsigned long *addr) | ||
| 17 | { | ||
| 18 | addr[nr / BITS_PER_LONG] &= ~(1UL << (nr % BITS_PER_LONG)); | ||
| 19 | } | ||
| 20 | |||
| 16 | static __always_inline int test_bit(unsigned int nr, const unsigned long *addr) | 21 | static __always_inline int test_bit(unsigned int nr, const unsigned long *addr) |
| 17 | { | 22 | { |
| 18 | return ((1UL << (nr % BITS_PER_LONG)) & | 23 | return ((1UL << (nr % BITS_PER_LONG)) & |
diff --git a/tools/perf/util/include/linux/linkage.h b/tools/perf/util/include/linux/linkage.h new file mode 100644 index 000000000000..06387cffe125 --- /dev/null +++ b/tools/perf/util/include/linux/linkage.h | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | |||
| 2 | #ifndef PERF_LINUX_LINKAGE_H_ | ||
| 3 | #define PERF_LINUX_LINKAGE_H_ | ||
| 4 | |||
| 5 | /* linkage.h ... for including arch/x86/lib/memcpy_64.S */ | ||
| 6 | |||
| 7 | #define ENTRY(name) \ | ||
| 8 | .globl name; \ | ||
| 9 | name: | ||
| 10 | |||
| 11 | #define ENDPROC(name) | ||
| 12 | |||
| 13 | #endif /* PERF_LINUX_LINKAGE_H_ */ | ||
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 4af5bd59cfd1..c305305a3884 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
| @@ -434,7 +434,7 @@ parse_single_tracepoint_event(char *sys_name, | |||
| 434 | id = atoll(id_buf); | 434 | id = atoll(id_buf); |
| 435 | attr->config = id; | 435 | attr->config = id; |
| 436 | attr->type = PERF_TYPE_TRACEPOINT; | 436 | attr->type = PERF_TYPE_TRACEPOINT; |
| 437 | *strp = evt_name + evt_length; | 437 | *strp += strlen(sys_name) + evt_length + 1; /* + 1 for the ':' */ |
| 438 | 438 | ||
| 439 | attr->sample_type |= PERF_SAMPLE_RAW; | 439 | attr->sample_type |= PERF_SAMPLE_RAW; |
| 440 | attr->sample_type |= PERF_SAMPLE_TIME; | 440 | attr->sample_type |= PERF_SAMPLE_TIME; |
| @@ -495,7 +495,7 @@ static enum event_result parse_tracepoint_event(const char **strp, | |||
| 495 | struct perf_event_attr *attr) | 495 | struct perf_event_attr *attr) |
| 496 | { | 496 | { |
| 497 | const char *evt_name; | 497 | const char *evt_name; |
| 498 | char *flags; | 498 | char *flags = NULL, *comma_loc; |
| 499 | char sys_name[MAX_EVENT_LENGTH]; | 499 | char sys_name[MAX_EVENT_LENGTH]; |
| 500 | unsigned int sys_length, evt_length; | 500 | unsigned int sys_length, evt_length; |
| 501 | 501 | ||
| @@ -514,6 +514,11 @@ static enum event_result parse_tracepoint_event(const char **strp, | |||
| 514 | sys_name[sys_length] = '\0'; | 514 | sys_name[sys_length] = '\0'; |
| 515 | evt_name = evt_name + 1; | 515 | evt_name = evt_name + 1; |
| 516 | 516 | ||
| 517 | comma_loc = strchr(evt_name, ','); | ||
| 518 | if (comma_loc) { | ||
| 519 | /* take the event name up to the comma */ | ||
| 520 | evt_name = strndup(evt_name, comma_loc - evt_name); | ||
| 521 | } | ||
| 517 | flags = strchr(evt_name, ':'); | 522 | flags = strchr(evt_name, ':'); |
| 518 | if (flags) { | 523 | if (flags) { |
| 519 | /* split it out: */ | 524 | /* split it out: */ |
| @@ -524,9 +529,8 @@ static enum event_result parse_tracepoint_event(const char **strp, | |||
| 524 | evt_length = strlen(evt_name); | 529 | evt_length = strlen(evt_name); |
| 525 | if (evt_length >= MAX_EVENT_LENGTH) | 530 | if (evt_length >= MAX_EVENT_LENGTH) |
| 526 | return EVT_FAILED; | 531 | return EVT_FAILED; |
| 527 | |||
| 528 | if (strpbrk(evt_name, "*?")) { | 532 | if (strpbrk(evt_name, "*?")) { |
| 529 | *strp = evt_name + evt_length; | 533 | *strp += strlen(sys_name) + evt_length; |
| 530 | return parse_multiple_tracepoint_event(sys_name, evt_name, | 534 | return parse_multiple_tracepoint_event(sys_name, evt_name, |
| 531 | flags); | 535 | flags); |
| 532 | } else | 536 | } else |
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h index c7d72dce54b2..abc31a1dac1a 100644 --- a/tools/perf/util/parse-options.h +++ b/tools/perf/util/parse-options.h | |||
| @@ -119,6 +119,10 @@ struct option { | |||
| 119 | { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .flags = PARSE_OPT_NOARG } | 119 | { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .flags = PARSE_OPT_NOARG } |
| 120 | #define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \ | 120 | #define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \ |
| 121 | { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT } | 121 | { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT } |
| 122 | #define OPT_CALLBACK_DEFAULT_NOOPT(s, l, v, a, h, f, d) \ | ||
| 123 | { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\ | ||
| 124 | .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\ | ||
| 125 | .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG} | ||
| 122 | 126 | ||
| 123 | /* parse_options() will filter out the processed options and leave the | 127 | /* parse_options() will filter out the processed options and leave the |
| 124 | * non-option argments in argv[]. | 128 | * non-option argments in argv[]. |
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index bba69d455699..beaefc3c1223 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h | |||
| @@ -34,9 +34,9 @@ extern int find_available_vars_at(int fd, struct perf_probe_event *pev, | |||
| 34 | bool externs); | 34 | bool externs); |
| 35 | 35 | ||
| 36 | #include <dwarf.h> | 36 | #include <dwarf.h> |
| 37 | #include <libdw.h> | 37 | #include <elfutils/libdw.h> |
| 38 | #include <libdwfl.h> | 38 | #include <elfutils/libdwfl.h> |
| 39 | #include <version.h> | 39 | #include <elfutils/version.h> |
| 40 | 40 | ||
| 41 | struct probe_finder { | 41 | struct probe_finder { |
| 42 | struct perf_probe_event *pev; /* Target probe event */ | 42 | struct perf_probe_event *pev; /* Target probe event */ |
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index b059dc50cc2d..93680818e244 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * trace-event-perl. Feed perf trace events to an embedded Perl interpreter. | 2 | * trace-event-perl. Feed perf script events to an embedded Perl interpreter. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com> | 4 | * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com> |
| 5 | * | 5 | * |
| @@ -411,8 +411,8 @@ static int perl_generate_script(const char *outfile) | |||
| 411 | return -1; | 411 | return -1; |
| 412 | } | 412 | } |
| 413 | 413 | ||
| 414 | fprintf(ofp, "# perf trace event handlers, " | 414 | fprintf(ofp, "# perf script event handlers, " |
| 415 | "generated by perf trace -g perl\n"); | 415 | "generated by perf script -g perl\n"); |
| 416 | 416 | ||
| 417 | fprintf(ofp, "# Licensed under the terms of the GNU GPL" | 417 | fprintf(ofp, "# Licensed under the terms of the GNU GPL" |
| 418 | " License version 2\n\n"); | 418 | " License version 2\n\n"); |
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 33a632523743..c6d99334bdfa 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
| @@ -442,8 +442,8 @@ static int python_generate_script(const char *outfile) | |||
| 442 | fprintf(stderr, "couldn't open %s\n", fname); | 442 | fprintf(stderr, "couldn't open %s\n", fname); |
| 443 | return -1; | 443 | return -1; |
| 444 | } | 444 | } |
| 445 | fprintf(ofp, "# perf trace event handlers, " | 445 | fprintf(ofp, "# perf script event handlers, " |
| 446 | "generated by perf trace -g python\n"); | 446 | "generated by perf script -g python\n"); |
| 447 | 447 | ||
| 448 | fprintf(ofp, "# Licensed under the terms of the GNU GPL" | 448 | fprintf(ofp, "# Licensed under the terms of the GNU GPL" |
| 449 | " License version 2\n\n"); | 449 | " License version 2\n\n"); |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index fa9d652c2dc3..b59abf5aba36 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
| @@ -65,9 +65,49 @@ out_close: | |||
| 65 | return -1; | 65 | return -1; |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | static void perf_session__id_header_size(struct perf_session *session) | ||
| 69 | { | ||
| 70 | struct sample_data *data; | ||
| 71 | u64 sample_type = session->sample_type; | ||
| 72 | u16 size = 0; | ||
| 73 | |||
| 74 | if (!session->sample_id_all) | ||
| 75 | goto out; | ||
| 76 | |||
| 77 | if (sample_type & PERF_SAMPLE_TID) | ||
| 78 | size += sizeof(data->tid) * 2; | ||
| 79 | |||
| 80 | if (sample_type & PERF_SAMPLE_TIME) | ||
| 81 | size += sizeof(data->time); | ||
| 82 | |||
| 83 | if (sample_type & PERF_SAMPLE_ID) | ||
| 84 | size += sizeof(data->id); | ||
| 85 | |||
| 86 | if (sample_type & PERF_SAMPLE_STREAM_ID) | ||
| 87 | size += sizeof(data->stream_id); | ||
| 88 | |||
| 89 | if (sample_type & PERF_SAMPLE_CPU) | ||
| 90 | size += sizeof(data->cpu) * 2; | ||
| 91 | out: | ||
| 92 | session->id_hdr_size = size; | ||
| 93 | } | ||
| 94 | |||
| 95 | void perf_session__set_sample_id_all(struct perf_session *session, bool value) | ||
| 96 | { | ||
| 97 | session->sample_id_all = value; | ||
| 98 | perf_session__id_header_size(session); | ||
| 99 | } | ||
| 100 | |||
| 101 | void perf_session__set_sample_type(struct perf_session *session, u64 type) | ||
| 102 | { | ||
| 103 | session->sample_type = type; | ||
| 104 | } | ||
| 105 | |||
| 68 | void perf_session__update_sample_type(struct perf_session *self) | 106 | void perf_session__update_sample_type(struct perf_session *self) |
| 69 | { | 107 | { |
| 70 | self->sample_type = perf_header__sample_type(&self->header); | 108 | self->sample_type = perf_header__sample_type(&self->header); |
| 109 | self->sample_id_all = perf_header__sample_id_all(&self->header); | ||
| 110 | perf_session__id_header_size(self); | ||
| 71 | } | 111 | } |
| 72 | 112 | ||
| 73 | int perf_session__create_kernel_maps(struct perf_session *self) | 113 | int perf_session__create_kernel_maps(struct perf_session *self) |
| @@ -101,10 +141,20 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc | |||
| 101 | INIT_LIST_HEAD(&self->dead_threads); | 141 | INIT_LIST_HEAD(&self->dead_threads); |
| 102 | self->hists_tree = RB_ROOT; | 142 | self->hists_tree = RB_ROOT; |
| 103 | self->last_match = NULL; | 143 | self->last_match = NULL; |
| 104 | self->mmap_window = 32; | 144 | /* |
| 145 | * On 64bit we can mmap the data file in one go. No need for tiny mmap | ||
| 146 | * slices. On 32bit we use 32MB. | ||
| 147 | */ | ||
| 148 | #if BITS_PER_LONG == 64 | ||
| 149 | self->mmap_window = ULLONG_MAX; | ||
| 150 | #else | ||
| 151 | self->mmap_window = 32 * 1024 * 1024ULL; | ||
| 152 | #endif | ||
| 105 | self->machines = RB_ROOT; | 153 | self->machines = RB_ROOT; |
| 106 | self->repipe = repipe; | 154 | self->repipe = repipe; |
| 107 | INIT_LIST_HEAD(&self->ordered_samples.samples_head); | 155 | INIT_LIST_HEAD(&self->ordered_samples.samples); |
| 156 | INIT_LIST_HEAD(&self->ordered_samples.sample_cache); | ||
| 157 | INIT_LIST_HEAD(&self->ordered_samples.to_free); | ||
| 108 | machine__init(&self->host_machine, "", HOST_KERNEL_ID); | 158 | machine__init(&self->host_machine, "", HOST_KERNEL_ID); |
| 109 | 159 | ||
| 110 | if (mode == O_RDONLY) { | 160 | if (mode == O_RDONLY) { |
| @@ -230,7 +280,15 @@ struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, | |||
| 230 | return syms; | 280 | return syms; |
| 231 | } | 281 | } |
| 232 | 282 | ||
| 283 | static int process_event_synth_stub(event_t *event __used, | ||
| 284 | struct perf_session *session __used) | ||
| 285 | { | ||
| 286 | dump_printf(": unhandled!\n"); | ||
| 287 | return 0; | ||
| 288 | } | ||
| 289 | |||
| 233 | static int process_event_stub(event_t *event __used, | 290 | static int process_event_stub(event_t *event __used, |
| 291 | struct sample_data *sample __used, | ||
| 234 | struct perf_session *session __used) | 292 | struct perf_session *session __used) |
| 235 | { | 293 | { |
| 236 | dump_printf(": unhandled!\n"); | 294 | dump_printf(": unhandled!\n"); |
| @@ -262,7 +320,7 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) | |||
| 262 | if (handler->exit == NULL) | 320 | if (handler->exit == NULL) |
| 263 | handler->exit = process_event_stub; | 321 | handler->exit = process_event_stub; |
| 264 | if (handler->lost == NULL) | 322 | if (handler->lost == NULL) |
| 265 | handler->lost = process_event_stub; | 323 | handler->lost = event__process_lost; |
| 266 | if (handler->read == NULL) | 324 | if (handler->read == NULL) |
| 267 | handler->read = process_event_stub; | 325 | handler->read = process_event_stub; |
| 268 | if (handler->throttle == NULL) | 326 | if (handler->throttle == NULL) |
| @@ -270,13 +328,13 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) | |||
| 270 | if (handler->unthrottle == NULL) | 328 | if (handler->unthrottle == NULL) |
| 271 | handler->unthrottle = process_event_stub; | 329 | handler->unthrottle = process_event_stub; |
| 272 | if (handler->attr == NULL) | 330 | if (handler->attr == NULL) |
| 273 | handler->attr = process_event_stub; | 331 | handler->attr = process_event_synth_stub; |
| 274 | if (handler->event_type == NULL) | 332 | if (handler->event_type == NULL) |
| 275 | handler->event_type = process_event_stub; | 333 | handler->event_type = process_event_synth_stub; |
| 276 | if (handler->tracing_data == NULL) | 334 | if (handler->tracing_data == NULL) |
| 277 | handler->tracing_data = process_event_stub; | 335 | handler->tracing_data = process_event_synth_stub; |
| 278 | if (handler->build_id == NULL) | 336 | if (handler->build_id == NULL) |
| 279 | handler->build_id = process_event_stub; | 337 | handler->build_id = process_event_synth_stub; |
| 280 | if (handler->finished_round == NULL) { | 338 | if (handler->finished_round == NULL) { |
| 281 | if (handler->ordered_samples) | 339 | if (handler->ordered_samples) |
| 282 | handler->finished_round = process_finished_round; | 340 | handler->finished_round = process_finished_round; |
| @@ -386,33 +444,61 @@ static event__swap_op event__swap_ops[] = { | |||
| 386 | 444 | ||
| 387 | struct sample_queue { | 445 | struct sample_queue { |
| 388 | u64 timestamp; | 446 | u64 timestamp; |
| 389 | struct sample_event *event; | 447 | u64 file_offset; |
| 448 | event_t *event; | ||
| 390 | struct list_head list; | 449 | struct list_head list; |
| 391 | }; | 450 | }; |
| 392 | 451 | ||
| 452 | static void perf_session_free_sample_buffers(struct perf_session *session) | ||
| 453 | { | ||
| 454 | struct ordered_samples *os = &session->ordered_samples; | ||
| 455 | |||
| 456 | while (!list_empty(&os->to_free)) { | ||
| 457 | struct sample_queue *sq; | ||
| 458 | |||
| 459 | sq = list_entry(os->to_free.next, struct sample_queue, list); | ||
| 460 | list_del(&sq->list); | ||
| 461 | free(sq); | ||
| 462 | } | ||
| 463 | } | ||
| 464 | |||
| 465 | static int perf_session_deliver_event(struct perf_session *session, | ||
| 466 | event_t *event, | ||
| 467 | struct sample_data *sample, | ||
| 468 | struct perf_event_ops *ops, | ||
| 469 | u64 file_offset); | ||
| 470 | |||
| 393 | static void flush_sample_queue(struct perf_session *s, | 471 | static void flush_sample_queue(struct perf_session *s, |
| 394 | struct perf_event_ops *ops) | 472 | struct perf_event_ops *ops) |
| 395 | { | 473 | { |
| 396 | struct list_head *head = &s->ordered_samples.samples_head; | 474 | struct ordered_samples *os = &s->ordered_samples; |
| 397 | u64 limit = s->ordered_samples.next_flush; | 475 | struct list_head *head = &os->samples; |
| 398 | struct sample_queue *tmp, *iter; | 476 | struct sample_queue *tmp, *iter; |
| 477 | struct sample_data sample; | ||
| 478 | u64 limit = os->next_flush; | ||
| 479 | u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; | ||
| 399 | 480 | ||
| 400 | if (!ops->ordered_samples || !limit) | 481 | if (!ops->ordered_samples || !limit) |
| 401 | return; | 482 | return; |
| 402 | 483 | ||
| 403 | list_for_each_entry_safe(iter, tmp, head, list) { | 484 | list_for_each_entry_safe(iter, tmp, head, list) { |
| 404 | if (iter->timestamp > limit) | 485 | if (iter->timestamp > limit) |
| 405 | return; | 486 | break; |
| 406 | |||
| 407 | if (iter == s->ordered_samples.last_inserted) | ||
| 408 | s->ordered_samples.last_inserted = NULL; | ||
| 409 | 487 | ||
| 410 | ops->sample((event_t *)iter->event, s); | 488 | event__parse_sample(iter->event, s, &sample); |
| 489 | perf_session_deliver_event(s, iter->event, &sample, ops, | ||
| 490 | iter->file_offset); | ||
| 411 | 491 | ||
| 412 | s->ordered_samples.last_flush = iter->timestamp; | 492 | os->last_flush = iter->timestamp; |
| 413 | list_del(&iter->list); | 493 | list_del(&iter->list); |
| 414 | free(iter->event); | 494 | list_add(&iter->list, &os->sample_cache); |
| 415 | free(iter); | 495 | } |
| 496 | |||
| 497 | if (list_empty(head)) { | ||
| 498 | os->last_sample = NULL; | ||
| 499 | } else if (last_ts <= limit) { | ||
| 500 | os->last_sample = | ||
| 501 | list_entry(head->prev, struct sample_queue, list); | ||
| 416 | } | 502 | } |
| 417 | } | 503 | } |
| 418 | 504 | ||
| @@ -465,178 +551,265 @@ static int process_finished_round(event_t *event __used, | |||
| 465 | return 0; | 551 | return 0; |
| 466 | } | 552 | } |
| 467 | 553 | ||
| 468 | static void __queue_sample_end(struct sample_queue *new, struct list_head *head) | ||
| 469 | { | ||
| 470 | struct sample_queue *iter; | ||
| 471 | |||
| 472 | list_for_each_entry_reverse(iter, head, list) { | ||
| 473 | if (iter->timestamp < new->timestamp) { | ||
| 474 | list_add(&new->list, &iter->list); | ||
| 475 | return; | ||
| 476 | } | ||
| 477 | } | ||
| 478 | |||
| 479 | list_add(&new->list, head); | ||
| 480 | } | ||
| 481 | |||
| 482 | static void __queue_sample_before(struct sample_queue *new, | ||
| 483 | struct sample_queue *iter, | ||
| 484 | struct list_head *head) | ||
| 485 | { | ||
| 486 | list_for_each_entry_continue_reverse(iter, head, list) { | ||
| 487 | if (iter->timestamp < new->timestamp) { | ||
| 488 | list_add(&new->list, &iter->list); | ||
| 489 | return; | ||
| 490 | } | ||
| 491 | } | ||
| 492 | |||
| 493 | list_add(&new->list, head); | ||
| 494 | } | ||
| 495 | |||
| 496 | static void __queue_sample_after(struct sample_queue *new, | ||
| 497 | struct sample_queue *iter, | ||
| 498 | struct list_head *head) | ||
| 499 | { | ||
| 500 | list_for_each_entry_continue(iter, head, list) { | ||
| 501 | if (iter->timestamp > new->timestamp) { | ||
| 502 | list_add_tail(&new->list, &iter->list); | ||
| 503 | return; | ||
| 504 | } | ||
| 505 | } | ||
| 506 | list_add_tail(&new->list, head); | ||
| 507 | } | ||
| 508 | |||
| 509 | /* The queue is ordered by time */ | 554 | /* The queue is ordered by time */ |
| 510 | static void __queue_sample_event(struct sample_queue *new, | 555 | static void __queue_event(struct sample_queue *new, struct perf_session *s) |
| 511 | struct perf_session *s) | ||
| 512 | { | 556 | { |
| 513 | struct sample_queue *last_inserted = s->ordered_samples.last_inserted; | 557 | struct ordered_samples *os = &s->ordered_samples; |
| 514 | struct list_head *head = &s->ordered_samples.samples_head; | 558 | struct sample_queue *sample = os->last_sample; |
| 559 | u64 timestamp = new->timestamp; | ||
| 560 | struct list_head *p; | ||
| 515 | 561 | ||
| 562 | os->last_sample = new; | ||
| 516 | 563 | ||
| 517 | if (!last_inserted) { | 564 | if (!sample) { |
| 518 | __queue_sample_end(new, head); | 565 | list_add(&new->list, &os->samples); |
| 566 | os->max_timestamp = timestamp; | ||
| 519 | return; | 567 | return; |
| 520 | } | 568 | } |
| 521 | 569 | ||
| 522 | /* | 570 | /* |
| 523 | * Most of the time the current event has a timestamp | 571 | * last_sample might point to some random place in the list as it's |
| 524 | * very close to the last event inserted, unless we just switched | 572 | * the last queued event. We expect that the new event is close to |
| 525 | * to another event buffer. Having a sorting based on a list and | 573 | * this. |
| 526 | * on the last inserted event that is close to the current one is | ||
| 527 | * probably more efficient than an rbtree based sorting. | ||
| 528 | */ | 574 | */ |
| 529 | if (last_inserted->timestamp >= new->timestamp) | 575 | if (sample->timestamp <= timestamp) { |
| 530 | __queue_sample_before(new, last_inserted, head); | 576 | while (sample->timestamp <= timestamp) { |
| 531 | else | 577 | p = sample->list.next; |
| 532 | __queue_sample_after(new, last_inserted, head); | 578 | if (p == &os->samples) { |
| 579 | list_add_tail(&new->list, &os->samples); | ||
| 580 | os->max_timestamp = timestamp; | ||
| 581 | return; | ||
| 582 | } | ||
| 583 | sample = list_entry(p, struct sample_queue, list); | ||
| 584 | } | ||
| 585 | list_add_tail(&new->list, &sample->list); | ||
| 586 | } else { | ||
| 587 | while (sample->timestamp > timestamp) { | ||
| 588 | p = sample->list.prev; | ||
| 589 | if (p == &os->samples) { | ||
| 590 | list_add(&new->list, &os->samples); | ||
| 591 | return; | ||
| 592 | } | ||
| 593 | sample = list_entry(p, struct sample_queue, list); | ||
| 594 | } | ||
| 595 | list_add(&new->list, &sample->list); | ||
| 596 | } | ||
| 533 | } | 597 | } |
| 534 | 598 | ||
| 535 | static int queue_sample_event(event_t *event, struct sample_data *data, | 599 | #define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) |
| 536 | struct perf_session *s) | 600 | |
| 601 | static int perf_session_queue_event(struct perf_session *s, event_t *event, | ||
| 602 | struct sample_data *data, u64 file_offset) | ||
| 537 | { | 603 | { |
| 604 | struct ordered_samples *os = &s->ordered_samples; | ||
| 605 | struct list_head *sc = &os->sample_cache; | ||
| 538 | u64 timestamp = data->time; | 606 | u64 timestamp = data->time; |
| 539 | struct sample_queue *new; | 607 | struct sample_queue *new; |
| 540 | 608 | ||
| 609 | if (!timestamp || timestamp == ~0ULL) | ||
| 610 | return -ETIME; | ||
| 541 | 611 | ||
| 542 | if (timestamp < s->ordered_samples.last_flush) { | 612 | if (timestamp < s->ordered_samples.last_flush) { |
| 543 | printf("Warning: Timestamp below last timeslice flush\n"); | 613 | printf("Warning: Timestamp below last timeslice flush\n"); |
| 544 | return -EINVAL; | 614 | return -EINVAL; |
| 545 | } | 615 | } |
| 546 | 616 | ||
| 547 | new = malloc(sizeof(*new)); | 617 | if (!list_empty(sc)) { |
| 548 | if (!new) | 618 | new = list_entry(sc->next, struct sample_queue, list); |
| 549 | return -ENOMEM; | 619 | list_del(&new->list); |
| 620 | } else if (os->sample_buffer) { | ||
| 621 | new = os->sample_buffer + os->sample_buffer_idx; | ||
| 622 | if (++os->sample_buffer_idx == MAX_SAMPLE_BUFFER) | ||
| 623 | os->sample_buffer = NULL; | ||
| 624 | } else { | ||
| 625 | os->sample_buffer = malloc(MAX_SAMPLE_BUFFER * sizeof(*new)); | ||
| 626 | if (!os->sample_buffer) | ||
| 627 | return -ENOMEM; | ||
| 628 | list_add(&os->sample_buffer->list, &os->to_free); | ||
| 629 | os->sample_buffer_idx = 2; | ||
| 630 | new = os->sample_buffer + 1; | ||
| 631 | } | ||
| 550 | 632 | ||
| 551 | new->timestamp = timestamp; | 633 | new->timestamp = timestamp; |
| 634 | new->file_offset = file_offset; | ||
| 635 | new->event = event; | ||
| 552 | 636 | ||
| 553 | new->event = malloc(event->header.size); | 637 | __queue_event(new, s); |
| 554 | if (!new->event) { | ||
| 555 | free(new); | ||
| 556 | return -ENOMEM; | ||
| 557 | } | ||
| 558 | 638 | ||
| 559 | memcpy(new->event, event, event->header.size); | 639 | return 0; |
| 640 | } | ||
| 560 | 641 | ||
| 561 | __queue_sample_event(new, s); | 642 | static void callchain__printf(struct sample_data *sample) |
| 562 | s->ordered_samples.last_inserted = new; | 643 | { |
| 644 | unsigned int i; | ||
| 563 | 645 | ||
| 564 | if (new->timestamp > s->ordered_samples.max_timestamp) | 646 | printf("... chain: nr:%Lu\n", sample->callchain->nr); |
| 565 | s->ordered_samples.max_timestamp = new->timestamp; | ||
| 566 | 647 | ||
| 567 | return 0; | 648 | for (i = 0; i < sample->callchain->nr; i++) |
| 649 | printf("..... %2d: %016Lx\n", i, sample->callchain->ips[i]); | ||
| 568 | } | 650 | } |
| 569 | 651 | ||
| 570 | static int perf_session__process_sample(event_t *event, struct perf_session *s, | 652 | static void perf_session__print_tstamp(struct perf_session *session, |
| 571 | struct perf_event_ops *ops) | 653 | event_t *event, |
| 654 | struct sample_data *sample) | ||
| 572 | { | 655 | { |
| 573 | struct sample_data data; | 656 | if (event->header.type != PERF_RECORD_SAMPLE && |
| 657 | !session->sample_id_all) { | ||
| 658 | fputs("-1 -1 ", stdout); | ||
| 659 | return; | ||
| 660 | } | ||
| 574 | 661 | ||
| 575 | if (!ops->ordered_samples) | 662 | if ((session->sample_type & PERF_SAMPLE_CPU)) |
| 576 | return ops->sample(event, s); | 663 | printf("%u ", sample->cpu); |
| 577 | 664 | ||
| 578 | bzero(&data, sizeof(struct sample_data)); | 665 | if (session->sample_type & PERF_SAMPLE_TIME) |
| 579 | event__parse_sample(event, s->sample_type, &data); | 666 | printf("%Lu ", sample->time); |
| 667 | } | ||
| 580 | 668 | ||
| 581 | queue_sample_event(event, &data, s); | 669 | static void dump_event(struct perf_session *session, event_t *event, |
| 670 | u64 file_offset, struct sample_data *sample) | ||
| 671 | { | ||
| 672 | if (!dump_trace) | ||
| 673 | return; | ||
| 582 | 674 | ||
| 583 | return 0; | 675 | printf("\n%#Lx [%#x]: event: %d\n", file_offset, event->header.size, |
| 676 | event->header.type); | ||
| 677 | |||
| 678 | trace_event(event); | ||
| 679 | |||
| 680 | if (sample) | ||
| 681 | perf_session__print_tstamp(session, event, sample); | ||
| 682 | |||
| 683 | printf("%#Lx [%#x]: PERF_RECORD_%s", file_offset, event->header.size, | ||
| 684 | event__get_event_name(event->header.type)); | ||
| 584 | } | 685 | } |
| 585 | 686 | ||
| 586 | static int perf_session__process_event(struct perf_session *self, | 687 | static void dump_sample(struct perf_session *session, event_t *event, |
| 587 | event_t *event, | 688 | struct sample_data *sample) |
| 588 | struct perf_event_ops *ops, | ||
| 589 | u64 offset, u64 head) | ||
| 590 | { | 689 | { |
| 591 | trace_event(event); | 690 | if (!dump_trace) |
| 691 | return; | ||
| 592 | 692 | ||
| 593 | if (event->header.type < PERF_RECORD_HEADER_MAX) { | 693 | printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc, |
| 594 | dump_printf("%#Lx [%#x]: PERF_RECORD_%s", | 694 | sample->pid, sample->tid, sample->ip, sample->period); |
| 595 | offset + head, event->header.size, | ||
| 596 | event__name[event->header.type]); | ||
| 597 | hists__inc_nr_events(&self->hists, event->header.type); | ||
| 598 | } | ||
| 599 | 695 | ||
| 600 | if (self->header.needs_swap && event__swap_ops[event->header.type]) | 696 | if (session->sample_type & PERF_SAMPLE_CALLCHAIN) |
| 601 | event__swap_ops[event->header.type](event); | 697 | callchain__printf(sample); |
| 698 | } | ||
| 699 | |||
| 700 | static int perf_session_deliver_event(struct perf_session *session, | ||
| 701 | event_t *event, | ||
| 702 | struct sample_data *sample, | ||
| 703 | struct perf_event_ops *ops, | ||
| 704 | u64 file_offset) | ||
| 705 | { | ||
| 706 | dump_event(session, event, file_offset, sample); | ||
| 602 | 707 | ||
| 603 | switch (event->header.type) { | 708 | switch (event->header.type) { |
| 604 | case PERF_RECORD_SAMPLE: | 709 | case PERF_RECORD_SAMPLE: |
| 605 | return perf_session__process_sample(event, self, ops); | 710 | dump_sample(session, event, sample); |
| 711 | return ops->sample(event, sample, session); | ||
| 606 | case PERF_RECORD_MMAP: | 712 | case PERF_RECORD_MMAP: |
| 607 | return ops->mmap(event, self); | 713 | return ops->mmap(event, sample, session); |
| 608 | case PERF_RECORD_COMM: | 714 | case PERF_RECORD_COMM: |
| 609 | return ops->comm(event, self); | 715 | return ops->comm(event, sample, session); |
| 610 | case PERF_RECORD_FORK: | 716 | case PERF_RECORD_FORK: |
| 611 | return ops->fork(event, self); | 717 | return ops->fork(event, sample, session); |
| 612 | case PERF_RECORD_EXIT: | 718 | case PERF_RECORD_EXIT: |
| 613 | return ops->exit(event, self); | 719 | return ops->exit(event, sample, session); |
| 614 | case PERF_RECORD_LOST: | 720 | case PERF_RECORD_LOST: |
| 615 | return ops->lost(event, self); | 721 | return ops->lost(event, sample, session); |
| 616 | case PERF_RECORD_READ: | 722 | case PERF_RECORD_READ: |
| 617 | return ops->read(event, self); | 723 | return ops->read(event, sample, session); |
| 618 | case PERF_RECORD_THROTTLE: | 724 | case PERF_RECORD_THROTTLE: |
| 619 | return ops->throttle(event, self); | 725 | return ops->throttle(event, sample, session); |
| 620 | case PERF_RECORD_UNTHROTTLE: | 726 | case PERF_RECORD_UNTHROTTLE: |
| 621 | return ops->unthrottle(event, self); | 727 | return ops->unthrottle(event, sample, session); |
| 728 | default: | ||
| 729 | ++session->hists.stats.nr_unknown_events; | ||
| 730 | return -1; | ||
| 731 | } | ||
| 732 | } | ||
| 733 | |||
| 734 | static int perf_session__preprocess_sample(struct perf_session *session, | ||
| 735 | event_t *event, struct sample_data *sample) | ||
| 736 | { | ||
| 737 | if (event->header.type != PERF_RECORD_SAMPLE || | ||
| 738 | !(session->sample_type & PERF_SAMPLE_CALLCHAIN)) | ||
| 739 | return 0; | ||
| 740 | |||
| 741 | if (!ip_callchain__valid(sample->callchain, event)) { | ||
| 742 | pr_debug("call-chain problem with event, skipping it.\n"); | ||
| 743 | ++session->hists.stats.nr_invalid_chains; | ||
| 744 | session->hists.stats.total_invalid_chains += sample->period; | ||
| 745 | return -EINVAL; | ||
| 746 | } | ||
| 747 | return 0; | ||
| 748 | } | ||
| 749 | |||
| 750 | static int perf_session__process_user_event(struct perf_session *session, event_t *event, | ||
| 751 | struct perf_event_ops *ops, u64 file_offset) | ||
| 752 | { | ||
| 753 | dump_event(session, event, file_offset, NULL); | ||
| 754 | |||
| 755 | /* These events are processed right away */ | ||
| 756 | switch (event->header.type) { | ||
| 622 | case PERF_RECORD_HEADER_ATTR: | 757 | case PERF_RECORD_HEADER_ATTR: |
| 623 | return ops->attr(event, self); | 758 | return ops->attr(event, session); |
| 624 | case PERF_RECORD_HEADER_EVENT_TYPE: | 759 | case PERF_RECORD_HEADER_EVENT_TYPE: |
| 625 | return ops->event_type(event, self); | 760 | return ops->event_type(event, session); |
| 626 | case PERF_RECORD_HEADER_TRACING_DATA: | 761 | case PERF_RECORD_HEADER_TRACING_DATA: |
| 627 | /* setup for reading amidst mmap */ | 762 | /* setup for reading amidst mmap */ |
| 628 | lseek(self->fd, offset + head, SEEK_SET); | 763 | lseek(session->fd, file_offset, SEEK_SET); |
| 629 | return ops->tracing_data(event, self); | 764 | return ops->tracing_data(event, session); |
| 630 | case PERF_RECORD_HEADER_BUILD_ID: | 765 | case PERF_RECORD_HEADER_BUILD_ID: |
| 631 | return ops->build_id(event, self); | 766 | return ops->build_id(event, session); |
| 632 | case PERF_RECORD_FINISHED_ROUND: | 767 | case PERF_RECORD_FINISHED_ROUND: |
| 633 | return ops->finished_round(event, self, ops); | 768 | return ops->finished_round(event, session, ops); |
| 634 | default: | 769 | default: |
| 635 | ++self->hists.stats.nr_unknown_events; | 770 | return -EINVAL; |
| 636 | return -1; | ||
| 637 | } | 771 | } |
| 638 | } | 772 | } |
| 639 | 773 | ||
| 774 | static int perf_session__process_event(struct perf_session *session, | ||
| 775 | event_t *event, | ||
| 776 | struct perf_event_ops *ops, | ||
| 777 | u64 file_offset) | ||
| 778 | { | ||
| 779 | struct sample_data sample; | ||
| 780 | int ret; | ||
| 781 | |||
| 782 | if (session->header.needs_swap && event__swap_ops[event->header.type]) | ||
| 783 | event__swap_ops[event->header.type](event); | ||
| 784 | |||
| 785 | if (event->header.type >= PERF_RECORD_HEADER_MAX) | ||
| 786 | return -EINVAL; | ||
| 787 | |||
| 788 | hists__inc_nr_events(&session->hists, event->header.type); | ||
| 789 | |||
| 790 | if (event->header.type >= PERF_RECORD_USER_TYPE_START) | ||
| 791 | return perf_session__process_user_event(session, event, ops, file_offset); | ||
| 792 | |||
| 793 | /* | ||
| 794 | * For all kernel events we get the sample data | ||
| 795 | */ | ||
| 796 | event__parse_sample(event, session, &sample); | ||
| 797 | |||
| 798 | /* Preprocess sample records - precheck callchains */ | ||
| 799 | if (perf_session__preprocess_sample(session, event, &sample)) | ||
| 800 | return 0; | ||
| 801 | |||
| 802 | if (ops->ordered_samples) { | ||
| 803 | ret = perf_session_queue_event(session, event, &sample, | ||
| 804 | file_offset); | ||
| 805 | if (ret != -ETIME) | ||
| 806 | return ret; | ||
| 807 | } | ||
| 808 | |||
| 809 | return perf_session_deliver_event(session, event, &sample, ops, | ||
| 810 | file_offset); | ||
| 811 | } | ||
| 812 | |||
| 640 | void perf_event_header__bswap(struct perf_event_header *self) | 813 | void perf_event_header__bswap(struct perf_event_header *self) |
| 641 | { | 814 | { |
| 642 | self->type = bswap_32(self->type); | 815 | self->type = bswap_32(self->type); |
| @@ -724,8 +897,7 @@ more: | |||
| 724 | } | 897 | } |
| 725 | 898 | ||
| 726 | if (size == 0 || | 899 | if (size == 0 || |
| 727 | (skip = perf_session__process_event(self, &event, ops, | 900 | (skip = perf_session__process_event(self, &event, ops, head)) < 0) { |
| 728 | 0, head)) < 0) { | ||
| 729 | dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n", | 901 | dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n", |
| 730 | head, event.header.size, event.header.type); | 902 | head, event.header.size, event.header.type); |
| 731 | /* | 903 | /* |
| @@ -740,9 +912,6 @@ more: | |||
| 740 | 912 | ||
| 741 | head += size; | 913 | head += size; |
| 742 | 914 | ||
| 743 | dump_printf("\n%#Lx [%#x]: event: %d\n", | ||
| 744 | head, event.header.size, event.header.type); | ||
| 745 | |||
| 746 | if (skip > 0) | 915 | if (skip > 0) |
| 747 | head += skip; | 916 | head += skip; |
| 748 | 917 | ||
| @@ -751,82 +920,90 @@ more: | |||
| 751 | done: | 920 | done: |
| 752 | err = 0; | 921 | err = 0; |
| 753 | out_err: | 922 | out_err: |
| 923 | perf_session_free_sample_buffers(self); | ||
| 754 | return err; | 924 | return err; |
| 755 | } | 925 | } |
| 756 | 926 | ||
| 757 | int __perf_session__process_events(struct perf_session *self, | 927 | int __perf_session__process_events(struct perf_session *session, |
| 758 | u64 data_offset, u64 data_size, | 928 | u64 data_offset, u64 data_size, |
| 759 | u64 file_size, struct perf_event_ops *ops) | 929 | u64 file_size, struct perf_event_ops *ops) |
| 760 | { | 930 | { |
| 761 | int err, mmap_prot, mmap_flags; | 931 | u64 head, page_offset, file_offset, file_pos, progress_next; |
| 762 | u64 head, shift; | 932 | int err, mmap_prot, mmap_flags, map_idx = 0; |
| 763 | u64 offset = 0; | 933 | struct ui_progress *progress; |
| 764 | size_t page_size; | 934 | size_t page_size, mmap_size; |
| 935 | char *buf, *mmaps[8]; | ||
| 765 | event_t *event; | 936 | event_t *event; |
| 766 | uint32_t size; | 937 | uint32_t size; |
| 767 | char *buf; | ||
| 768 | struct ui_progress *progress = ui_progress__new("Processing events...", | ||
| 769 | self->size); | ||
| 770 | if (progress == NULL) | ||
| 771 | return -1; | ||
| 772 | 938 | ||
| 773 | perf_event_ops__fill_defaults(ops); | 939 | perf_event_ops__fill_defaults(ops); |
| 774 | 940 | ||
| 775 | page_size = sysconf(_SC_PAGESIZE); | 941 | page_size = sysconf(_SC_PAGESIZE); |
| 776 | 942 | ||
| 777 | head = data_offset; | 943 | page_offset = page_size * (data_offset / page_size); |
| 778 | shift = page_size * (head / page_size); | 944 | file_offset = page_offset; |
| 779 | offset += shift; | 945 | head = data_offset - page_offset; |
| 780 | head -= shift; | 946 | |
| 947 | if (data_offset + data_size < file_size) | ||
| 948 | file_size = data_offset + data_size; | ||
| 949 | |||
| 950 | progress_next = file_size / 16; | ||
| 951 | progress = ui_progress__new("Processing events...", file_size); | ||
| 952 | if (progress == NULL) | ||
| 953 | return -1; | ||
| 954 | |||
| 955 | mmap_size = session->mmap_window; | ||
| 956 | if (mmap_size > file_size) | ||
| 957 | mmap_size = file_size; | ||
| 958 | |||
| 959 | memset(mmaps, 0, sizeof(mmaps)); | ||
| 781 | 960 | ||
| 782 | mmap_prot = PROT_READ; | 961 | mmap_prot = PROT_READ; |
| 783 | mmap_flags = MAP_SHARED; | 962 | mmap_flags = MAP_SHARED; |
| 784 | 963 | ||
| 785 | if (self->header.needs_swap) { | 964 | if (session->header.needs_swap) { |
| 786 | mmap_prot |= PROT_WRITE; | 965 | mmap_prot |= PROT_WRITE; |
| 787 | mmap_flags = MAP_PRIVATE; | 966 | mmap_flags = MAP_PRIVATE; |
| 788 | } | 967 | } |
| 789 | remap: | 968 | remap: |
| 790 | buf = mmap(NULL, page_size * self->mmap_window, mmap_prot, | 969 | buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, session->fd, |
| 791 | mmap_flags, self->fd, offset); | 970 | file_offset); |
| 792 | if (buf == MAP_FAILED) { | 971 | if (buf == MAP_FAILED) { |
| 793 | pr_err("failed to mmap file\n"); | 972 | pr_err("failed to mmap file\n"); |
| 794 | err = -errno; | 973 | err = -errno; |
| 795 | goto out_err; | 974 | goto out_err; |
| 796 | } | 975 | } |
| 976 | mmaps[map_idx] = buf; | ||
| 977 | map_idx = (map_idx + 1) & (ARRAY_SIZE(mmaps) - 1); | ||
| 978 | file_pos = file_offset + head; | ||
| 797 | 979 | ||
| 798 | more: | 980 | more: |
| 799 | event = (event_t *)(buf + head); | 981 | event = (event_t *)(buf + head); |
| 800 | ui_progress__update(progress, offset); | ||
| 801 | 982 | ||
| 802 | if (self->header.needs_swap) | 983 | if (session->header.needs_swap) |
| 803 | perf_event_header__bswap(&event->header); | 984 | perf_event_header__bswap(&event->header); |
| 804 | size = event->header.size; | 985 | size = event->header.size; |
| 805 | if (size == 0) | 986 | if (size == 0) |
| 806 | size = 8; | 987 | size = 8; |
| 807 | 988 | ||
| 808 | if (head + event->header.size >= page_size * self->mmap_window) { | 989 | if (head + event->header.size >= mmap_size) { |
| 809 | int munmap_ret; | 990 | if (mmaps[map_idx]) { |
| 810 | 991 | munmap(mmaps[map_idx], mmap_size); | |
| 811 | shift = page_size * (head / page_size); | 992 | mmaps[map_idx] = NULL; |
| 812 | 993 | } | |
| 813 | munmap_ret = munmap(buf, page_size * self->mmap_window); | ||
| 814 | assert(munmap_ret == 0); | ||
| 815 | 994 | ||
| 816 | offset += shift; | 995 | page_offset = page_size * (head / page_size); |
| 817 | head -= shift; | 996 | file_offset += page_offset; |
| 997 | head -= page_offset; | ||
| 818 | goto remap; | 998 | goto remap; |
| 819 | } | 999 | } |
| 820 | 1000 | ||
| 821 | size = event->header.size; | 1001 | size = event->header.size; |
| 822 | 1002 | ||
| 823 | dump_printf("\n%#Lx [%#x]: event: %d\n", | ||
| 824 | offset + head, event->header.size, event->header.type); | ||
| 825 | |||
| 826 | if (size == 0 || | 1003 | if (size == 0 || |
| 827 | perf_session__process_event(self, event, ops, offset, head) < 0) { | 1004 | perf_session__process_event(session, event, ops, file_pos) < 0) { |
| 828 | dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n", | 1005 | dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n", |
| 829 | offset + head, event->header.size, | 1006 | file_offset + head, event->header.size, |
| 830 | event->header.type); | 1007 | event->header.type); |
| 831 | /* | 1008 | /* |
| 832 | * assume we lost track of the stream, check alignment, and | 1009 | * assume we lost track of the stream, check alignment, and |
| @@ -839,19 +1016,49 @@ more: | |||
| 839 | } | 1016 | } |
| 840 | 1017 | ||
| 841 | head += size; | 1018 | head += size; |
| 1019 | file_pos += size; | ||
| 842 | 1020 | ||
| 843 | if (offset + head >= data_offset + data_size) | 1021 | if (file_pos >= progress_next) { |
| 844 | goto done; | 1022 | progress_next += file_size / 16; |
| 1023 | ui_progress__update(progress, file_pos); | ||
| 1024 | } | ||
| 845 | 1025 | ||
| 846 | if (offset + head < file_size) | 1026 | if (file_pos < file_size) |
| 847 | goto more; | 1027 | goto more; |
| 848 | done: | 1028 | |
| 849 | err = 0; | 1029 | err = 0; |
| 850 | /* do the final flush for ordered samples */ | 1030 | /* do the final flush for ordered samples */ |
| 851 | self->ordered_samples.next_flush = ULLONG_MAX; | 1031 | session->ordered_samples.next_flush = ULLONG_MAX; |
| 852 | flush_sample_queue(self, ops); | 1032 | flush_sample_queue(session, ops); |
| 853 | out_err: | 1033 | out_err: |
| 854 | ui_progress__delete(progress); | 1034 | ui_progress__delete(progress); |
| 1035 | |||
| 1036 | if (ops->lost == event__process_lost && | ||
| 1037 | session->hists.stats.total_lost != 0) { | ||
| 1038 | ui__warning("Processed %Lu events and LOST %Lu!\n\n" | ||
| 1039 | "Check IO/CPU overload!\n\n", | ||
| 1040 | session->hists.stats.total_period, | ||
| 1041 | session->hists.stats.total_lost); | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | if (session->hists.stats.nr_unknown_events != 0) { | ||
| 1045 | ui__warning("Found %u unknown events!\n\n" | ||
| 1046 | "Is this an older tool processing a perf.data " | ||
| 1047 | "file generated by a more recent tool?\n\n" | ||
| 1048 | "If that is not the case, consider " | ||
| 1049 | "reporting to linux-kernel@vger.kernel.org.\n\n", | ||
| 1050 | session->hists.stats.nr_unknown_events); | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | if (session->hists.stats.nr_invalid_chains != 0) { | ||
| 1054 | ui__warning("Found invalid callchains!\n\n" | ||
| 1055 | "%u out of %u events were discarded for this reason.\n\n" | ||
| 1056 | "Consider reporting to linux-kernel@vger.kernel.org.\n\n", | ||
| 1057 | session->hists.stats.nr_invalid_chains, | ||
| 1058 | session->hists.stats.nr_events[PERF_RECORD_SAMPLE]); | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | perf_session_free_sample_buffers(session); | ||
| 855 | return err; | 1062 | return err; |
| 856 | } | 1063 | } |
| 857 | 1064 | ||
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 9fa0fc2a863f..ac36f99f14af 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
| @@ -17,8 +17,12 @@ struct ordered_samples { | |||
| 17 | u64 last_flush; | 17 | u64 last_flush; |
| 18 | u64 next_flush; | 18 | u64 next_flush; |
| 19 | u64 max_timestamp; | 19 | u64 max_timestamp; |
| 20 | struct list_head samples_head; | 20 | struct list_head samples; |
| 21 | struct sample_queue *last_inserted; | 21 | struct list_head sample_cache; |
| 22 | struct list_head to_free; | ||
| 23 | struct sample_queue *sample_buffer; | ||
| 24 | struct sample_queue *last_sample; | ||
| 25 | int sample_buffer_idx; | ||
| 22 | }; | 26 | }; |
| 23 | 27 | ||
| 24 | struct perf_session { | 28 | struct perf_session { |
| @@ -42,6 +46,8 @@ struct perf_session { | |||
| 42 | int fd; | 46 | int fd; |
| 43 | bool fd_pipe; | 47 | bool fd_pipe; |
| 44 | bool repipe; | 48 | bool repipe; |
| 49 | bool sample_id_all; | ||
| 50 | u16 id_hdr_size; | ||
| 45 | int cwdlen; | 51 | int cwdlen; |
| 46 | char *cwd; | 52 | char *cwd; |
| 47 | struct ordered_samples ordered_samples; | 53 | struct ordered_samples ordered_samples; |
| @@ -50,7 +56,9 @@ struct perf_session { | |||
| 50 | 56 | ||
| 51 | struct perf_event_ops; | 57 | struct perf_event_ops; |
| 52 | 58 | ||
| 53 | typedef int (*event_op)(event_t *self, struct perf_session *session); | 59 | typedef int (*event_op)(event_t *self, struct sample_data *sample, |
| 60 | struct perf_session *session); | ||
| 61 | typedef int (*event_synth_op)(event_t *self, struct perf_session *session); | ||
| 54 | typedef int (*event_op2)(event_t *self, struct perf_session *session, | 62 | typedef int (*event_op2)(event_t *self, struct perf_session *session, |
| 55 | struct perf_event_ops *ops); | 63 | struct perf_event_ops *ops); |
| 56 | 64 | ||
| @@ -63,8 +71,8 @@ struct perf_event_ops { | |||
| 63 | lost, | 71 | lost, |
| 64 | read, | 72 | read, |
| 65 | throttle, | 73 | throttle, |
| 66 | unthrottle, | 74 | unthrottle; |
| 67 | attr, | 75 | event_synth_op attr, |
| 68 | event_type, | 76 | event_type, |
| 69 | tracing_data, | 77 | tracing_data, |
| 70 | build_id; | 78 | build_id; |
| @@ -100,6 +108,8 @@ int perf_session__create_kernel_maps(struct perf_session *self); | |||
| 100 | 108 | ||
| 101 | int do_read(int fd, void *buf, size_t size); | 109 | int do_read(int fd, void *buf, size_t size); |
| 102 | void perf_session__update_sample_type(struct perf_session *self); | 110 | void perf_session__update_sample_type(struct perf_session *self); |
| 111 | void perf_session__set_sample_id_all(struct perf_session *session, bool value); | ||
| 112 | void perf_session__set_sample_type(struct perf_session *session, u64 type); | ||
| 103 | void perf_session__remove_thread(struct perf_session *self, struct thread *th); | 113 | void perf_session__remove_thread(struct perf_session *self, struct thread *th); |
| 104 | 114 | ||
| 105 | static inline | 115 | static inline |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index b62a553cc67d..f44fa541d56e 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
| @@ -170,7 +170,7 @@ static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf, | |||
| 170 | return repsep_snprintf(bf, size, "%-*s", width, dso_name); | 170 | return repsep_snprintf(bf, size, "%-*s", width, dso_name); |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | return repsep_snprintf(bf, size, "%*Lx", width, self->ip); | 173 | return repsep_snprintf(bf, size, "%-*s", width, "[unknown]"); |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | /* --sort symbol */ | 176 | /* --sort symbol */ |
| @@ -196,7 +196,7 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, | |||
| 196 | 196 | ||
| 197 | if (verbose) { | 197 | if (verbose) { |
| 198 | char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!'; | 198 | char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!'; |
| 199 | ret += repsep_snprintf(bf, size, "%*Lx %c ", | 199 | ret += repsep_snprintf(bf, size, "%-#*llx %c ", |
| 200 | BITS_PER_LONG / 4, self->ip, o); | 200 | BITS_PER_LONG / 4, self->ip, o); |
| 201 | } | 201 | } |
| 202 | 202 | ||
| @@ -205,7 +205,7 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, | |||
| 205 | ret += repsep_snprintf(bf + ret, size - ret, "%s", | 205 | ret += repsep_snprintf(bf + ret, size - ret, "%s", |
| 206 | self->ms.sym->name); | 206 | self->ms.sym->name); |
| 207 | else | 207 | else |
| 208 | ret += repsep_snprintf(bf + ret, size - ret, "%*Lx", | 208 | ret += repsep_snprintf(bf + ret, size - ret, "%-#*llx", |
| 209 | BITS_PER_LONG / 4, self->ip); | 209 | BITS_PER_LONG / 4, self->ip); |
| 210 | 210 | ||
| 211 | return ret; | 211 | return ret; |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index d628c8d1cf5e..ceefa6568def 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
| @@ -121,7 +121,7 @@ static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) | |||
| 121 | * We still haven't the actual symbols, so guess the | 121 | * We still haven't the actual symbols, so guess the |
| 122 | * last map final address. | 122 | * last map final address. |
| 123 | */ | 123 | */ |
| 124 | curr->end = ~0UL; | 124 | curr->end = ~0ULL; |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | static void map_groups__fixup_end(struct map_groups *self) | 127 | static void map_groups__fixup_end(struct map_groups *self) |
| @@ -1836,8 +1836,8 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, | |||
| 1836 | const char *kallsyms_filename = NULL; | 1836 | const char *kallsyms_filename = NULL; |
| 1837 | char *kallsyms_allocated_filename = NULL; | 1837 | char *kallsyms_allocated_filename = NULL; |
| 1838 | /* | 1838 | /* |
| 1839 | * Step 1: if the user specified a vmlinux filename, use it and only | 1839 | * Step 1: if the user specified a kallsyms or vmlinux filename, use |
| 1840 | * it, reporting errors to the user if it cannot be used. | 1840 | * it and only it, reporting errors to the user if it cannot be used. |
| 1841 | * | 1841 | * |
| 1842 | * For instance, try to analyse an ARM perf.data file _without_ a | 1842 | * For instance, try to analyse an ARM perf.data file _without_ a |
| 1843 | * build-id, or if the user specifies the wrong path to the right | 1843 | * build-id, or if the user specifies the wrong path to the right |
| @@ -1850,6 +1850,11 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, | |||
| 1850 | * validation in dso__load_vmlinux and will bail out if they don't | 1850 | * validation in dso__load_vmlinux and will bail out if they don't |
| 1851 | * match. | 1851 | * match. |
| 1852 | */ | 1852 | */ |
| 1853 | if (symbol_conf.kallsyms_name != NULL) { | ||
| 1854 | kallsyms_filename = symbol_conf.kallsyms_name; | ||
| 1855 | goto do_kallsyms; | ||
| 1856 | } | ||
| 1857 | |||
| 1853 | if (symbol_conf.vmlinux_name != NULL) { | 1858 | if (symbol_conf.vmlinux_name != NULL) { |
| 1854 | err = dso__load_vmlinux(self, map, | 1859 | err = dso__load_vmlinux(self, map, |
| 1855 | symbol_conf.vmlinux_name, filter); | 1860 | symbol_conf.vmlinux_name, filter); |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 038f2201ee09..12defbe18c13 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
| @@ -72,6 +72,7 @@ struct symbol_conf { | |||
| 72 | show_cpu_utilization, | 72 | show_cpu_utilization, |
| 73 | initialized; | 73 | initialized; |
| 74 | const char *vmlinux_name, | 74 | const char *vmlinux_name, |
| 75 | *kallsyms_name, | ||
| 75 | *source_prefix, | 76 | *source_prefix, |
| 76 | *field_sep; | 77 | *field_sep; |
| 77 | const char *default_guest_vmlinux_name, | 78 | const char *default_guest_vmlinux_name, |
diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c index 056c69521a38..7b5a8926624e 100644 --- a/tools/perf/util/ui/util.c +++ b/tools/perf/util/ui/util.c | |||
| @@ -104,10 +104,24 @@ out_destroy_form: | |||
| 104 | return rc; | 104 | return rc; |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | static const char yes[] = "Yes", no[] = "No"; | 107 | static const char yes[] = "Yes", no[] = "No", |
| 108 | warning_str[] = "Warning!", ok[] = "Ok"; | ||
| 108 | 109 | ||
| 109 | bool ui__dialog_yesno(const char *msg) | 110 | bool ui__dialog_yesno(const char *msg) |
| 110 | { | 111 | { |
| 111 | /* newtWinChoice should really be accepting const char pointers... */ | 112 | /* newtWinChoice should really be accepting const char pointers... */ |
| 112 | return newtWinChoice(NULL, (char *)yes, (char *)no, (char *)msg) == 1; | 113 | return newtWinChoice(NULL, (char *)yes, (char *)no, (char *)msg) == 1; |
| 113 | } | 114 | } |
| 115 | |||
| 116 | void ui__warning(const char *format, ...) | ||
| 117 | { | ||
| 118 | va_list args; | ||
| 119 | |||
| 120 | va_start(args, format); | ||
| 121 | if (use_browser > 0) | ||
| 122 | newtWinMessagev((char *)warning_str, (char *)ok, | ||
| 123 | (char *)format, args); | ||
| 124 | else | ||
| 125 | vfprintf(stderr, format, args); | ||
| 126 | va_end(args); | ||
| 127 | } | ||
