diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-08-12 06:16:11 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-08-12 06:16:11 -0400 |
commit | 5f1230c9b80b89f404938ff88dfa64a963f74f2c (patch) | |
tree | f829a0246125b517443de57b883bc663aad82d9d | |
parent | 709bc871923c12b284424f9d47b99dc975ba8b29 (diff) | |
parent | 4605bb55b91449a1a953a51f0334d3bc02351adb (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
User visible changes:
- Introduce 'srcfile' sort key: (Andi Kleen)
# perf record -F 10000 usleep 1
# perf report --stdio --dsos '[kernel.vmlinux]' -s srcfile
<SNIP>
# Overhead Source File
26.49% copy_page_64.S
5.49% signal.c
0.51% msr.h
#
It can be combined with other fields, for instance, experiment with
'-s srcfile,symbol'.
There are some oddities in some distros and with some specific DSOs, being
investigated, so your mileage may vary.
- Update the column width for the "srcline" sort key (Arnaldo Carvalho de Melo)
- Support per-event 'freq' term: (Namhyung Kim)
$ perf record -e 'cpu/instructions,freq=1234/',cycles -c 1000 sleep 1
$ perf evlist -F
cpu/instructions,freq=1234/: sample_freq=1234
cycles: sample_period=1000
$
Infrastructure changes:
- Move perf_counts struct and functions into separate object (Jiri Olsa)
- Unset perf_event_attr::freq when period term is set (Jiri Olsa)
- Move callchain option parsing code to util.c (Kan Liang)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
27 files changed, 292 insertions, 173 deletions
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 0d852d1bc90f..afbe45ef7e3e 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -49,6 +49,7 @@ OPTIONS | |||
49 | These params can be used to overload default config values per event. | 49 | These params can be used to overload default config values per event. |
50 | Here is a list of the params. | 50 | Here is a list of the params. |
51 | - 'period': Set event sampling period | 51 | - 'period': Set event sampling period |
52 | - 'freq': Set event sampling frequency | ||
52 | - 'time': Disable/enable time stamping. Acceptable values are 1 for | 53 | - 'time': Disable/enable time stamping. Acceptable values are 1 for |
53 | enabling time stamping. 0 for disabling time stamping. | 54 | enabling time stamping. 0 for disabling time stamping. |
54 | The default is 1. | 55 | The default is 1. |
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 960da203ec11..7b07d19e2d54 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt | |||
@@ -81,6 +81,8 @@ OPTIONS | |||
81 | - cpu: cpu number the task ran at the time of sample | 81 | - cpu: cpu number the task ran at the time of sample |
82 | - srcline: filename and line number executed at the time of sample. The | 82 | - srcline: filename and line number executed at the time of sample. The |
83 | DWARF debugging info must be provided. | 83 | DWARF debugging info must be provided. |
84 | - srcfile: file name of the source file of the same. Requires dwarf | ||
85 | information. | ||
84 | - weight: Event specific weight, e.g. memory latency or transaction | 86 | - weight: Event specific weight, e.g. memory latency or transaction |
85 | abort cost. This is the global weight. | 87 | abort cost. This is the global weight. |
86 | - local_weight: Local weight version of the weight above. | 88 | - local_weight: Local weight version of the weight above. |
@@ -354,6 +356,8 @@ OPTIONS | |||
354 | 356 | ||
355 | To disable decoding entirely, use --no-itrace. | 357 | To disable decoding entirely, use --no-itrace. |
356 | 358 | ||
359 | --full-source-path:: | ||
360 | Show the full path for source files for srcline output. | ||
357 | 361 | ||
358 | include::callchain-overhead-calculation.txt[] | 362 | include::callchain-overhead-calculation.txt[] |
359 | 363 | ||
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index e2fec5fc21e7..8e9be1f9c1dd 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt | |||
@@ -260,6 +260,9 @@ OPTIONS | |||
260 | 260 | ||
261 | To disable decoding entirely, use --no-itrace. | 261 | To disable decoding entirely, use --no-itrace. |
262 | 262 | ||
263 | --full-source-path:: | ||
264 | Show the full path for source files for srcline output. | ||
265 | |||
263 | SEE ALSO | 266 | SEE ALSO |
264 | -------- | 267 | -------- |
265 | linkperf:perf-record[1], linkperf:perf-script-perl[1], | 268 | linkperf:perf-record[1], linkperf:perf-script-perl[1], |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 3a9d1b659fcd..f301e865001f 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -738,6 +738,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
738 | OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts", | 738 | OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts", |
739 | "Instruction Tracing options", | 739 | "Instruction Tracing options", |
740 | itrace_parse_synth_opts), | 740 | itrace_parse_synth_opts), |
741 | OPT_BOOLEAN(0, "full-source-path", &srcline_full_filename, | ||
742 | "Show full source file name path for source lines"), | ||
741 | OPT_END() | 743 | OPT_END() |
742 | }; | 744 | }; |
743 | struct perf_data_file file = { | 745 | struct perf_data_file file = { |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 7912feb9a024..7b376d215e94 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -1653,6 +1653,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1653 | OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts", | 1653 | OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts", |
1654 | "Instruction Tracing options", | 1654 | "Instruction Tracing options", |
1655 | itrace_parse_synth_opts), | 1655 | itrace_parse_synth_opts), |
1656 | OPT_BOOLEAN(0, "full-source-path", &srcline_full_filename, | ||
1657 | "Show full source file name path for source lines"), | ||
1656 | OPT_END() | 1658 | OPT_END() |
1657 | }; | 1659 | }; |
1658 | const char * const script_subcommands[] = { "record", "report", NULL }; | 1660 | const char * const script_subcommands[] = { "record", "report", NULL }; |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index a054ddc0b2a0..7aa039bd379a 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -58,6 +58,7 @@ | |||
58 | #include "util/cpumap.h" | 58 | #include "util/cpumap.h" |
59 | #include "util/thread.h" | 59 | #include "util/thread.h" |
60 | #include "util/thread_map.h" | 60 | #include "util/thread_map.h" |
61 | #include "util/counts.h" | ||
61 | 62 | ||
62 | #include <stdlib.h> | 63 | #include <stdlib.h> |
63 | #include <sys/prctl.h> | 64 | #include <sys/prctl.h> |
diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 2ee81d74cf45..1ce0adc8b3cb 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build | |||
@@ -68,6 +68,7 @@ libperf-y += target.o | |||
68 | libperf-y += rblist.o | 68 | libperf-y += rblist.o |
69 | libperf-y += intlist.o | 69 | libperf-y += intlist.o |
70 | libperf-y += vdso.o | 70 | libperf-y += vdso.o |
71 | libperf-y += counts.o | ||
71 | libperf-y += stat.o | 72 | libperf-y += stat.o |
72 | libperf-y += stat-shadow.o | 73 | libperf-y += stat-shadow.o |
73 | libperf-y += record.o | 74 | libperf-y += record.o |
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 931cca8e6ae8..773fe13ce627 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -25,96 +25,9 @@ | |||
25 | 25 | ||
26 | __thread struct callchain_cursor callchain_cursor; | 26 | __thread struct callchain_cursor callchain_cursor; |
27 | 27 | ||
28 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | ||
29 | static int get_stack_size(const char *str, unsigned long *_size) | ||
30 | { | ||
31 | char *endptr; | ||
32 | unsigned long size; | ||
33 | unsigned long max_size = round_down(USHRT_MAX, sizeof(u64)); | ||
34 | |||
35 | size = strtoul(str, &endptr, 0); | ||
36 | |||
37 | do { | ||
38 | if (*endptr) | ||
39 | break; | ||
40 | |||
41 | size = round_up(size, sizeof(u64)); | ||
42 | if (!size || size > max_size) | ||
43 | break; | ||
44 | |||
45 | *_size = size; | ||
46 | return 0; | ||
47 | |||
48 | } while (0); | ||
49 | |||
50 | pr_err("callchain: Incorrect stack dump size (max %ld): %s\n", | ||
51 | max_size, str); | ||
52 | return -1; | ||
53 | } | ||
54 | #endif /* HAVE_DWARF_UNWIND_SUPPORT */ | ||
55 | |||
56 | int parse_callchain_record_opt(const char *arg, struct callchain_param *param) | 28 | int parse_callchain_record_opt(const char *arg, struct callchain_param *param) |
57 | { | 29 | { |
58 | char *tok, *name, *saveptr = NULL; | 30 | return parse_callchain_record(arg, param); |
59 | char *buf; | ||
60 | int ret = -1; | ||
61 | |||
62 | /* We need buffer that we know we can write to. */ | ||
63 | buf = malloc(strlen(arg) + 1); | ||
64 | if (!buf) | ||
65 | return -ENOMEM; | ||
66 | |||
67 | strcpy(buf, arg); | ||
68 | |||
69 | tok = strtok_r((char *)buf, ",", &saveptr); | ||
70 | name = tok ? : (char *)buf; | ||
71 | |||
72 | do { | ||
73 | /* Framepointer style */ | ||
74 | if (!strncmp(name, "fp", sizeof("fp"))) { | ||
75 | if (!strtok_r(NULL, ",", &saveptr)) { | ||
76 | param->record_mode = CALLCHAIN_FP; | ||
77 | ret = 0; | ||
78 | } else | ||
79 | pr_err("callchain: No more arguments " | ||
80 | "needed for --call-graph fp\n"); | ||
81 | break; | ||
82 | |||
83 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | ||
84 | /* Dwarf style */ | ||
85 | } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { | ||
86 | const unsigned long default_stack_dump_size = 8192; | ||
87 | |||
88 | ret = 0; | ||
89 | param->record_mode = CALLCHAIN_DWARF; | ||
90 | param->dump_size = default_stack_dump_size; | ||
91 | |||
92 | tok = strtok_r(NULL, ",", &saveptr); | ||
93 | if (tok) { | ||
94 | unsigned long size = 0; | ||
95 | |||
96 | ret = get_stack_size(tok, &size); | ||
97 | param->dump_size = size; | ||
98 | } | ||
99 | #endif /* HAVE_DWARF_UNWIND_SUPPORT */ | ||
100 | } else if (!strncmp(name, "lbr", sizeof("lbr"))) { | ||
101 | if (!strtok_r(NULL, ",", &saveptr)) { | ||
102 | param->record_mode = CALLCHAIN_LBR; | ||
103 | ret = 0; | ||
104 | } else | ||
105 | pr_err("callchain: No more arguments " | ||
106 | "needed for --call-graph lbr\n"); | ||
107 | break; | ||
108 | } else { | ||
109 | pr_err("callchain: Unknown --call-graph option " | ||
110 | "value: %s\n", arg); | ||
111 | break; | ||
112 | } | ||
113 | |||
114 | } while (0); | ||
115 | |||
116 | free(buf); | ||
117 | return ret; | ||
118 | } | 31 | } |
119 | 32 | ||
120 | static int parse_callchain_mode(const char *value) | 33 | static int parse_callchain_mode(const char *value) |
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 68a32c2fe87a..acee2b3cd801 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
@@ -177,6 +177,7 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node * | |||
177 | bool hide_unresolved); | 177 | bool hide_unresolved); |
178 | 178 | ||
179 | extern const char record_callchain_help[]; | 179 | extern const char record_callchain_help[]; |
180 | extern int parse_callchain_record(const char *arg, struct callchain_param *param); | ||
180 | int parse_callchain_record_opt(const char *arg, struct callchain_param *param); | 181 | int parse_callchain_record_opt(const char *arg, struct callchain_param *param); |
181 | int parse_callchain_report_opt(const char *arg); | 182 | int parse_callchain_report_opt(const char *arg); |
182 | int perf_callchain_config(const char *var, const char *value); | 183 | int perf_callchain_config(const char *var, const char *value); |
diff --git a/tools/perf/util/counts.c b/tools/perf/util/counts.c new file mode 100644 index 000000000000..e3fde313deb2 --- /dev/null +++ b/tools/perf/util/counts.c | |||
@@ -0,0 +1,52 @@ | |||
1 | #include <stdlib.h> | ||
2 | #include "evsel.h" | ||
3 | #include "counts.h" | ||
4 | |||
5 | struct perf_counts *perf_counts__new(int ncpus, int nthreads) | ||
6 | { | ||
7 | struct perf_counts *counts = zalloc(sizeof(*counts)); | ||
8 | |||
9 | if (counts) { | ||
10 | struct xyarray *values; | ||
11 | |||
12 | values = xyarray__new(ncpus, nthreads, sizeof(struct perf_counts_values)); | ||
13 | if (!values) { | ||
14 | free(counts); | ||
15 | return NULL; | ||
16 | } | ||
17 | |||
18 | counts->values = values; | ||
19 | } | ||
20 | |||
21 | return counts; | ||
22 | } | ||
23 | |||
24 | void perf_counts__delete(struct perf_counts *counts) | ||
25 | { | ||
26 | if (counts) { | ||
27 | xyarray__delete(counts->values); | ||
28 | free(counts); | ||
29 | } | ||
30 | } | ||
31 | |||
32 | static void perf_counts__reset(struct perf_counts *counts) | ||
33 | { | ||
34 | xyarray__reset(counts->values); | ||
35 | } | ||
36 | |||
37 | void perf_evsel__reset_counts(struct perf_evsel *evsel) | ||
38 | { | ||
39 | perf_counts__reset(evsel->counts); | ||
40 | } | ||
41 | |||
42 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads) | ||
43 | { | ||
44 | evsel->counts = perf_counts__new(ncpus, nthreads); | ||
45 | return evsel->counts != NULL ? 0 : -ENOMEM; | ||
46 | } | ||
47 | |||
48 | void perf_evsel__free_counts(struct perf_evsel *evsel) | ||
49 | { | ||
50 | perf_counts__delete(evsel->counts); | ||
51 | evsel->counts = NULL; | ||
52 | } | ||
diff --git a/tools/perf/util/counts.h b/tools/perf/util/counts.h new file mode 100644 index 000000000000..34d8baaf558a --- /dev/null +++ b/tools/perf/util/counts.h | |||
@@ -0,0 +1,37 @@ | |||
1 | #ifndef __PERF_COUNTS_H | ||
2 | #define __PERF_COUNTS_H | ||
3 | |||
4 | #include "xyarray.h" | ||
5 | |||
6 | struct perf_counts_values { | ||
7 | union { | ||
8 | struct { | ||
9 | u64 val; | ||
10 | u64 ena; | ||
11 | u64 run; | ||
12 | }; | ||
13 | u64 values[3]; | ||
14 | }; | ||
15 | }; | ||
16 | |||
17 | struct perf_counts { | ||
18 | s8 scaled; | ||
19 | struct perf_counts_values aggr; | ||
20 | struct xyarray *values; | ||
21 | }; | ||
22 | |||
23 | |||
24 | static inline struct perf_counts_values* | ||
25 | perf_counts(struct perf_counts *counts, int cpu, int thread) | ||
26 | { | ||
27 | return xyarray__entry(counts->values, cpu, thread); | ||
28 | } | ||
29 | |||
30 | struct perf_counts *perf_counts__new(int ncpus, int nthreads); | ||
31 | void perf_counts__delete(struct perf_counts *counts); | ||
32 | |||
33 | void perf_evsel__reset_counts(struct perf_evsel *evsel); | ||
34 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads); | ||
35 | void perf_evsel__free_counts(struct perf_evsel *evsel); | ||
36 | |||
37 | #endif /* __PERF_COUNTS_H */ | ||
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index f572f469a30d..04fddddc6b6f 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -598,6 +598,11 @@ static void apply_config_terms(struct perf_evsel *evsel) | |||
598 | switch (term->type) { | 598 | switch (term->type) { |
599 | case PERF_EVSEL__CONFIG_TERM_PERIOD: | 599 | case PERF_EVSEL__CONFIG_TERM_PERIOD: |
600 | attr->sample_period = term->val.period; | 600 | attr->sample_period = term->val.period; |
601 | attr->freq = 0; | ||
602 | break; | ||
603 | case PERF_EVSEL__CONFIG_TERM_FREQ: | ||
604 | attr->sample_freq = term->val.freq; | ||
605 | attr->freq = 1; | ||
601 | break; | 606 | break; |
602 | case PERF_EVSEL__CONFIG_TERM_TIME: | 607 | case PERF_EVSEL__CONFIG_TERM_TIME: |
603 | if (term->val.time) | 608 | if (term->val.time) |
@@ -2153,8 +2158,13 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, | |||
2153 | printed += perf_event_attr__fprintf(fp, &evsel->attr, | 2158 | printed += perf_event_attr__fprintf(fp, &evsel->attr, |
2154 | __print_attr__fprintf, &first); | 2159 | __print_attr__fprintf, &first); |
2155 | } else if (details->freq) { | 2160 | } else if (details->freq) { |
2156 | printed += comma_fprintf(fp, &first, " sample_freq=%" PRIu64, | 2161 | const char *term = "sample_freq"; |
2157 | (u64)evsel->attr.sample_freq); | 2162 | |
2163 | if (!evsel->attr.freq) | ||
2164 | term = "sample_period"; | ||
2165 | |||
2166 | printed += comma_fprintf(fp, &first, " %s=%" PRIu64, | ||
2167 | term, (u64)evsel->attr.sample_freq); | ||
2158 | } | 2168 | } |
2159 | out: | 2169 | out: |
2160 | fputc('\n', fp); | 2170 | fputc('\n', fp); |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 6a129081f3ad..fdf2674ab339 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -9,7 +9,7 @@ | |||
9 | #include "xyarray.h" | 9 | #include "xyarray.h" |
10 | #include "symbol.h" | 10 | #include "symbol.h" |
11 | #include "cpumap.h" | 11 | #include "cpumap.h" |
12 | #include "stat.h" | 12 | #include "counts.h" |
13 | 13 | ||
14 | struct perf_evsel; | 14 | struct perf_evsel; |
15 | 15 | ||
@@ -39,6 +39,7 @@ struct cgroup_sel; | |||
39 | */ | 39 | */ |
40 | enum { | 40 | enum { |
41 | PERF_EVSEL__CONFIG_TERM_PERIOD, | 41 | PERF_EVSEL__CONFIG_TERM_PERIOD, |
42 | PERF_EVSEL__CONFIG_TERM_FREQ, | ||
42 | PERF_EVSEL__CONFIG_TERM_TIME, | 43 | PERF_EVSEL__CONFIG_TERM_TIME, |
43 | PERF_EVSEL__CONFIG_TERM_MAX, | 44 | PERF_EVSEL__CONFIG_TERM_MAX, |
44 | }; | 45 | }; |
@@ -48,6 +49,7 @@ struct perf_evsel_config_term { | |||
48 | int type; | 49 | int type; |
49 | union { | 50 | union { |
50 | u64 period; | 51 | u64 period; |
52 | u64 freq; | ||
51 | bool time; | 53 | bool time; |
52 | } val; | 54 | } val; |
53 | }; | 55 | }; |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index a6e9ddd37913..6bccfae334b1 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -151,6 +151,12 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) | |||
151 | hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12); | 151 | hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12); |
152 | hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12); | 152 | hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12); |
153 | 153 | ||
154 | if (h->srcline) | ||
155 | hists__new_col_len(hists, HISTC_SRCLINE, strlen(h->srcline)); | ||
156 | |||
157 | if (h->srcfile) | ||
158 | hists__new_col_len(hists, HISTC_SRCFILE, strlen(h->srcfile)); | ||
159 | |||
154 | if (h->transaction) | 160 | if (h->transaction) |
155 | hists__new_col_len(hists, HISTC_TRANSACTION, | 161 | hists__new_col_len(hists, HISTC_TRANSACTION, |
156 | hist_entry__transaction_len()); | 162 | hist_entry__transaction_len()); |
@@ -761,6 +767,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, | |||
761 | struct hist_entry **he_cache = iter->priv; | 767 | struct hist_entry **he_cache = iter->priv; |
762 | struct hist_entry *he; | 768 | struct hist_entry *he; |
763 | struct hist_entry he_tmp = { | 769 | struct hist_entry he_tmp = { |
770 | .hists = evsel__hists(evsel), | ||
764 | .cpu = al->cpu, | 771 | .cpu = al->cpu, |
765 | .thread = al->thread, | 772 | .thread = al->thread, |
766 | .comm = thread__comm(al->thread), | 773 | .comm = thread__comm(al->thread), |
@@ -945,6 +952,8 @@ void hist_entry__delete(struct hist_entry *he) | |||
945 | 952 | ||
946 | zfree(&he->stat_acc); | 953 | zfree(&he->stat_acc); |
947 | free_srcline(he->srcline); | 954 | free_srcline(he->srcline); |
955 | if (he->srcfile && he->srcfile[0]) | ||
956 | free(he->srcfile); | ||
948 | free_callchain(he->callchain); | 957 | free_callchain(he->callchain); |
949 | free(he); | 958 | free(he); |
950 | } | 959 | } |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index e2f712f85d2e..bc528d54e457 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -30,6 +30,7 @@ enum hist_column { | |||
30 | HISTC_PARENT, | 30 | HISTC_PARENT, |
31 | HISTC_CPU, | 31 | HISTC_CPU, |
32 | HISTC_SRCLINE, | 32 | HISTC_SRCLINE, |
33 | HISTC_SRCFILE, | ||
33 | HISTC_MISPREDICT, | 34 | HISTC_MISPREDICT, |
34 | HISTC_IN_TX, | 35 | HISTC_IN_TX, |
35 | HISTC_ABORT, | 36 | HISTC_ABORT, |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 828936dc3f1e..dbf315df4220 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -597,6 +597,9 @@ do { \ | |||
597 | case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: | 597 | case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: |
598 | CHECK_TYPE_VAL(NUM); | 598 | CHECK_TYPE_VAL(NUM); |
599 | break; | 599 | break; |
600 | case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ: | ||
601 | CHECK_TYPE_VAL(NUM); | ||
602 | break; | ||
600 | case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: | 603 | case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: |
601 | /* | 604 | /* |
602 | * TODO uncomment when the field is available | 605 | * TODO uncomment when the field is available |
@@ -659,6 +662,9 @@ do { \ | |||
659 | case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: | 662 | case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: |
660 | ADD_CONFIG_TERM(PERIOD, period, term->val.num); | 663 | ADD_CONFIG_TERM(PERIOD, period, term->val.num); |
661 | break; | 664 | break; |
665 | case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ: | ||
666 | ADD_CONFIG_TERM(FREQ, freq, term->val.num); | ||
667 | break; | ||
662 | case PARSE_EVENTS__TERM_TYPE_TIME: | 668 | case PARSE_EVENTS__TERM_TYPE_TIME: |
663 | ADD_CONFIG_TERM(TIME, time, term->val.num); | 669 | ADD_CONFIG_TERM(TIME, time, term->val.num); |
664 | break; | 670 | break; |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index e6f9aacc1cce..ce2d13a16226 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -62,6 +62,7 @@ enum { | |||
62 | PARSE_EVENTS__TERM_TYPE_CONFIG2, | 62 | PARSE_EVENTS__TERM_TYPE_CONFIG2, |
63 | PARSE_EVENTS__TERM_TYPE_NAME, | 63 | PARSE_EVENTS__TERM_TYPE_NAME, |
64 | PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD, | 64 | PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD, |
65 | PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ, | ||
65 | PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, | 66 | PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, |
66 | PARSE_EVENTS__TERM_TYPE_TIME, | 67 | PARSE_EVENTS__TERM_TYPE_TIME, |
67 | }; | 68 | }; |
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index f5427505ae77..4306f5ad75c7 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l | |||
@@ -182,6 +182,7 @@ config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); } | |||
182 | config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); } | 182 | config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); } |
183 | name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); } | 183 | name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); } |
184 | period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } | 184 | period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } |
185 | freq { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ); } | ||
185 | branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } | 186 | branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } |
186 | time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); } | 187 | time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); } |
187 | , { return ','; } | 188 | , { return ','; } |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index d4b0e6454bc6..d85f11b8cacf 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -634,7 +634,7 @@ static char *formats_error_string(struct list_head *formats) | |||
634 | { | 634 | { |
635 | struct perf_pmu_format *format; | 635 | struct perf_pmu_format *format; |
636 | char *err, *str; | 636 | char *err, *str; |
637 | static const char *static_terms = "config,config1,config2,name,period,branch_type,time\n"; | 637 | static const char *static_terms = "config,config1,config2,name,period,freq,branch_type,time\n"; |
638 | unsigned i = 0; | 638 | unsigned i = 0; |
639 | 639 | ||
640 | if (!asprintf(&str, "valid terms:")) | 640 | if (!asprintf(&str, "valid terms:")) |
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index 0766d98c5da5..51be28b1bca2 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources | |||
@@ -16,7 +16,7 @@ util/util.c | |||
16 | util/xyarray.c | 16 | util/xyarray.c |
17 | util/cgroup.c | 17 | util/cgroup.c |
18 | util/rblist.c | 18 | util/rblist.c |
19 | util/stat.c | 19 | util/counts.c |
20 | util/strlist.c | 20 | util/strlist.c |
21 | util/trace-event.c | 21 | util/trace-event.c |
22 | ../lib/rbtree.c | 22 | ../lib/rbtree.c |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 5177088a71d3..c0c32b050e45 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -319,6 +319,57 @@ struct sort_entry sort_srcline = { | |||
319 | .se_width_idx = HISTC_SRCLINE, | 319 | .se_width_idx = HISTC_SRCLINE, |
320 | }; | 320 | }; |
321 | 321 | ||
322 | /* --sort srcfile */ | ||
323 | |||
324 | static char no_srcfile[1]; | ||
325 | |||
326 | static char *get_srcfile(struct hist_entry *e) | ||
327 | { | ||
328 | char *sf, *p; | ||
329 | struct map *map = e->ms.map; | ||
330 | |||
331 | sf = get_srcline(map->dso, map__rip_2objdump(map, e->ip), | ||
332 | e->ms.sym, true); | ||
333 | p = strchr(sf, ':'); | ||
334 | if (p && *sf) { | ||
335 | *p = 0; | ||
336 | return sf; | ||
337 | } | ||
338 | free(sf); | ||
339 | return no_srcfile; | ||
340 | } | ||
341 | |||
342 | static int64_t | ||
343 | sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right) | ||
344 | { | ||
345 | if (!left->srcfile) { | ||
346 | if (!left->ms.map) | ||
347 | left->srcfile = no_srcfile; | ||
348 | else | ||
349 | left->srcfile = get_srcfile(left); | ||
350 | } | ||
351 | if (!right->srcfile) { | ||
352 | if (!right->ms.map) | ||
353 | right->srcfile = no_srcfile; | ||
354 | else | ||
355 | right->srcfile = get_srcfile(right); | ||
356 | } | ||
357 | return strcmp(right->srcfile, left->srcfile); | ||
358 | } | ||
359 | |||
360 | static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf, | ||
361 | size_t size, unsigned int width) | ||
362 | { | ||
363 | return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcfile); | ||
364 | } | ||
365 | |||
366 | struct sort_entry sort_srcfile = { | ||
367 | .se_header = "Source File", | ||
368 | .se_cmp = sort__srcfile_cmp, | ||
369 | .se_snprintf = hist_entry__srcfile_snprintf, | ||
370 | .se_width_idx = HISTC_SRCFILE, | ||
371 | }; | ||
372 | |||
322 | /* --sort parent */ | 373 | /* --sort parent */ |
323 | 374 | ||
324 | static int64_t | 375 | static int64_t |
@@ -1196,6 +1247,7 @@ static struct sort_dimension common_sort_dimensions[] = { | |||
1196 | DIM(SORT_PARENT, "parent", sort_parent), | 1247 | DIM(SORT_PARENT, "parent", sort_parent), |
1197 | DIM(SORT_CPU, "cpu", sort_cpu), | 1248 | DIM(SORT_CPU, "cpu", sort_cpu), |
1198 | DIM(SORT_SRCLINE, "srcline", sort_srcline), | 1249 | DIM(SORT_SRCLINE, "srcline", sort_srcline), |
1250 | DIM(SORT_SRCFILE, "srcfile", sort_srcfile), | ||
1199 | DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), | 1251 | DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), |
1200 | DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), | 1252 | DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), |
1201 | DIM(SORT_TRANSACTION, "transaction", sort_transaction), | 1253 | DIM(SORT_TRANSACTION, "transaction", sort_transaction), |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index bc6c87a76d16..3c2a399f8f5b 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -114,6 +114,7 @@ struct hist_entry { | |||
114 | }; | 114 | }; |
115 | }; | 115 | }; |
116 | char *srcline; | 116 | char *srcline; |
117 | char *srcfile; | ||
117 | struct symbol *parent; | 118 | struct symbol *parent; |
118 | struct rb_root sorted_chain; | 119 | struct rb_root sorted_chain; |
119 | struct branch_info *branch_info; | 120 | struct branch_info *branch_info; |
@@ -172,6 +173,7 @@ enum sort_type { | |||
172 | SORT_PARENT, | 173 | SORT_PARENT, |
173 | SORT_CPU, | 174 | SORT_CPU, |
174 | SORT_SRCLINE, | 175 | SORT_SRCLINE, |
176 | SORT_SRCFILE, | ||
175 | SORT_LOCAL_WEIGHT, | 177 | SORT_LOCAL_WEIGHT, |
176 | SORT_GLOBAL_WEIGHT, | 178 | SORT_GLOBAL_WEIGHT, |
177 | SORT_TRANSACTION, | 179 | SORT_TRANSACTION, |
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index c93fb0c5bd0b..fc08248f08ca 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c | |||
@@ -10,6 +10,8 @@ | |||
10 | 10 | ||
11 | #include "symbol.h" | 11 | #include "symbol.h" |
12 | 12 | ||
13 | bool srcline_full_filename; | ||
14 | |||
13 | #ifdef HAVE_LIBBFD_SUPPORT | 15 | #ifdef HAVE_LIBBFD_SUPPORT |
14 | 16 | ||
15 | /* | 17 | /* |
@@ -277,7 +279,9 @@ char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, | |||
277 | if (!addr2line(dso_name, addr, &file, &line, dso)) | 279 | if (!addr2line(dso_name, addr, &file, &line, dso)) |
278 | goto out; | 280 | goto out; |
279 | 281 | ||
280 | if (asprintf(&srcline, "%s:%u", basename(file), line) < 0) { | 282 | if (asprintf(&srcline, "%s:%u", |
283 | srcline_full_filename ? file : basename(file), | ||
284 | line) < 0) { | ||
281 | free(file); | 285 | free(file); |
282 | goto out; | 286 | goto out; |
283 | } | 287 | } |
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index c5c709cdc3ce..415c359de465 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c | |||
@@ -97,55 +97,6 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel) | |||
97 | } | 97 | } |
98 | } | 98 | } |
99 | 99 | ||
100 | struct perf_counts *perf_counts__new(int ncpus, int nthreads) | ||
101 | { | ||
102 | struct perf_counts *counts = zalloc(sizeof(*counts)); | ||
103 | |||
104 | if (counts) { | ||
105 | struct xyarray *values; | ||
106 | |||
107 | values = xyarray__new(ncpus, nthreads, sizeof(struct perf_counts_values)); | ||
108 | if (!values) { | ||
109 | free(counts); | ||
110 | return NULL; | ||
111 | } | ||
112 | |||
113 | counts->values = values; | ||
114 | } | ||
115 | |||
116 | return counts; | ||
117 | } | ||
118 | |||
119 | void perf_counts__delete(struct perf_counts *counts) | ||
120 | { | ||
121 | if (counts) { | ||
122 | xyarray__delete(counts->values); | ||
123 | free(counts); | ||
124 | } | ||
125 | } | ||
126 | |||
127 | static void perf_counts__reset(struct perf_counts *counts) | ||
128 | { | ||
129 | xyarray__reset(counts->values); | ||
130 | } | ||
131 | |||
132 | void perf_evsel__reset_counts(struct perf_evsel *evsel) | ||
133 | { | ||
134 | perf_counts__reset(evsel->counts); | ||
135 | } | ||
136 | |||
137 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads) | ||
138 | { | ||
139 | evsel->counts = perf_counts__new(ncpus, nthreads); | ||
140 | return evsel->counts != NULL ? 0 : -ENOMEM; | ||
141 | } | ||
142 | |||
143 | void perf_evsel__free_counts(struct perf_evsel *evsel) | ||
144 | { | ||
145 | perf_counts__delete(evsel->counts); | ||
146 | evsel->counts = NULL; | ||
147 | } | ||
148 | |||
149 | void perf_evsel__reset_stat_priv(struct perf_evsel *evsel) | 100 | void perf_evsel__reset_stat_priv(struct perf_evsel *evsel) |
150 | { | 101 | { |
151 | int i; | 102 | int i; |
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index 0b897b083682..62448c8175d3 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h | |||
@@ -33,23 +33,6 @@ enum aggr_mode { | |||
33 | AGGR_THREAD, | 33 | AGGR_THREAD, |
34 | }; | 34 | }; |
35 | 35 | ||
36 | struct perf_counts_values { | ||
37 | union { | ||
38 | struct { | ||
39 | u64 val; | ||
40 | u64 ena; | ||
41 | u64 run; | ||
42 | }; | ||
43 | u64 values[3]; | ||
44 | }; | ||
45 | }; | ||
46 | |||
47 | struct perf_counts { | ||
48 | s8 scaled; | ||
49 | struct perf_counts_values aggr; | ||
50 | struct xyarray *values; | ||
51 | }; | ||
52 | |||
53 | struct perf_stat_config { | 36 | struct perf_stat_config { |
54 | enum aggr_mode aggr_mode; | 37 | enum aggr_mode aggr_mode; |
55 | bool scale; | 38 | bool scale; |
@@ -57,12 +40,6 @@ struct perf_stat_config { | |||
57 | unsigned int interval; | 40 | unsigned int interval; |
58 | }; | 41 | }; |
59 | 42 | ||
60 | static inline struct perf_counts_values* | ||
61 | perf_counts(struct perf_counts *counts, int cpu, int thread) | ||
62 | { | ||
63 | return xyarray__entry(counts->values, cpu, thread); | ||
64 | } | ||
65 | |||
66 | void update_stats(struct stats *stats, u64 val); | 43 | void update_stats(struct stats *stats, u64 val); |
67 | double avg_stats(struct stats *stats); | 44 | double avg_stats(struct stats *stats); |
68 | double stddev_stats(struct stats *stats); | 45 | double stddev_stats(struct stats *stats); |
@@ -96,13 +73,6 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count, | |||
96 | void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, | 73 | void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, |
97 | double avg, int cpu, enum aggr_mode aggr); | 74 | double avg, int cpu, enum aggr_mode aggr); |
98 | 75 | ||
99 | struct perf_counts *perf_counts__new(int ncpus, int nthreads); | ||
100 | void perf_counts__delete(struct perf_counts *counts); | ||
101 | |||
102 | void perf_evsel__reset_counts(struct perf_evsel *evsel); | ||
103 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads); | ||
104 | void perf_evsel__free_counts(struct perf_evsel *evsel); | ||
105 | |||
106 | void perf_evsel__reset_stat_priv(struct perf_evsel *evsel); | 76 | void perf_evsel__reset_stat_priv(struct perf_evsel *evsel); |
107 | int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel); | 77 | int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel); |
108 | void perf_evsel__free_stat_priv(struct perf_evsel *evsel); | 78 | void perf_evsel__free_stat_priv(struct perf_evsel *evsel); |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index edc2d633b332..f7adf1203df1 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -566,6 +566,96 @@ unsigned long parse_tag_value(const char *str, struct parse_tag *tags) | |||
566 | return (unsigned long) -1; | 566 | return (unsigned long) -1; |
567 | } | 567 | } |
568 | 568 | ||
569 | int get_stack_size(const char *str, unsigned long *_size) | ||
570 | { | ||
571 | char *endptr; | ||
572 | unsigned long size; | ||
573 | unsigned long max_size = round_down(USHRT_MAX, sizeof(u64)); | ||
574 | |||
575 | size = strtoul(str, &endptr, 0); | ||
576 | |||
577 | do { | ||
578 | if (*endptr) | ||
579 | break; | ||
580 | |||
581 | size = round_up(size, sizeof(u64)); | ||
582 | if (!size || size > max_size) | ||
583 | break; | ||
584 | |||
585 | *_size = size; | ||
586 | return 0; | ||
587 | |||
588 | } while (0); | ||
589 | |||
590 | pr_err("callchain: Incorrect stack dump size (max %ld): %s\n", | ||
591 | max_size, str); | ||
592 | return -1; | ||
593 | } | ||
594 | |||
595 | int parse_callchain_record(const char *arg, struct callchain_param *param) | ||
596 | { | ||
597 | char *tok, *name, *saveptr = NULL; | ||
598 | char *buf; | ||
599 | int ret = -1; | ||
600 | |||
601 | /* We need buffer that we know we can write to. */ | ||
602 | buf = malloc(strlen(arg) + 1); | ||
603 | if (!buf) | ||
604 | return -ENOMEM; | ||
605 | |||
606 | strcpy(buf, arg); | ||
607 | |||
608 | tok = strtok_r((char *)buf, ",", &saveptr); | ||
609 | name = tok ? : (char *)buf; | ||
610 | |||
611 | do { | ||
612 | /* Framepointer style */ | ||
613 | if (!strncmp(name, "fp", sizeof("fp"))) { | ||
614 | if (!strtok_r(NULL, ",", &saveptr)) { | ||
615 | param->record_mode = CALLCHAIN_FP; | ||
616 | ret = 0; | ||
617 | } else | ||
618 | pr_err("callchain: No more arguments " | ||
619 | "needed for --call-graph fp\n"); | ||
620 | break; | ||
621 | |||
622 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | ||
623 | /* Dwarf style */ | ||
624 | } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { | ||
625 | const unsigned long default_stack_dump_size = 8192; | ||
626 | |||
627 | ret = 0; | ||
628 | param->record_mode = CALLCHAIN_DWARF; | ||
629 | param->dump_size = default_stack_dump_size; | ||
630 | |||
631 | tok = strtok_r(NULL, ",", &saveptr); | ||
632 | if (tok) { | ||
633 | unsigned long size = 0; | ||
634 | |||
635 | ret = get_stack_size(tok, &size); | ||
636 | param->dump_size = size; | ||
637 | } | ||
638 | #endif /* HAVE_DWARF_UNWIND_SUPPORT */ | ||
639 | } else if (!strncmp(name, "lbr", sizeof("lbr"))) { | ||
640 | if (!strtok_r(NULL, ",", &saveptr)) { | ||
641 | param->record_mode = CALLCHAIN_LBR; | ||
642 | ret = 0; | ||
643 | } else | ||
644 | pr_err("callchain: No more arguments " | ||
645 | "needed for --call-graph lbr\n"); | ||
646 | break; | ||
647 | } else { | ||
648 | pr_err("callchain: Unknown --call-graph option " | ||
649 | "value: %s\n", arg); | ||
650 | break; | ||
651 | } | ||
652 | |||
653 | } while (0); | ||
654 | |||
655 | free(buf); | ||
656 | return ret; | ||
657 | } | ||
658 | |||
569 | int filename__read_str(const char *filename, char **buf, size_t *sizep) | 659 | int filename__read_str(const char *filename, char **buf, size_t *sizep) |
570 | { | 660 | { |
571 | size_t size = 0, alloc_size = 0; | 661 | size_t size = 0, alloc_size = 0; |
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 20d625a4cacf..88a891562a47 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -318,6 +318,7 @@ static inline int path__join3(char *bf, size_t size, | |||
318 | struct dso; | 318 | struct dso; |
319 | struct symbol; | 319 | struct symbol; |
320 | 320 | ||
321 | extern bool srcline_full_filename; | ||
321 | char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, | 322 | char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, |
322 | bool show_sym); | 323 | bool show_sym); |
323 | void free_srcline(char *srcline); | 324 | void free_srcline(char *srcline); |
@@ -351,4 +352,6 @@ static inline char *asprintf_expr_not_in_ints(const char *var, size_t nints, int | |||
351 | return asprintf_expr_inout_ints(var, false, nints, ints); | 352 | return asprintf_expr_inout_ints(var, false, nints, ints); |
352 | } | 353 | } |
353 | 354 | ||
355 | int get_stack_size(const char *str, unsigned long *_size); | ||
356 | |||
354 | #endif /* GIT_COMPAT_UTIL_H */ | 357 | #endif /* GIT_COMPAT_UTIL_H */ |