tools/perf: Add bitfield_swap to handle branch_stack endian issue
PATCH v2 1/2 tools/perf: Add bitfield_swap to handle branch_stack endian issue
branch_stack struct has bit field definition which produces different bit ordering for big/little endian. Because of this, when branch_stack sample is collected in a BE system and viewed/reported in a LE system, bit fields of the branch stack are not presented properly. To address this issue, a evsel__bitfield_swap_branch_stack() is defined and introduced in evsel__parse_sample.
---
Changelog v1:
- Renamed function and macro
- Added comments in code
tools/perf/util/evsel.c | 74 +++++++++++++++++++++++++++++++++++++++-- tools/perf/util/evsel.h | 13 ++++++++ 2 files changed, 85 insertions(+), 2 deletions(-)
tools/perf/util/evsel.c +72 -2
@@ -2221,6 +2221,51 @@ void __weak arch_perf_parse_sample_weight(struct perf_sample *data, data->weight = *array; } +u64 evsel__bitfield_swap_branch_flags (u64 value) +{ +u64 new_val =0 ; + +/* +* branch_flags +* union { +* u64 values; +* struct { +* mispred:1 //target mispredicted +* predicted:1 //target predicted +* in_tx:1 //in transaction +* abort:1 //transaction abort +* cycles:16 //cycle count to last branch +* type:4 //branch type +* reserved:40 +* } +* } +* +* Avoid bswap64() the entire branch_flag.value, +* as it has variable bit-field sizes. Instead the +* macro takes the bit-field position/size, +* swaps it based on the host endianness. +*/ +if (bigendian ()) { + new_val =bitfield_swap (value,0 ,1 ); + new_val |=bitfield_swap (value,1 ,1 ); + new_val |=bitfield_swap (value,2 ,1 ); + new_val |=bitfield_swap (value,3 ,1 ); + new_val |=bitfield_swap (value,4 ,16 ); + new_val |=bitfield_swap (value,20 ,4 ); + new_val |=bitfield_swap (value,24 ,40 ); + }else { + new_val =bitfield_swap (value,63 ,1 ); + new_val |=bitfield_swap (value,62 ,1 ); + new_val |=bitfield_swap (value,61 ,1 ); + new_val |=bitfield_swap (value,60 ,1 ); + new_val |=bitfield_swap (value,44 ,16 ); + new_val |=bitfield_swap (value,40 ,4 ); + new_val |=bitfield_swap (value,0 ,40 ); + } + +return new_val; +} +int evsel__parse_sample (struct evsel *evsel,union perf_event *event,struct perf_sample *data) {
@@ -2408,6 +2453,8 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,if (type &PERF_SAMPLE_BRANCH_STACK ) {const u64 max_branch_nr =UINT64_MAX /sizeof (struct branch_entry ); +struct branch_entry *e; +unsigned int i;OVERFLOW_CHECK_u64 (array); data->branch_stack = (struct branch_stack *)array++;
@@ -2416,10 +2463,33 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,return -EFAULT ; sz = data->branch_stack->nr *sizeof (struct branch_entry ); -if (evsel__has_branch_hw_idx (evsel)) +if (evsel__has_branch_hw_idx (evsel)) { sz +=sizeof (u64); -else + e = &data->branch_stack->entries[0 ]; + }else { data->no_hw_idx = true; +/* +* if the PERF_SAMPLE_BRANCH_HW_INDEX is not applied, +* only nr and entries[] will be output by kernel. +*/ + e = (struct branch_entry *)&data->branch_stack->hw_idx; + } + +if (swapped) { +/* +* struct branch_flag does not have endian +* specific bit field definition. And bswap +* will not resolve the issue, since these +* are bit fields. +* +* evsel__bitfield_swap_branch_flags() uses a +* bitfield_swap macro to swap the bit position +* based on the host endians. +*/ +for (i =0 ; i < data->branch_stack->nr; i++, e++) + e->flags.value =evsel__bitfield_swap_branch_flags (e->flags.value); + } +OVERFLOW_CHECK (array, sz, max_size); array = (void *)array + sz; }
tools/perf/util/evsel.h +13 -0
@@ -482,4 +482,17 @@ struct evsel *evsel__leader(struct evsel *evsel);bool evsel__has_leader (struct evsel *evsel,struct evsel *leader);bool evsel__is_leader (struct evsel *evsel);void evsel__set_leader (struct evsel *evsel,struct evsel *leader); + +/* +* Macro to swap the bit-field postition and size. +* Used when, +* - dont need to swap the entire u64 && +* - when u64 has variable bit-field sizes && +* - when presented in a host endian which is different +* than the source endian of the perf.data file +*/ +#define bitfield_swap (src, pos, size) \ + ((((src) >> (pos)) & ((1ull << (size)) - 1)) << (63 - ((pos) + (size) - 1))) + +u64 evsel__bitfield_swap_branch_flags (u64 value);#endif /* __PERF_EVSEL_H */
Signature · 1 line
2.31.1
PATCH v2 2/2 tools/perf/test: Add endian test for struct branch_flags
Extend sample-parsing test to include branch_flag endian-reverse test. Patch include "util/trace-event.h" to sample-parsing for importing bigendian() and extends samples_same() to include "needs_swap" to detect/enable check for endian-swap.
---
Changelog v1:
- Updated commit message
tools/perf/tests/sample-parsing.c | 43 +++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 5 deletions(-)
tools/perf/tests/sample-parsing.c +38 -5
@@ -13,6 +13,7 @@#include "evsel.h" #include "debug.h" #include "util/synthetic-events.h" +#include "util/trace-event.h" #include "tests.h"
@@ -30,9 +31,18 @@ } \ }while (0 ) +/* +* Hardcode the expected values for branch_entry flags. +* These are based on the input value (213) specified +* in branch_stack variable. + */ +#define BS_EXPECTED_BE 0xa00d000000000000 +#define BS_EXPECTED_LE 0xd5000000 +#define FLAG (s) s->branch_stack->entries[i].flags +static bool samples_same (const struct perf_sample *s1,const struct perf_sample *s2, -u64 type,u64 read_format) +u64 type,u64 read_format,bool needs_swap) {size_t i;
@@ -100,8 +110,14 @@ static bool samples_same(const struct perf_sample *s1,if (type &PERF_SAMPLE_BRANCH_STACK ) {COMP (branch_stack->nr);COMP (branch_stack->hw_idx); -for (i =0 ; i < s1->branch_stack->nr; i++) -MCOMP (branch_stack->entries[i]); +for (i =0 ; i < s1->branch_stack->nr; i++) { +if (needs_swap) +return ((bigendian ()) ? + (FLAG (s2).value ==BS_EXPECTED_BE ) : + (FLAG (s2).value ==BS_EXPECTED_LE )); +else +MCOMP (branch_stack->entries[i]); + } }if (type &PERF_SAMPLE_REGS_USER ) {
@@ -248,7 +264,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format) }, };struct sample_read_value values[] = {{1 ,5 }, {9 ,3 }, {2 ,7 }, {6 ,4 },}; -struct perf_sample sample_out; +struct perf_sample sample_out, sample_out_endian;size_t i, sz, bufsz;int err, ret =-1 ;
@@ -313,12 +329,29 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format) goto out_free; } -if (!samples_same (&sample, &sample_out, sample_type, read_format)) { +if (!samples_same (&sample, &sample_out, sample_type, read_format, evsel.needs_swap)) {pr_debug ("parsing failed for sample_type %#" PRIx64"\n" , sample_type); goto out_free; } +if (sample_type ==PERF_SAMPLE_BRANCH_STACK ) { + evsel.needs_swap = true; + evsel.sample_size =__evsel__sample_size (sample_type); + err =evsel__parse_sample (&evsel, event, &sample_out_endian); +if (err) { +pr_debug ("%s failed for sample_type %#" PRIx64", error %d\n" , +"evsel__parse_sample" , sample_type, err); + goto out_free; + } + +if (!samples_same (&sample, &sample_out_endian, sample_type, read_format, evsel.needs_swap)) { +pr_debug ("parsing failed for sample_type %#" PRIx64"\n" , + sample_type); + goto out_free; + } + } + ret =0 ; out_free:free (event);
Signature · 1 line
2.31.1
Quoted 92 lines · Madhavan Srinivasan
branch_stackstruct has bit field definition which produces different bit ordering for big/little endian. Because of this, whenbranch_stacksample is collected in a BE system and viewed/reported in a LE system, bit fields of the branch stack are not presented properly. To address this issue, aevsel__bitfield_swap_branch_stack()is defined and introduced inevsel__parse_sample.Signed-off-by Madhavan Srinivasan <[email protected]>---
Changelog v1:
- Renamed function and macro
- Added comments in codetools/perf/util/evsel.c | 74 +++++++++++++++++++++++++++++++++++++++-- tools/perf/util/evsel.h | 13 ++++++++ 2 files changed, 85 insertions(+), 2 deletions(-)tools/perf/util/evsel.c +49
-2@@ -2221,6 +2221,51 @@ void __weak arch_perf_parse_sample_weight(struct perf_sample *data, data->weight = *array; } +u64 evsel__bitfield_swap_branch_flags (u64 value) +{ +u64 new_val =0 ; + +/* +* branch_flags +* union { +* u64 values; +* struct { +* mispred:1 //target mispredicted +* predicted:1 //target predicted +* in_tx:1 //in transaction +* abort:1 //transaction abort +* cycles:16 //cycle count to last branch +* type:4 //branch type +* reserved:40 +* } +* } +* +* Avoid bswap64() the entire branch_flag.value, +* as it has variable bit-field sizes. Instead the +* macro takes the bit-field position/size, +* swaps it based on the host endianness. +*/ +if (bigendian ()) { + new_val =bitfield_swap (value,0 ,1 ); + new_val |=bitfield_swap (value,1 ,1 ); + new_val |=bitfield_swap (value,2 ,1 ); + new_val |=bitfield_swap (value,3 ,1 ); + new_val |=bitfield_swap (value,4 ,16 ); + new_val |=bitfield_swap (value,20 ,4 ); + new_val |=bitfield_swap (value,24 ,40 ); + }else { + new_val =bitfield_swap (value,63 ,1 ); + new_val |=bitfield_swap (value,62 ,1 ); + new_val |=bitfield_swap (value,61 ,1 ); + new_val |=bitfield_swap (value,60 ,1 ); + new_val |=bitfield_swap (value,44 ,16 ); + new_val |=bitfield_swap (value,40 ,4 ); + new_val |=bitfield_swap (value,0 ,40 ); + } + +return new_val; +} +int evsel__parse_sample (struct evsel *evsel,union perf_event *event,struct perf_sample *data) {@@ -2408,6 +2453,8 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,if (type &PERF_SAMPLE_BRANCH_STACK ) {const u64 max_branch_nr =UINT64_MAX /sizeof (struct branch_entry ); +struct branch_entry *e; +unsigned int i;OVERFLOW_CHECK_u64 (array); data->branch_stack = (struct branch_stack *)array++;@@ -2416,10 +2463,33 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,return -EFAULT ; sz = data->branch_stack->nr *sizeof (struct branch_entry ); -if (evsel__has_branch_hw_idx (evsel)) +if (evsel__has_branch_hw_idx (evsel)) { sz +=sizeof (u64); -else + e = &data->branch_stack->entries[0 ];
tools/perf/util/evsel.c int evsel__parse_sample(struct evsel *evsel, union perf_event *event, · line 2478
Quoted 10 lines
tools/perf/util/evsel.c +9
-0+ }else { data->no_hw_idx = true; +/* +* if the PERF_SAMPLE_BRANCH_HW_INDEX is not applied, +* only nr and entries[] will be output by kernel. +*/ + e = (struct branch_entry *)&data->branch_stack->hw_idx; + } + +if (swapped) {
thanks for all the comments, make it easy to review
tools/perf/util/evsel.c int evsel__parse_sample(struct evsel *evsel, union perf_event *event, · line 2490
Quoted 12 lines
tools/perf/util/evsel.c +12
-0+/* +* struct branch_flag does not have endian +* specific bit field definition. And bswap +* will not resolve the issue, since these +* are bit fields. +* +* evsel__bitfield_swap_branch_flags() uses a +* bitfield_swap macro to swap the bit position +* based on the host endians. +*/ +for (i =0 ; i < data->branch_stack->nr; i++, e++) + e->flags.value =evsel__bitfield_swap_branch_flags (e->flags.value);
one last thing that confuses me.. the sample is already swapped at this point, right? with perf_event__all64_swap function
should you swap it back first and then do the proper bitfield swap? like we do in PERF_SAMPLE_RAW to get proper u32 values
thanks,
jirka
Quoted 30 lines
tools/perf/util/evsel.c +2
-0+ } +OVERFLOW_CHECK (array, sz, max_size); array = (void *)array + sz; }tools/perf/util/evsel.h +13
-0@@ -482,4 +482,17 @@ struct evsel *evsel__leader(struct evsel *evsel);bool evsel__has_leader (struct evsel *evsel,struct evsel *leader);bool evsel__is_leader (struct evsel *evsel);void evsel__set_leader (struct evsel *evsel,struct evsel *leader); + +/* +* Macro to swap the bit-field postition and size. +* Used when, +* - dont need to swap the entire u64 && +* - when u64 has variable bit-field sizes && +* - when presented in a host endian which is different +* than the source endian of the perf.data file +*/ +#define bitfield_swap (src, pos, size) \ + ((((src) >> (pos)) & ((1ull << (size)) - 1)) << (63 - ((pos) + (size) - 1))) + +u64 evsel__bitfield_swap_branch_flags (u64 value);#endif /* __PERF_EVSEL_H */ Signature · 1 line
2.31.1
Quoted 120 lines · Jiri Olsa
Quoted 92 lines · Madhavan Srinivasan
branch_stackstruct has bit field definition which produces different bit ordering for big/little endian. Because of this, whenbranch_stacksample is collected in a BE system and viewed/reported in a LE system, bit fields of the branch stack are not presented properly. To address this issue, aevsel__bitfield_swap_branch_stack()is defined and introduced inevsel__parse_sample.Signed-off-by Madhavan Srinivasan <[email protected]>---
Changelog v1:
- Renamed function and macro
- Added comments in codetools/perf/util/evsel.c | 74 +++++++++++++++++++++++++++++++++++++++-- tools/perf/util/evsel.h | 13 ++++++++ 2 files changed, 85 insertions(+), 2 deletions(-)tools/perf/util/evsel.c +49
-2@@ -2221,6 +2221,51 @@ void __weak arch_perf_parse_sample_weight(struct perf_sample *data, data->weight = *array; } +u64 evsel__bitfield_swap_branch_flags (u64 value) +{ +u64 new_val =0 ; + +/* +* branch_flags +* union { +* u64 values; +* struct { +* mispred:1 //target mispredicted +* predicted:1 //target predicted +* in_tx:1 //in transaction +* abort:1 //transaction abort +* cycles:16 //cycle count to last branch +* type:4 //branch type +* reserved:40 +* } +* } +* +* Avoid bswap64() the entire branch_flag.value, +* as it has variable bit-field sizes. Instead the +* macro takes the bit-field position/size, +* swaps it based on the host endianness. +*/ +if (bigendian ()) { + new_val =bitfield_swap (value,0 ,1 ); + new_val |=bitfield_swap (value,1 ,1 ); + new_val |=bitfield_swap (value,2 ,1 ); + new_val |=bitfield_swap (value,3 ,1 ); + new_val |=bitfield_swap (value,4 ,16 ); + new_val |=bitfield_swap (value,20 ,4 ); + new_val |=bitfield_swap (value,24 ,40 ); + }else { + new_val =bitfield_swap (value,63 ,1 ); + new_val |=bitfield_swap (value,62 ,1 ); + new_val |=bitfield_swap (value,61 ,1 ); + new_val |=bitfield_swap (value,60 ,1 ); + new_val |=bitfield_swap (value,44 ,16 ); + new_val |=bitfield_swap (value,40 ,4 ); + new_val |=bitfield_swap (value,0 ,40 ); + } + +return new_val; +} +int evsel__parse_sample (struct evsel *evsel,union perf_event *event,struct perf_sample *data) {@@ -2408,6 +2453,8 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,if (type &PERF_SAMPLE_BRANCH_STACK ) {const u64 max_branch_nr =UINT64_MAX /sizeof (struct branch_entry ); +struct branch_entry *e; +unsigned int i;OVERFLOW_CHECK_u64 (array); data->branch_stack = (struct branch_stack *)array++;@@ -2416,10 +2463,33 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,return -EFAULT ; sz = data->branch_stack->nr *sizeof (struct branch_entry ); -if (evsel__has_branch_hw_idx (evsel)) +if (evsel__has_branch_hw_idx (evsel)) { sz +=sizeof (u64); -else + e = &data->branch_stack->entries[0 ];tools/perf/util/evsel.c int evsel__parse_sample(struct evsel *evsel, union perf_event *event, · line 2478
Quoted 10 lines
tools/perf/util/evsel.c +9
-0+ }else { data->no_hw_idx = true; +/* +* if the PERF_SAMPLE_BRANCH_HW_INDEX is not applied, +* only nr and entries[] will be output by kernel. +*/ + e = (struct branch_entry *)&data->branch_stack->hw_idx; + } + +if (swapped) {thanks for all the comments, make it easy to review
tools/perf/util/evsel.c int evsel__parse_sample(struct evsel *evsel, union perf_event *event, · line 2490
Quoted 12 lines
tools/perf/util/evsel.c +12
-0+/* +* struct branch_flag does not have endian +* specific bit field definition. And bswap +* will not resolve the issue, since these +* are bit fields. +* +* evsel__bitfield_swap_branch_flags() uses a +* bitfield_swap macro to swap the bit position +* based on the host endians. +*/ +for (i =0 ; i < data->branch_stack->nr; i++, e++) + e->flags.value =evsel__bitfield_swap_branch_flags (e->flags.value);one last thing that confuses me.. the sample is already swapped at this point, right? with
perf_event__all64_swapfunction
Quoted 2 lines
should you swap it back first and then do the proper bitfield swap? like we do in
PERF_SAMPLE_RAWto get proper u32 values
No, in case of PERF_SAMPLE_RAW type, first word contains the size.
Let me explain with an example (hope will not confuse further :) ), say we have branch_flag.value as 0x4000000000000000 generated in a BE system, which has predict set, now if we undo the swap done by perf_event__all64_swap, value comes out as 0x40 (in a LE system) and if this value fed to bitswap macro, we end up 0x0000000040000000, which is wrong. Instead, by not swapping back, we feed the value in the source-endian to the new macro.
Maddy
Quoted 33 lines
thanks,
jirkaQuoted 30 lines
tools/perf/util/evsel.c +2
-0+ } +OVERFLOW_CHECK (array, sz, max_size); array = (void *)array + sz; }tools/perf/util/evsel.h +13
-0@@ -482,4 +482,17 @@ struct evsel *evsel__leader(struct evsel *evsel);bool evsel__has_leader (struct evsel *evsel,struct evsel *leader);bool evsel__is_leader (struct evsel *evsel);void evsel__set_leader (struct evsel *evsel,struct evsel *leader); + +/* +* Macro to swap the bit-field postition and size. +* Used when, +* - dont need to swap the entire u64 && +* - when u64 has variable bit-field sizes && +* - when presented in a host endian which is different +* than the source endian of the perf.data file +*/ +#define bitfield_swap (src, pos, size) \ + ((((src) >> (pos)) & ((1ull << (size)) - 1)) << (63 - ((pos) + (size) - 1))) + +u64 evsel__bitfield_swap_branch_flags (u64 value);#endif /* __PERF_EVSEL_H */ Signature · 1 line
2.31.1
Quoted 9 lines · Madhavan Srinivasan
branch_stackstruct has bit field definition which produces different bit ordering for big/little endian. Because of this, whenbranch_stacksample is collected in a BE system and viewed/reported in a LE system, bit fields of the branch stack are not presented properly. To address this issue, aevsel__bitfield_swap_branch_stack()is defined and introduced inevsel__parse_sample.Signed-off-by Madhavan Srinivasan <[email protected]>
for both patches
thanks,
jirka
Quoted 135 lines
---
Changelog v1:
- Renamed function and macro
- Added comments in codetools/perf/util/evsel.c | 74 +++++++++++++++++++++++++++++++++++++++-- tools/perf/util/evsel.h | 13 ++++++++ 2 files changed, 85 insertions(+), 2 deletions(-)tools/perf/util/evsel.c +72
-2@@ -2221,6 +2221,51 @@ void __weak arch_perf_parse_sample_weight(struct perf_sample *data, data->weight = *array; } +u64 evsel__bitfield_swap_branch_flags (u64 value) +{ +u64 new_val =0 ; + +/* +* branch_flags +* union { +* u64 values; +* struct { +* mispred:1 //target mispredicted +* predicted:1 //target predicted +* in_tx:1 //in transaction +* abort:1 //transaction abort +* cycles:16 //cycle count to last branch +* type:4 //branch type +* reserved:40 +* } +* } +* +* Avoid bswap64() the entire branch_flag.value, +* as it has variable bit-field sizes. Instead the +* macro takes the bit-field position/size, +* swaps it based on the host endianness. +*/ +if (bigendian ()) { + new_val =bitfield_swap (value,0 ,1 ); + new_val |=bitfield_swap (value,1 ,1 ); + new_val |=bitfield_swap (value,2 ,1 ); + new_val |=bitfield_swap (value,3 ,1 ); + new_val |=bitfield_swap (value,4 ,16 ); + new_val |=bitfield_swap (value,20 ,4 ); + new_val |=bitfield_swap (value,24 ,40 ); + }else { + new_val =bitfield_swap (value,63 ,1 ); + new_val |=bitfield_swap (value,62 ,1 ); + new_val |=bitfield_swap (value,61 ,1 ); + new_val |=bitfield_swap (value,60 ,1 ); + new_val |=bitfield_swap (value,44 ,16 ); + new_val |=bitfield_swap (value,40 ,4 ); + new_val |=bitfield_swap (value,0 ,40 ); + } + +return new_val; +} +int evsel__parse_sample (struct evsel *evsel,union perf_event *event,struct perf_sample *data) {@@ -2408,6 +2453,8 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,if (type &PERF_SAMPLE_BRANCH_STACK ) {const u64 max_branch_nr =UINT64_MAX /sizeof (struct branch_entry ); +struct branch_entry *e; +unsigned int i;OVERFLOW_CHECK_u64 (array); data->branch_stack = (struct branch_stack *)array++;@@ -2416,10 +2463,33 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,return -EFAULT ; sz = data->branch_stack->nr *sizeof (struct branch_entry ); -if (evsel__has_branch_hw_idx (evsel)) +if (evsel__has_branch_hw_idx (evsel)) { sz +=sizeof (u64); -else + e = &data->branch_stack->entries[0 ]; + }else { data->no_hw_idx = true; +/* +* if the PERF_SAMPLE_BRANCH_HW_INDEX is not applied, +* only nr and entries[] will be output by kernel. +*/ + e = (struct branch_entry *)&data->branch_stack->hw_idx; + } + +if (swapped) { +/* +* struct branch_flag does not have endian +* specific bit field definition. And bswap +* will not resolve the issue, since these +* are bit fields. +* +* evsel__bitfield_swap_branch_flags() uses a +* bitfield_swap macro to swap the bit position +* based on the host endians. +*/ +for (i =0 ; i < data->branch_stack->nr; i++, e++) + e->flags.value =evsel__bitfield_swap_branch_flags (e->flags.value); + } +OVERFLOW_CHECK (array, sz, max_size); array = (void *)array + sz; }tools/perf/util/evsel.h +13
-0@@ -482,4 +482,17 @@ struct evsel *evsel__leader(struct evsel *evsel);bool evsel__has_leader (struct evsel *evsel,struct evsel *leader);bool evsel__is_leader (struct evsel *evsel);void evsel__set_leader (struct evsel *evsel,struct evsel *leader); + +/* +* Macro to swap the bit-field postition and size. +* Used when, +* - dont need to swap the entire u64 && +* - when u64 has variable bit-field sizes && +* - when presented in a host endian which is different +* than the source endian of the perf.data file +*/ +#define bitfield_swap (src, pos, size) \ + ((((src) >> (pos)) & ((1ull << (size)) - 1)) << (63 - ((pos) + (size) - 1))) + +u64 evsel__bitfield_swap_branch_flags (u64 value);#endif /* __PERF_EVSEL_H */ Signature · 1 line
2.31.1
Em Mon, Oct 25, 2021 at 02:07:23PM +0200, Jiri Olsa escreveu:
Quoted 9 lines · Madhavan Srinivasan
Quoted 8 lines
branch_stackstruct has bit field definition which produces different bit ordering for big/little endian. Because of this, whenbranch_stacksample is collected in a BE system and viewed/reported in a LE system, bit fields of the branch stack are not presented properly. To address this issue, aevsel__bitfield_swap_branch_stack()is defined and introduced inevsel__parse_sample.
Quoted 5 lines
Quoted 1 line
Signed-off-by Madhavan Srinivasan <[email protected]>for both patches
Acked-by Jiri Olsa <[email protected]>
Thanks, applied.
- Arnaldo
Quoted 138 lines
thanks,
jirkaQuoted 135 lines
---
Changelog v1:
- Renamed function and macro
- Added comments in codetools/perf/util/evsel.c | 74 +++++++++++++++++++++++++++++++++++++++-- tools/perf/util/evsel.h | 13 ++++++++ 2 files changed, 85 insertions(+), 2 deletions(-)tools/perf/util/evsel.c +72
-2@@ -2221,6 +2221,51 @@ void __weak arch_perf_parse_sample_weight(struct perf_sample *data, data->weight = *array; } +u64 evsel__bitfield_swap_branch_flags (u64 value) +{ +u64 new_val =0 ; + +/* +* branch_flags +* union { +* u64 values; +* struct { +* mispred:1 //target mispredicted +* predicted:1 //target predicted +* in_tx:1 //in transaction +* abort:1 //transaction abort +* cycles:16 //cycle count to last branch +* type:4 //branch type +* reserved:40 +* } +* } +* +* Avoid bswap64() the entire branch_flag.value, +* as it has variable bit-field sizes. Instead the +* macro takes the bit-field position/size, +* swaps it based on the host endianness. +*/ +if (bigendian ()) { + new_val =bitfield_swap (value,0 ,1 ); + new_val |=bitfield_swap (value,1 ,1 ); + new_val |=bitfield_swap (value,2 ,1 ); + new_val |=bitfield_swap (value,3 ,1 ); + new_val |=bitfield_swap (value,4 ,16 ); + new_val |=bitfield_swap (value,20 ,4 ); + new_val |=bitfield_swap (value,24 ,40 ); + }else { + new_val =bitfield_swap (value,63 ,1 ); + new_val |=bitfield_swap (value,62 ,1 ); + new_val |=bitfield_swap (value,61 ,1 ); + new_val |=bitfield_swap (value,60 ,1 ); + new_val |=bitfield_swap (value,44 ,16 ); + new_val |=bitfield_swap (value,40 ,4 ); + new_val |=bitfield_swap (value,0 ,40 ); + } + +return new_val; +} +int evsel__parse_sample (struct evsel *evsel,union perf_event *event,struct perf_sample *data) {@@ -2408,6 +2453,8 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,if (type &PERF_SAMPLE_BRANCH_STACK ) {const u64 max_branch_nr =UINT64_MAX /sizeof (struct branch_entry ); +struct branch_entry *e; +unsigned int i;OVERFLOW_CHECK_u64 (array); data->branch_stack = (struct branch_stack *)array++;@@ -2416,10 +2463,33 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,return -EFAULT ; sz = data->branch_stack->nr *sizeof (struct branch_entry ); -if (evsel__has_branch_hw_idx (evsel)) +if (evsel__has_branch_hw_idx (evsel)) { sz +=sizeof (u64); -else + e = &data->branch_stack->entries[0 ]; + }else { data->no_hw_idx = true; +/* +* if the PERF_SAMPLE_BRANCH_HW_INDEX is not applied, +* only nr and entries[] will be output by kernel. +*/ + e = (struct branch_entry *)&data->branch_stack->hw_idx; + } + +if (swapped) { +/* +* struct branch_flag does not have endian +* specific bit field definition. And bswap +* will not resolve the issue, since these +* are bit fields. +* +* evsel__bitfield_swap_branch_flags() uses a +* bitfield_swap macro to swap the bit position +* based on the host endians. +*/ +for (i =0 ; i < data->branch_stack->nr; i++, e++) + e->flags.value =evsel__bitfield_swap_branch_flags (e->flags.value); + } +OVERFLOW_CHECK (array, sz, max_size); array = (void *)array + sz; }tools/perf/util/evsel.h +13
-0@@ -482,4 +482,17 @@ struct evsel *evsel__leader(struct evsel *evsel);bool evsel__has_leader (struct evsel *evsel,struct evsel *leader);bool evsel__is_leader (struct evsel *evsel);void evsel__set_leader (struct evsel *evsel,struct evsel *leader); + +/* +* Macro to swap the bit-field postition and size. +* Used when, +* - dont need to swap the entire u64 && +* - when u64 has variable bit-field sizes && +* - when presented in a host endian which is different +* than the source endian of the perf.data file +*/ +#define bitfield_swap (src, pos, size) \ + ((((src) >> (pos)) & ((1ull << (size)) - 1)) << (63 - ((pos) + (size) - 1))) + +u64 evsel__bitfield_swap_branch_flags (u64 value);#endif /* __PERF_EVSEL_H */ Signature · 1 line
2.31.1
Signature · 1 line
- Arnaldo
Arnaldo Carvalho de Melo
maintainerEm Sat, Oct 16, 2021 at 06:20:58PM +0530, Madhavan Srinivasan escreveu:
Quoted 8 lines
branch_stackstruct has bit field definition which produces different bit ordering for big/little endian. Because of this, whenbranch_stacksample is collected in a BE system and viewed/reported in a LE system, bit fields of the branch stack are not presented properly. To address this issue, aevsel__bitfield_swap_branch_stack()is defined and introduced inevsel__parse_sample.
Quoted 5 lines
Signed-off-by Madhavan Srinivasan <[email protected]>---
Changelog v1:
- Renamed function and macro
- Added comments in code
[acme@quaco perf]$ perf test python
19: 'import perf' in python : FAILED!
[acme@quaco perf]$ perf test -v python
Couldn't bump rlimit(MEMLOCK), failures may take place when creating BPF maps, etc
19: 'import perf' in python :
--- start ---
test child forked, pid 991284
python usage test: "echo "import sys ; sys.path.append('/tmp/build/perf/python'); import perf" | '/usr/bin/python3' " Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: /tmp/build/perf/python/perf.cpython-39-x86_64-linux-gnu.so: undefined symbol: bigendian test child finished with -1
---- end ----
'import perf' in python: FAILED!
[acme@quaco perf]$
Quoted 129 lines
tools/perf/util/evsel.c | 74 +++++++++++++++++++++++++++++++++++++++-- tools/perf/util/evsel.h | 13 ++++++++ 2 files changed, 85 insertions(+), 2 deletions(-)tools/perf/util/evsel.c +72
-2@@ -2221,6 +2221,51 @@ void __weak arch_perf_parse_sample_weight(struct perf_sample *data, data->weight = *array; } +u64 evsel__bitfield_swap_branch_flags (u64 value) +{ +u64 new_val =0 ; + +/* +* branch_flags +* union { +* u64 values; +* struct { +* mispred:1 //target mispredicted +* predicted:1 //target predicted +* in_tx:1 //in transaction +* abort:1 //transaction abort +* cycles:16 //cycle count to last branch +* type:4 //branch type +* reserved:40 +* } +* } +* +* Avoid bswap64() the entire branch_flag.value, +* as it has variable bit-field sizes. Instead the +* macro takes the bit-field position/size, +* swaps it based on the host endianness. +*/ +if (bigendian ()) { + new_val =bitfield_swap (value,0 ,1 ); + new_val |=bitfield_swap (value,1 ,1 ); + new_val |=bitfield_swap (value,2 ,1 ); + new_val |=bitfield_swap (value,3 ,1 ); + new_val |=bitfield_swap (value,4 ,16 ); + new_val |=bitfield_swap (value,20 ,4 ); + new_val |=bitfield_swap (value,24 ,40 ); + }else { + new_val =bitfield_swap (value,63 ,1 ); + new_val |=bitfield_swap (value,62 ,1 ); + new_val |=bitfield_swap (value,61 ,1 ); + new_val |=bitfield_swap (value,60 ,1 ); + new_val |=bitfield_swap (value,44 ,16 ); + new_val |=bitfield_swap (value,40 ,4 ); + new_val |=bitfield_swap (value,0 ,40 ); + } + +return new_val; +} +int evsel__parse_sample (struct evsel *evsel,union perf_event *event,struct perf_sample *data) {@@ -2408,6 +2453,8 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,if (type &PERF_SAMPLE_BRANCH_STACK ) {const u64 max_branch_nr =UINT64_MAX /sizeof (struct branch_entry ); +struct branch_entry *e; +unsigned int i;OVERFLOW_CHECK_u64 (array); data->branch_stack = (struct branch_stack *)array++;@@ -2416,10 +2463,33 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,return -EFAULT ; sz = data->branch_stack->nr *sizeof (struct branch_entry ); -if (evsel__has_branch_hw_idx (evsel)) +if (evsel__has_branch_hw_idx (evsel)) { sz +=sizeof (u64); -else + e = &data->branch_stack->entries[0 ]; + }else { data->no_hw_idx = true; +/* +* if the PERF_SAMPLE_BRANCH_HW_INDEX is not applied, +* only nr and entries[] will be output by kernel. +*/ + e = (struct branch_entry *)&data->branch_stack->hw_idx; + } + +if (swapped) { +/* +* struct branch_flag does not have endian +* specific bit field definition. And bswap +* will not resolve the issue, since these +* are bit fields. +* +* evsel__bitfield_swap_branch_flags() uses a +* bitfield_swap macro to swap the bit position +* based on the host endians. +*/ +for (i =0 ; i < data->branch_stack->nr; i++, e++) + e->flags.value =evsel__bitfield_swap_branch_flags (e->flags.value); + } +OVERFLOW_CHECK (array, sz, max_size); array = (void *)array + sz; }tools/perf/util/evsel.h +13
-0@@ -482,4 +482,17 @@ struct evsel *evsel__leader(struct evsel *evsel);bool evsel__has_leader (struct evsel *evsel,struct evsel *leader);bool evsel__is_leader (struct evsel *evsel);void evsel__set_leader (struct evsel *evsel,struct evsel *leader); + +/* +* Macro to swap the bit-field postition and size. +* Used when, +* - dont need to swap the entire u64 && +* - when u64 has variable bit-field sizes && +* - when presented in a host endian which is different +* than the source endian of the perf.data file +*/ +#define bitfield_swap (src, pos, size) \ + ((((src) >> (pos)) & ((1ull << (size)) - 1)) << (63 - ((pos) + (size) - 1))) + +u64 evsel__bitfield_swap_branch_flags (u64 value);#endif /* __PERF_EVSEL_H */ Signature · 1 line
2.31.1
Signature · 1 line
- Arnaldo
Quoted 15 lines · Arnaldo Carvalho de Melo
Em Sat, Oct 16, 2021 at 06:20:58PM +0530, Madhavan Srinivasan escreveu:
Quoted 13 lines
branch_stackstruct has bit field definition which produces different bit ordering for big/little endian. Because of this, whenbranch_stacksample is collected in a BE system and viewed/reported in a LE system, bit fields of the branch stack are not presented properly. To address this issue, aevsel__bitfield_swap_branch_stack()is defined and introduced inevsel__parse_sample.Signed-off-by Madhavan Srinivasan <[email protected]>---
Changelog v1:
- Renamed function and macro
- Added comments in code
Please, run 'perf test' before submitting patches, it's not that difficult, please do so.
- Arnaldo
Quoted 146 lines
[acme@quaco perf]$ perf test python
19: 'import perf' in python : FAILED!
[acme@quaco perf]$ perf test -v python
Couldn't bump rlimit(MEMLOCK), failures may take place when creating BPF maps, etc
19: 'import perf' in python :
--- start ---
test child forked, pid 991284
python usage test: "echo "import sys ;sys.path.append('/tmp/build/perf/python'); import perf" | '/usr/bin/python3' " Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError:/tmp/build/perf/python/perf.cpython-39-x86_64-linux-gnu.so: undefined symbol: bigendian test child finished with -1
---- end ----
'import perf' in python: FAILED!
[acme@quaco perf]$Quoted 129 lines
tools/perf/util/evsel.c | 74 +++++++++++++++++++++++++++++++++++++++-- tools/perf/util/evsel.h | 13 ++++++++ 2 files changed, 85 insertions(+), 2 deletions(-)tools/perf/util/evsel.c +72
-2@@ -2221,6 +2221,51 @@ void __weak arch_perf_parse_sample_weight(struct perf_sample *data, data->weight = *array; } +u64 evsel__bitfield_swap_branch_flags (u64 value) +{ +u64 new_val =0 ; + +/* +* branch_flags +* union { +* u64 values; +* struct { +* mispred:1 //target mispredicted +* predicted:1 //target predicted +* in_tx:1 //in transaction +* abort:1 //transaction abort +* cycles:16 //cycle count to last branch +* type:4 //branch type +* reserved:40 +* } +* } +* +* Avoid bswap64() the entire branch_flag.value, +* as it has variable bit-field sizes. Instead the +* macro takes the bit-field position/size, +* swaps it based on the host endianness. +*/ +if (bigendian ()) { + new_val =bitfield_swap (value,0 ,1 ); + new_val |=bitfield_swap (value,1 ,1 ); + new_val |=bitfield_swap (value,2 ,1 ); + new_val |=bitfield_swap (value,3 ,1 ); + new_val |=bitfield_swap (value,4 ,16 ); + new_val |=bitfield_swap (value,20 ,4 ); + new_val |=bitfield_swap (value,24 ,40 ); + }else { + new_val =bitfield_swap (value,63 ,1 ); + new_val |=bitfield_swap (value,62 ,1 ); + new_val |=bitfield_swap (value,61 ,1 ); + new_val |=bitfield_swap (value,60 ,1 ); + new_val |=bitfield_swap (value,44 ,16 ); + new_val |=bitfield_swap (value,40 ,4 ); + new_val |=bitfield_swap (value,0 ,40 ); + } + +return new_val; +} +int evsel__parse_sample (struct evsel *evsel,union perf_event *event,struct perf_sample *data) {@@ -2408,6 +2453,8 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,if (type &PERF_SAMPLE_BRANCH_STACK ) {const u64 max_branch_nr =UINT64_MAX /sizeof (struct branch_entry ); +struct branch_entry *e; +unsigned int i;OVERFLOW_CHECK_u64 (array); data->branch_stack = (struct branch_stack *)array++;@@ -2416,10 +2463,33 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,return -EFAULT ; sz = data->branch_stack->nr *sizeof (struct branch_entry ); -if (evsel__has_branch_hw_idx (evsel)) +if (evsel__has_branch_hw_idx (evsel)) { sz +=sizeof (u64); -else + e = &data->branch_stack->entries[0 ]; + }else { data->no_hw_idx = true; +/* +* if the PERF_SAMPLE_BRANCH_HW_INDEX is not applied, +* only nr and entries[] will be output by kernel. +*/ + e = (struct branch_entry *)&data->branch_stack->hw_idx; + } + +if (swapped) { +/* +* struct branch_flag does not have endian +* specific bit field definition. And bswap +* will not resolve the issue, since these +* are bit fields. +* +* evsel__bitfield_swap_branch_flags() uses a +* bitfield_swap macro to swap the bit position +* based on the host endians. +*/ +for (i =0 ; i < data->branch_stack->nr; i++, e++) + e->flags.value =evsel__bitfield_swap_branch_flags (e->flags.value); + } +OVERFLOW_CHECK (array, sz, max_size); array = (void *)array + sz; }tools/perf/util/evsel.h +13
-0@@ -482,4 +482,17 @@ struct evsel *evsel__leader(struct evsel *evsel);bool evsel__has_leader (struct evsel *evsel,struct evsel *leader);bool evsel__is_leader (struct evsel *evsel);void evsel__set_leader (struct evsel *evsel,struct evsel *leader); + +/* +* Macro to swap the bit-field postition and size. +* Used when, +* - dont need to swap the entire u64 && +* - when u64 has variable bit-field sizes && +* - when presented in a host endian which is different +* than the source endian of the perf.data file +*/ +#define bitfield_swap (src, pos, size) \ + ((((src) >> (pos)) & ((1ull << (size)) - 1)) << (63 - ((pos) + (size) - 1))) + +u64 evsel__bitfield_swap_branch_flags (u64 value);#endif /* __PERF_EVSEL_H */ Signature · 1 line
2.31.1
Quoted 11 lines · Arnaldo Carvalho de Melo
Quoted 9 lines · Arnaldo Carvalho de Melo
Em Sat, Oct 16, 2021 at 06:20:58PM +0530, Madhavan Srinivasan escreveu:
Quoted 8 lines
branch_stackstruct has bit field definition which produces different bit ordering for big/little endian. Because of this, whenbranch_stacksample is collected in a BE system and viewed/reported in a LE system, bit fields of the branch stack are not presented properly. To address this issue, aevsel__bitfield_swap_branch_stack()is defined and introduced inevsel__parse_sample.
Quoted 6 lines
Quoted 5 lines
Quoted 5 lines
Signed-off-by Madhavan Srinivasan <[email protected]>---
Changelog v1:
- Renamed function and macro
- Added comments in codePlease, run 'perf test' before submitting patches, it's not that difficult, please do so.
I did. I ran 'perf test' and did not see any fail. I did not do 'perf test python', will check that out. My bad.
Maddy
Quoted 148 lines
- Arnaldo
Quoted 145 lines
[acme@quaco perf]$ perf test python
19: 'import perf' in python : FAILED!
[acme@quaco perf]$ perf test -v python
Couldn't bump rlimit(MEMLOCK), failures may take place when creating BPF maps, etc
19: 'import perf' in python :
--- start ---
test child forked, pid 991284
python usage test: "echo "import sys ;sys.path.append('/tmp/build/perf/python'); import perf" | '/usr/bin/python3' " Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError:/tmp/build/perf/python/perf.cpython-39-x86_64-linux-gnu.so: undefined symbol: bigendian test child finished with -1
---- end ----
'import perf' in python: FAILED!
[acme@quaco perf]$Quoted 129 lines
tools/perf/util/evsel.c | 74 +++++++++++++++++++++++++++++++++++++++-- tools/perf/util/evsel.h | 13 ++++++++ 2 files changed, 85 insertions(+), 2 deletions(-)tools/perf/util/evsel.c +72
-2@@ -2221,6 +2221,51 @@ void __weak arch_perf_parse_sample_weight(struct perf_sample *data, data->weight = *array; } +u64 evsel__bitfield_swap_branch_flags (u64 value) +{ +u64 new_val =0 ; + +/* +* branch_flags +* union { +* u64 values; +* struct { +* mispred:1 //target mispredicted +* predicted:1 //target predicted +* in_tx:1 //in transaction +* abort:1 //transaction abort +* cycles:16 //cycle count to last branch +* type:4 //branch type +* reserved:40 +* } +* } +* +* Avoid bswap64() the entire branch_flag.value, +* as it has variable bit-field sizes. Instead the +* macro takes the bit-field position/size, +* swaps it based on the host endianness. +*/ +if (bigendian ()) { + new_val =bitfield_swap (value,0 ,1 ); + new_val |=bitfield_swap (value,1 ,1 ); + new_val |=bitfield_swap (value,2 ,1 ); + new_val |=bitfield_swap (value,3 ,1 ); + new_val |=bitfield_swap (value,4 ,16 ); + new_val |=bitfield_swap (value,20 ,4 ); + new_val |=bitfield_swap (value,24 ,40 ); + }else { + new_val =bitfield_swap (value,63 ,1 ); + new_val |=bitfield_swap (value,62 ,1 ); + new_val |=bitfield_swap (value,61 ,1 ); + new_val |=bitfield_swap (value,60 ,1 ); + new_val |=bitfield_swap (value,44 ,16 ); + new_val |=bitfield_swap (value,40 ,4 ); + new_val |=bitfield_swap (value,0 ,40 ); + } + +return new_val; +} +int evsel__parse_sample (struct evsel *evsel,union perf_event *event,struct perf_sample *data) {@@ -2408,6 +2453,8 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,if (type &PERF_SAMPLE_BRANCH_STACK ) {const u64 max_branch_nr =UINT64_MAX /sizeof (struct branch_entry ); +struct branch_entry *e; +unsigned int i;OVERFLOW_CHECK_u64 (array); data->branch_stack = (struct branch_stack *)array++;@@ -2416,10 +2463,33 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,return -EFAULT ; sz = data->branch_stack->nr *sizeof (struct branch_entry ); -if (evsel__has_branch_hw_idx (evsel)) +if (evsel__has_branch_hw_idx (evsel)) { sz +=sizeof (u64); -else + e = &data->branch_stack->entries[0 ]; + }else { data->no_hw_idx = true; +/* +* if the PERF_SAMPLE_BRANCH_HW_INDEX is not applied, +* only nr and entries[] will be output by kernel. +*/ + e = (struct branch_entry *)&data->branch_stack->hw_idx; + } + +if (swapped) { +/* +* struct branch_flag does not have endian +* specific bit field definition. And bswap +* will not resolve the issue, since these +* are bit fields. +* +* evsel__bitfield_swap_branch_flags() uses a +* bitfield_swap macro to swap the bit position +* based on the host endians. +*/ +for (i =0 ; i < data->branch_stack->nr; i++, e++) + e->flags.value =evsel__bitfield_swap_branch_flags (e->flags.value); + } +OVERFLOW_CHECK (array, sz, max_size); array = (void *)array + sz; }tools/perf/util/evsel.h +13
-0@@ -482,4 +482,17 @@ struct evsel *evsel__leader(struct evsel *evsel);bool evsel__has_leader (struct evsel *evsel,struct evsel *leader);bool evsel__is_leader (struct evsel *evsel);void evsel__set_leader (struct evsel *evsel,struct evsel *leader); + +/* +* Macro to swap the bit-field postition and size. +* Used when, +* - dont need to swap the entire u64 && +* - when u64 has variable bit-field sizes && +* - when presented in a host endian which is different +* than the source endian of the perf.data file +*/ +#define bitfield_swap (src, pos, size) \ + ((((src) >> (pos)) & ((1ull << (size)) - 1)) << (63 - ((pos) + (size) - 1))) + +u64 evsel__bitfield_swap_branch_flags (u64 value);#endif /* __PERF_EVSEL_H */ Signature · 1 line
2.31.1
Quoted 11 lines · Arnaldo Carvalho de Melo
Quoted 9 lines · Arnaldo Carvalho de Melo
Em Sat, Oct 16, 2021 at 06:20:58PM +0530, Madhavan Srinivasan escreveu:
Quoted 8 lines
branch_stackstruct has bit field definition which produces different bit ordering for big/little endian. Because of this, whenbranch_stacksample is collected in a BE system and viewed/reported in a LE system, bit fields of the branch stack are not presented properly. To address this issue, aevsel__bitfield_swap_branch_stack()is defined and introduced inevsel__parse_sample.
Quoted 21 lines
Quoted 5 lines
Quoted 5 lines
Signed-off-by Madhavan Srinivasan <[email protected]>---
Changelog v1:
- Renamed function and macro
- Added comments in codePlease, run 'perf test' before submitting patches, it's not that difficult, please do so.
- Arnaldo
Quoted 12 lines
[acme@quaco perf]$ perf test python
19: 'import perf' in python : FAILED!
[acme@quaco perf]$ perf test -v python
Couldn't bump rlimit(MEMLOCK), failures may take place when creating BPF maps, etc
19: 'import perf' in python :
--- start ---
test child forked, pid 991284
python usage test: "echo "import sys ;sys.path.append('/tmp/build/perf/python'); import perf" | '/usr/bin/python3' " Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError:/tmp/build/perf/python/perf.cpython-39-x86_64-linux-gnu.so: undefined symbol: bigendian test child finished with -1
using tep_is_bigendian() instead of bigendian() fixes it. Will send a V3 with that changes.
Maddy
Quoted 130 lines
Quoted 130 lines
---- end ---- 'import perf' in python: FAILED! [acme@quaco perf]$
Quoted 129 lines
tools/perf/util/evsel.c | 74 +++++++++++++++++++++++++++++++++++++++-- tools/perf/util/evsel.h | 13 ++++++++ 2 files changed, 85 insertions(+), 2 deletions(-)tools/perf/util/evsel.c +72
-2@@ -2221,6 +2221,51 @@ void __weak arch_perf_parse_sample_weight(struct perf_sample *data, data->weight = *array; } +u64 evsel__bitfield_swap_branch_flags (u64 value) +{ +u64 new_val =0 ; + +/* +* branch_flags +* union { +* u64 values; +* struct { +* mispred:1 //target mispredicted +* predicted:1 //target predicted +* in_tx:1 //in transaction +* abort:1 //transaction abort +* cycles:16 //cycle count to last branch +* type:4 //branch type +* reserved:40 +* } +* } +* +* Avoid bswap64() the entire branch_flag.value, +* as it has variable bit-field sizes. Instead the +* macro takes the bit-field position/size, +* swaps it based on the host endianness. +*/ +if (bigendian ()) { + new_val =bitfield_swap (value,0 ,1 ); + new_val |=bitfield_swap (value,1 ,1 ); + new_val |=bitfield_swap (value,2 ,1 ); + new_val |=bitfield_swap (value,3 ,1 ); + new_val |=bitfield_swap (value,4 ,16 ); + new_val |=bitfield_swap (value,20 ,4 ); + new_val |=bitfield_swap (value,24 ,40 ); + }else { + new_val =bitfield_swap (value,63 ,1 ); + new_val |=bitfield_swap (value,62 ,1 ); + new_val |=bitfield_swap (value,61 ,1 ); + new_val |=bitfield_swap (value,60 ,1 ); + new_val |=bitfield_swap (value,44 ,16 ); + new_val |=bitfield_swap (value,40 ,4 ); + new_val |=bitfield_swap (value,0 ,40 ); + } + +return new_val; +} +int evsel__parse_sample (struct evsel *evsel,union perf_event *event,struct perf_sample *data) {@@ -2408,6 +2453,8 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,if (type &PERF_SAMPLE_BRANCH_STACK ) {const u64 max_branch_nr =UINT64_MAX /sizeof (struct branch_entry ); +struct branch_entry *e; +unsigned int i;OVERFLOW_CHECK_u64 (array); data->branch_stack = (struct branch_stack *)array++;@@ -2416,10 +2463,33 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,return -EFAULT ; sz = data->branch_stack->nr *sizeof (struct branch_entry ); -if (evsel__has_branch_hw_idx (evsel)) +if (evsel__has_branch_hw_idx (evsel)) { sz +=sizeof (u64); -else + e = &data->branch_stack->entries[0 ]; + }else { data->no_hw_idx = true; +/* +* if the PERF_SAMPLE_BRANCH_HW_INDEX is not applied, +* only nr and entries[] will be output by kernel. +*/ + e = (struct branch_entry *)&data->branch_stack->hw_idx; + } + +if (swapped) { +/* +* struct branch_flag does not have endian +* specific bit field definition. And bswap +* will not resolve the issue, since these +* are bit fields. +* +* evsel__bitfield_swap_branch_flags() uses a +* bitfield_swap macro to swap the bit position +* based on the host endians. +*/ +for (i =0 ; i < data->branch_stack->nr; i++, e++) + e->flags.value =evsel__bitfield_swap_branch_flags (e->flags.value); + } +OVERFLOW_CHECK (array, sz, max_size); array = (void *)array + sz; }tools/perf/util/evsel.h +13
-0@@ -482,4 +482,17 @@ struct evsel *evsel__leader(struct evsel *evsel);bool evsel__has_leader (struct evsel *evsel,struct evsel *leader);bool evsel__is_leader (struct evsel *evsel);void evsel__set_leader (struct evsel *evsel,struct evsel *leader); + +/* +* Macro to swap the bit-field postition and size. +* Used when, +* - dont need to swap the entire u64 && +* - when u64 has variable bit-field sizes && +* - when presented in a host endian which is different +* than the source endian of the perf.data file +*/ +#define bitfield_swap (src, pos, size) \ + ((((src) >> (pos)) & ((1ull << (size)) - 1)) << (63 - ((pos) + (size) - 1))) + +u64 evsel__bitfield_swap_branch_flags (u64 value);#endif /* __PERF_EVSEL_H */ Signature · 1 line
2.31.1