Perf-script supports '-S' or '--symbol' options to only list the
trace records in given symbols. Symbol is typically a name
or hex address. If it's hex address, it is the start address of
one symbol.
While it would be useful if we can filter trace records by any hex
address (not only the start address of symbol). So now we support
filtering trace records by more conditions, such as:
- symbol name
- start address of symbol
- any hexadecimal address
- address range
The comparison order is defined as:
1. symbol name comparison
2. symbol start address comparison.
3. any hexadecimal address comparison.
4. address range comparison.
Let's see some examples:
root@kbl-ppc:~# ./perf script -S 0xffffffff9ca77308
perf 18123 [000] 6142863.075104: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [000] 6142863.075107: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [000] 6142863.075108: 10 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [001] 6142863.075156: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [001] 6142863.075158: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [001] 6142863.075159: 17 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [002] 6142863.075202: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [002] 6142863.075204: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [002] 6142863.075205: 16 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [003] 6142863.075250: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [003] 6142863.075252: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [003] 6142863.075253: 16 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
Filter the traced records by hex address 0xffffffff9ca77308.
Easy to use, we support the hex address without '0x' prefix,
e.g.
./perf script -S ffffffff9ca77308
It has the same effect.
We also support to filter trace records by a address range.
root@kbl-ppc:~# ./perf script -S ffffffff9ca77304 --addr-range 16
perf 18123 [000] 6142863.075104: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [000] 6142863.075107: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [000] 6142863.075108: 10 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [000] 6142863.075109: 273 cycles: ffffffff9ca7730a native_write_msr+0xa ([kernel.kallsyms])
perf 18123 [001] 6142863.075156: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [001] 6142863.075158: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [001] 6142863.075159: 17 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [001] 6142863.075160: 456 cycles: ffffffff9ca7730f native_write_msr+0xf ([kernel.kallsyms])
perf 18123 [002] 6142863.075202: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [002] 6142863.075204: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [002] 6142863.075205: 16 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [002] 6142863.075206: 436 cycles: ffffffff9ca7730f native_write_msr+0xf ([kernel.kallsyms])
perf 18123 [003] 6142863.075250: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [003] 6142863.075252: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [003] 6142863.075253: 16 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [003] 6142863.075254: 436 cycles: ffffffff9ca7730f native_write_msr+0xf ([kernel.kallsyms])
perf 18123 [004] 6142863.075299: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [004] 6142863.075301: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [004] 6142863.075302: 16 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [004] 6142863.075303: 431 cycles: ffffffff9ca7730f native_write_msr+0xf ([kernel.kallsyms])
perf 18123 [005] 6142863.075348: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [005] 6142863.075349: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [005] 6142863.075351: 17 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [005] 6142863.075352: 454 cycles: ffffffff9ca7730f native_write_msr+0xf ([kernel.kallsyms])
perf 18123 [006] 6142863.075390: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [006] 6142863.075392: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [006] 6142863.075393: 17 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [006] 6142863.075394: 459 cycles: ffffffff9ca7730f native_write_msr+0xf ([kernel.kallsyms])
perf 18123 [007] 6142863.075438: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [007] 6142863.075440: 1 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [007] 6142863.075441: 17 cycles: ffffffff9ca77308 native_write_msr+0x8 ([kernel.kallsyms])
perf 18123 [007] 6142863.075442: 466 cycles: ffffffff9ca7730f native_write_msr+0xf ([kernel.kallsyms])
Filter the traced records from address range [0xffffffff9ca77304, 0xffffffff9ca77304 + 15].
Signed-off-by: Jin Yao <[email protected]>
---
tools/perf/Documentation/perf-script.txt | 19 +++++++++++++
tools/perf/builtin-script.c | 2 ++
tools/perf/util/event.c | 36 ++++++++++++++++++++++++
tools/perf/util/symbol_conf.h | 1 +
4 files changed, 58 insertions(+)
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 44d37210fc8f..0ef2261baeb9 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -422,9 +422,28 @@ include::itrace.txt[]
Only consider the listed symbols. Symbols are typically a name
but they may also be hexadecimal address.
+ The hexadecimal address may be the start address of a symbol or
+ any other address to filter the trace records.
+
For example, to select the symbol noploop or the address 0x4007a0:
perf script --symbols=noploop,0x4007a0
+ Support filtering trace records by symbol name, start address of
+ symbol, any hexadecimal address and address range.
+
+ The comparison order is:
+ 1. symbol name comparison
+ 2. symbol start address comparison.
+ 3. any hexadecimal address comparison.
+ 4. address range comparison (see --addr-range).
+
+--addr-range::
+ Use with -S or --symbols to list traced records within address range.
+
+ For example, to list the traced records within the address range
+ [0x4007a0, 0x0x4007a9]:
+ perf script -S 0x4007a0 --addr-range 10
+
--call-trace::
Show call stream for intel_pt traces. The CPUs are interleaved, but
can be filtered with -C.
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index edacfa98d073..e0feda33dbb9 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -3525,6 +3525,8 @@ int cmd_script(int argc, const char **argv)
"system-wide collection from all CPUs"),
OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
"only consider these symbols"),
+ OPT_INTEGER(0, "addr-range", &symbol_conf.addr_range,
+ "Use with -S to list traced records within address range"),
OPT_CALLBACK_OPTARG(0, "insn-trace", &itrace_synth_opts, NULL, NULL,
"Decode instructions from itrace", parse_insn_trace),
OPT_CALLBACK_OPTARG(0, "xed", NULL, NULL, NULL,
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index fbe8578e4c47..525b859cb445 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -645,6 +645,22 @@ struct symbol *thread__find_symbol_fb(struct thread *thread, u8 cpumode,
return al->sym;
}
+static bool check_address_range(struct strlist *sym_list, int addr_range,
+ struct addr_location *al)
+{
+ struct str_node *pos;
+ char *endptr;
+ u64 addr, al_addr = al->map->unmap_ip(al->map, al->addr);
+
+ strlist__for_each_entry(pos, sym_list) {
+ addr = strtoull(pos->s, &endptr, 16);
+ if (al_addr >= addr && al_addr < addr + addr_range)
+ return true;
+ }
+
+ return false;
+}
+
/*
* Callers need to drop the reference to al->thread, obtained in
* machine__findnew_thread()
@@ -709,6 +725,26 @@ int machine__resolve(struct machine *machine, struct addr_location *al,
ret = strlist__has_entry(symbol_conf.sym_list,
al_addr_str);
}
+ if (!ret && al->map) {
+ snprintf(al_addr_str, sz, "0x%"PRIx64,
+ al->map->unmap_ip(al->map, al->addr));
+ ret = strlist__has_entry(symbol_conf.sym_list,
+ al_addr_str);
+ if (!ret) {
+ /* Check for hex without "0x" prefix */
+ snprintf(al_addr_str, sz, "%"PRIx64,
+ al->map->unmap_ip(al->map, al->addr));
+ ret = strlist__has_entry(symbol_conf.sym_list,
+ al_addr_str);
+ }
+
+ if (!ret && symbol_conf.addr_range) {
+ ret = check_address_range(symbol_conf.sym_list,
+ symbol_conf.addr_range,
+ al);
+ }
+ }
+
if (!ret)
al->filtered |= (1 << HIST_FILTER__SYMBOL);
}
diff --git a/tools/perf/util/symbol_conf.h b/tools/perf/util/symbol_conf.h
index b18f9c8dbb75..07e247cdb43c 100644
--- a/tools/perf/util/symbol_conf.h
+++ b/tools/perf/util/symbol_conf.h
@@ -75,6 +75,7 @@ struct symbol_conf {
int res_sample;
int pad_output_len_dso;
int group_sort_idx;
+ int addr_range;
};
extern struct symbol_conf symbol_conf;
--
2.17.1
On Mon, Jan 25, 2021 at 07:27:49AM +0800, Jin Yao wrote:
SNIP
> perf script --symbols=noploop,0x4007a0
>
> + Support filtering trace records by symbol name, start address of
> + symbol, any hexadecimal address and address range.
> +
> + The comparison order is:
> + 1. symbol name comparison
> + 2. symbol start address comparison.
> + 3. any hexadecimal address comparison.
> + 4. address range comparison (see --addr-range).
> +
> +--addr-range::
> + Use with -S or --symbols to list traced records within address range.
> +
> + For example, to list the traced records within the address range
> + [0x4007a0, 0x0x4007a9]:
> + perf script -S 0x4007a0 --addr-range 10
> +
> --call-trace::
> Show call stream for intel_pt traces. The CPUs are interleaved, but
> can be filtered with -C.
> diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
> index edacfa98d073..e0feda33dbb9 100644
> --- a/tools/perf/builtin-script.c
> +++ b/tools/perf/builtin-script.c
> @@ -3525,6 +3525,8 @@ int cmd_script(int argc, const char **argv)
> "system-wide collection from all CPUs"),
> OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
> "only consider these symbols"),
> + OPT_INTEGER(0, "addr-range", &symbol_conf.addr_range,
> + "Use with -S to list traced records within address range"),
> OPT_CALLBACK_OPTARG(0, "insn-trace", &itrace_synth_opts, NULL, NULL,
> "Decode instructions from itrace", parse_insn_trace),
> OPT_CALLBACK_OPTARG(0, "xed", NULL, NULL, NULL,
> diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
> index fbe8578e4c47..525b859cb445 100644
> --- a/tools/perf/util/event.c
> +++ b/tools/perf/util/event.c
> @@ -645,6 +645,22 @@ struct symbol *thread__find_symbol_fb(struct thread *thread, u8 cpumode,
> return al->sym;
> }
>
> +static bool check_address_range(struct strlist *sym_list, int addr_range,
> + struct addr_location *al)
> +{
> + struct str_node *pos;
> + char *endptr;
> + u64 addr, al_addr = al->map->unmap_ip(al->map, al->addr);
> +
> + strlist__for_each_entry(pos, sym_list) {
> + addr = strtoull(pos->s, &endptr, 16);
> + if (al_addr >= addr && al_addr < addr + addr_range)
> + return true;
> + }
> +
> + return false;
> +}
> +
> /*
> * Callers need to drop the reference to al->thread, obtained in
> * machine__findnew_thread()
> @@ -709,6 +725,26 @@ int machine__resolve(struct machine *machine, struct addr_location *al,
> ret = strlist__has_entry(symbol_conf.sym_list,
> al_addr_str);
> }
> + if (!ret && al->map) {
> + snprintf(al_addr_str, sz, "0x%"PRIx64,
> + al->map->unmap_ip(al->map, al->addr));
> + ret = strlist__has_entry(symbol_conf.sym_list,
> + al_addr_str);
> + if (!ret) {
> + /* Check for hex without "0x" prefix */
> + snprintf(al_addr_str, sz, "%"PRIx64,
> + al->map->unmap_ip(al->map, al->addr));
> + ret = strlist__has_entry(symbol_conf.sym_list,
> + al_addr_str);
> + }
that seems tricky.. what if user specify more leading zeros,
I think it'd be better to search intlist instead
we could move all 'address' entries from sym_list to
new intlist (in symbol__init) and use it for this search
jirka
Hi Jiri,
On 1/28/2021 7:13 AM, Jiri Olsa wrote:
>> @@ -709,6 +725,26 @@ int machine__resolve(struct machine *machine, struct addr_location *al,
>> ret = strlist__has_entry(symbol_conf.sym_list,
>> al_addr_str);
>> }
>> + if (!ret && al->map) {
>> + snprintf(al_addr_str, sz, "0x%"PRIx64,
>> + al->map->unmap_ip(al->map, al->addr));
>> + ret = strlist__has_entry(symbol_conf.sym_list,
>> + al_addr_str);
>> + if (!ret) {
>> + /* Check for hex without "0x" prefix */
>> + snprintf(al_addr_str, sz, "%"PRIx64,
>> + al->map->unmap_ip(al->map, al->addr));
>> + ret = strlist__has_entry(symbol_conf.sym_list,
>> + al_addr_str);
>> + }
> that seems tricky.. what if user specify more leading zeros,
> I think it'd be better to search intlist instead
>
> we could move all 'address' entries from sym_list to
> new intlist (in symbol__init) and use it for this search
>
> jirka
>
intlist now only supports 'int' type.
I'm considering to use 'long' to replace original 'int' in struct int_node.
struct int_node {
struct rb_node rb_node;
- int i;
+ long i;
void *priv;
};
On 32 bits platform, sizeof(long) is 4, and on 64 bits platform, sizeof(long) is 8. So that should
be OK for storing the values such as pid/tid and address.
I'm not very clear why currently it uses 'int' for i in struct int_node, maybe something I don't
understand correctly. Please correct me if my understanding is wrong.
Thanks
Jin Yao
Em Thu, Jan 28, 2021 at 11:31:26AM +0800, Jin, Yao escreveu:
> On 1/28/2021 7:13 AM, Jiri Olsa wrote:
> > > @@ -709,6 +725,26 @@ int machine__resolve(struct machine *machine, struct addr_location *al,
> > > ret = strlist__has_entry(symbol_conf.sym_list, al_addr_str);
> > > }
> > > + if (!ret && al->map) {
> > > + snprintf(al_addr_str, sz, "0x%"PRIx64,
> > > + al->map->unmap_ip(al->map, al->addr));
> > > + ret = strlist__has_entry(symbol_conf.sym_list,
> > > + al_addr_str);
> > > + if (!ret) {
> > > + /* Check for hex without "0x" prefix */
> > > + snprintf(al_addr_str, sz, "%"PRIx64,
> > > + al->map->unmap_ip(al->map, al->addr));
> > > + ret = strlist__has_entry(symbol_conf.sym_list,
> > > + al_addr_str);
> > > + }
> > that seems tricky.. what if user specify more leading zeros,
> > I think it'd be better to search intlist instead
> > we could move all 'address' entries from sym_list to
> > new intlist (in symbol__init) and use it for this search
> intlist now only supports 'int' type.
> I'm considering to use 'long' to replace original 'int' in struct int_node.
> struct int_node {
> struct rb_node rb_node;
> - int i;
> + long i;
> void *priv;
> };
> On 32 bits platform, sizeof(long) is 4, and on 64 bits platform,
> sizeof(long) is 8. So that should be OK for storing the values such as
> pid/tid and address.
> I'm not very clear why currently it uses 'int' for i in struct int_node,
> maybe something I don't understand correctly. Please correct me if my
> understanding is wrong.
I think its ok to make it a long, it won't even enlarge the struct
because:
[acme@quaco pahole]$ pahole -C int_node ~/bin/perf
struct int_node {
struct rb_node rb_node __attribute__((__aligned__(8))); /* 0 24 */
int i; /* 24 4 */
/* XXX 4 bytes hole, try to pack */
void * priv; /* 32 8 */
/* size: 40, cachelines: 1, members: 3 */
/* sum members: 36, holes: 1, sum holes: 4 */
/* forced alignments: 1 */
/* last cacheline: 40 bytes */
} __attribute__((__aligned__(8)));
[acme@quaco pahole]$
:-)
- Arnaldo
On 1/28/2021 8:43 PM, Arnaldo Carvalho de Melo wrote:
> Em Thu, Jan 28, 2021 at 11:31:26AM +0800, Jin, Yao escreveu:
>> On 1/28/2021 7:13 AM, Jiri Olsa wrote:
>>>> @@ -709,6 +725,26 @@ int machine__resolve(struct machine *machine, struct addr_location *al,
>>>> ret = strlist__has_entry(symbol_conf.sym_list, al_addr_str);
>>>> }
>>>> + if (!ret && al->map) {
>>>> + snprintf(al_addr_str, sz, "0x%"PRIx64,
>>>> + al->map->unmap_ip(al->map, al->addr));
>>>> + ret = strlist__has_entry(symbol_conf.sym_list,
>>>> + al_addr_str);
>>>> + if (!ret) {
>>>> + /* Check for hex without "0x" prefix */
>>>> + snprintf(al_addr_str, sz, "%"PRIx64,
>>>> + al->map->unmap_ip(al->map, al->addr));
>>>> + ret = strlist__has_entry(symbol_conf.sym_list,
>>>> + al_addr_str);
>>>> + }
>>> that seems tricky.. what if user specify more leading zeros,
>>> I think it'd be better to search intlist instead
>
>>> we could move all 'address' entries from sym_list to
>>> new intlist (in symbol__init) and use it for this search
>
>> intlist now only supports 'int' type.
>
>> I'm considering to use 'long' to replace original 'int' in struct int_node.
>
>> struct int_node {
>> struct rb_node rb_node;
>> - int i;
>> + long i;
>> void *priv;
>> };
>
>> On 32 bits platform, sizeof(long) is 4, and on 64 bits platform,
>> sizeof(long) is 8. So that should be OK for storing the values such as
>> pid/tid and address.
>
>> I'm not very clear why currently it uses 'int' for i in struct int_node,
>> maybe something I don't understand correctly. Please correct me if my
>> understanding is wrong.
>
> I think its ok to make it a long, it won't even enlarge the struct
> because:
>
> [acme@quaco pahole]$ pahole -C int_node ~/bin/perf
> struct int_node {
> struct rb_node rb_node __attribute__((__aligned__(8))); /* 0 24 */
> int i; /* 24 4 */
>
> /* XXX 4 bytes hole, try to pack */
>
> void * priv; /* 32 8 */
>
> /* size: 40, cachelines: 1, members: 3 */
> /* sum members: 36, holes: 1, sum holes: 4 */
> /* forced alignments: 1 */
> /* last cacheline: 40 bytes */
> } __attribute__((__aligned__(8)));
> [acme@quaco pahole]$
>
> :-)
>
> - Arnaldo
>
Thanks Arnaldo!
OK, let me try to improve the intlist.
Thanks
Jin Yao