tools/perf/tests/shell/data_type_profiling.sh | 2 +- tools/perf/tests/workloads/datasym.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-)
The typedef creates an issue where the struct or the typedef may
appear in the output and cause the "perf data type profiling tests" to
fail. Let's remove the typedef to keep the test passing.
Fixes: 335047109d7d ("perf tests: Test annotate with data type profiling and C")
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/tests/shell/data_type_profiling.sh | 2 +-
tools/perf/tests/workloads/datasym.c | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/tools/perf/tests/shell/data_type_profiling.sh b/tools/perf/tests/shell/data_type_profiling.sh
index 2a7f8f7c42d0..fb47b7213b33 100755
--- a/tools/perf/tests/shell/data_type_profiling.sh
+++ b/tools/perf/tests/shell/data_type_profiling.sh
@@ -8,7 +8,7 @@ set -e
# data type profiling manifestation
# Values in testtypes and testprogs should match
-testtypes=("# data-type: struct Buf" "# data-type: struct _buf")
+testtypes=("# data-type: struct Buf" "# data-type: struct buf")
testprogs=("perf test -w code_with_type" "perf test -w datasym")
err=0
diff --git a/tools/perf/tests/workloads/datasym.c b/tools/perf/tests/workloads/datasym.c
index 1d0b7d64e1ba..19242c7255c0 100644
--- a/tools/perf/tests/workloads/datasym.c
+++ b/tools/perf/tests/workloads/datasym.c
@@ -4,14 +4,14 @@
#include <linux/compiler.h>
#include "../tests.h"
-typedef struct _buf {
+struct buf {
char data1;
char reserved[55];
char data2;
-} buf __attribute__((aligned(64)));
+} __attribute__((aligned(64)));
/* volatile to try to avoid the compiler seeing reserved as unused. */
-static volatile buf workload_datasym_buf1 = {
+static volatile struct buf workload_datasym_buf1 = {
/* to have this in the data section */
.reserved[0] = 1,
};
--
2.53.0.473.g4a7958ca14-goog
On Mon, 02 Mar 2026 15:58:21 -0800, Ian Rogers wrote: > The typedef creates an issue where the struct or the typedef may > appear in the output and cause the "perf data type profiling tests" to > fail. Let's remove the typedef to keep the test passing. > > Applied to perf-tools-next, thanks! Best regards, Namhyung
On Wed, Mar 04, 2026 at 01:48:53PM -0800, Namhyung Kim wrote: > On Mon, 02 Mar 2026 15:58:21 -0800, Ian Rogers wrote: > > The typedef creates an issue where the struct or the typedef may > > appear in the output and cause the "perf data type profiling tests" to > > fail. Let's remove the typedef to keep the test passing. > > > > > Applied to perf-tools-next, thanks! I applied this to perf-tools as well, for now just at tmp.perf-tools tho. - Arnaldo
> On Mon, Mar 02, 2026 at 03:58:21PM -0800, Ian Rogers wrote: > The typedef creates an issue where the struct or the typedef may > appear in the output and cause the "perf data type profiling tests" to > fail. Let's remove the typedef to keep the test passing. Yes, makes sense to me, thanks. As mentioned in the previous message, it sounds fishy to me that perf record and perf mem record capture different data type -- I'll try to get to the bottom of it (I was sort of hoping to finish the cross compilation topic first, but since it's not moving that fast, why not do some debugging here). Reviewed-by: Dmitrii Dolgov <9erthalion6@gmail.com>
> On Wed, Mar 04, 2026 at 11:44:16AM +0100, Dmitry Dolgov wrote:
> > On Mon, Mar 02, 2026 at 03:58:21PM -0800, Ian Rogers wrote:
> > The typedef creates an issue where the struct or the typedef may
> > appear in the output and cause the "perf data type profiling tests" to
> > fail. Let's remove the typedef to keep the test passing.
>
> Yes, makes sense to me, thanks. As mentioned in the previous message, it
> sounds fishy to me that perf record and perf mem record capture
> different data type -- I'll try to get to the bottom of it.
I think I figured it out. To reiterate, the problem was that in my environment
this:
$ perf record ...
$ perf annotate --code-with-type ...
was showing a different data structure for workload_datasym_buf1 (buf vs struct
_buf) than:
$ perf mem record ...
$ perf annotate --code-with-type ...
It turns out that the type_die for this variable was derived differently: for
"record" it was going through check_variable, for "mem record" through
global_var__collect. If the type tag is DW_TAG_typedef, check_variable tries to
figure out a real data type via die_get_real_type, which says this:
/**
* [...]
* If the type is qualifiers (e.g. const) or typedef, this skips it
* and tries to find real type (structure or basic types, e.g. int).
*/
But the underlying implementation doesn't actually check for DW_TAG_typedef for
some reason:
while (tag == DW_TAG_const_type ||
tag == DW_TAG_restrict_type ||
tag == DW_TAG_volatile_type ||
tag == DW_TAG_shared_type);
By itself it doesn't look problematic, but for some reason datasym test was
producing such a code, that had a chain of two DW_TAG_typedef in a row, so that
die_get_real_type was returning a DW_TAG_typedef again.
It looks to me like a deficiency of die_get_real_type, and the following code
change fixes the problem for me:
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index 9267af204c7..de152fae1d9 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -279,6 +279,7 @@ Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
} while (tag == DW_TAG_const_type ||
tag == DW_TAG_restrict_type ||
tag == DW_TAG_volatile_type ||
+ tag == DW_TAG_typedef ||
tag == DW_TAG_shared_type);
return vr_die;
Does this change sound reasonable?
Hello,
On Sun, Mar 29, 2026 at 06:18:52PM +0200, Dmitry Dolgov wrote:
> > On Wed, Mar 04, 2026 at 11:44:16AM +0100, Dmitry Dolgov wrote:
> > > On Mon, Mar 02, 2026 at 03:58:21PM -0800, Ian Rogers wrote:
> > > The typedef creates an issue where the struct or the typedef may
> > > appear in the output and cause the "perf data type profiling tests" to
> > > fail. Let's remove the typedef to keep the test passing.
> >
> > Yes, makes sense to me, thanks. As mentioned in the previous message, it
> > sounds fishy to me that perf record and perf mem record capture
> > different data type -- I'll try to get to the bottom of it.
>
> I think I figured it out. To reiterate, the problem was that in my environment
> this:
>
> $ perf record ...
> $ perf annotate --code-with-type ...
>
> was showing a different data structure for workload_datasym_buf1 (buf vs struct
> _buf) than:
>
> $ perf mem record ...
> $ perf annotate --code-with-type ...
>
> It turns out that the type_die for this variable was derived differently: for
> "record" it was going through check_variable, for "mem record" through
> global_var__collect. If the type tag is DW_TAG_typedef, check_variable tries to
> figure out a real data type via die_get_real_type, which says this:
>
> /**
> * [...]
> * If the type is qualifiers (e.g. const) or typedef, this skips it
> * and tries to find real type (structure or basic types, e.g. int).
> */
>
> But the underlying implementation doesn't actually check for DW_TAG_typedef for
> some reason:
>
> while (tag == DW_TAG_const_type ||
> tag == DW_TAG_restrict_type ||
> tag == DW_TAG_volatile_type ||
> tag == DW_TAG_shared_type);
>
> By itself it doesn't look problematic, but for some reason datasym test was
> producing such a code, that had a chain of two DW_TAG_typedef in a row, so that
> die_get_real_type was returning a DW_TAG_typedef again.
>
> It looks to me like a deficiency of die_get_real_type, and the following code
> change fixes the problem for me:
>
> diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
> index 9267af204c7..de152fae1d9 100644
> --- a/tools/perf/util/dwarf-aux.c
> +++ b/tools/perf/util/dwarf-aux.c
> @@ -279,6 +279,7 @@ Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
> } while (tag == DW_TAG_const_type ||
> tag == DW_TAG_restrict_type ||
> tag == DW_TAG_volatile_type ||
> + tag == DW_TAG_typedef ||
> tag == DW_TAG_shared_type);
>
> return vr_die;
>
> Does this change sound reasonable?
We have this:
Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
{
do {
vr_die = __die_get_real_type(vr_die, die_mem);
} while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
return vr_die;
}
Thanks,
Namhyung
> On Mon, Mar 30, 2026 at 11:42:25PM -0700, Namhyung Kim wrote:
>
> We have this:
>
> Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
> {
> do {
> vr_die = __die_get_real_type(vr_die, die_mem);
> } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
>
> return vr_die;
> }
Indeed, I didn't finish the analysis, fooled that the diff was solving
the issue. Adding DW_TAG_typedef into __die_get_real_type still fixes
the problem, but due to different reasons:
* check_variable calls __die_get_real_type directly at the beginning and
stores the result in type_die, which is the result of the function.
* if it doesn't resolve DW_TAG_typedef, the flow goes into the
die_get_real_type, which stores the result in the local variable
sized_type. But it never copied into the type_die, and never returned
as a result of the check_variable.
Hence we either need to add DW_TAG_typedef into __die_get_real_type, or
copy sized_type into type_die. After some testing both seems to be
achieving the goal.
On Tue Mar 31, 2026 at 8:22 PM BST, Dmitry Dolgov wrote:
>> On Mon, Mar 30, 2026 at 11:42:25PM -0700, Namhyung Kim wrote:
>>
>> We have this:
>>
>> Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
>> {
>> do {
>> vr_die = __die_get_real_type(vr_die, die_mem);
>> } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
>>
>> return vr_die;
>> }
>
> Indeed, I didn't finish the analysis, fooled that the diff was solving
> the issue. Adding DW_TAG_typedef into __die_get_real_type still fixes
> the problem, but due to different reasons:
>
> * check_variable calls __die_get_real_type directly at the beginning and
> stores the result in type_die, which is the result of the function.
>
> * if it doesn't resolve DW_TAG_typedef, the flow goes into the
> die_get_real_type, which stores the result in the local variable
> sized_type. But it never copied into the type_die, and never returned
> as a result of the check_variable.
>
> Hence we either need to add DW_TAG_typedef into __die_get_real_type, or
> copy sized_type into type_die. After some testing both seems to be
> achieving the goal.
Why is the code in `check_variable` resolving typedefs itself instead of using
`die_get_real_type` instead?
Best,
Gary
> On Tue, Apr 14, 2026 at 03:42:19PM +0100, Gary Guo wrote:
> > Indeed, I didn't finish the analysis, fooled that the diff was solving
> > the issue. Adding DW_TAG_typedef into __die_get_real_type still fixes
> > the problem, but due to different reasons:
> >
> > * check_variable calls __die_get_real_type directly at the beginning and
> > stores the result in type_die, which is the result of the function.
> >
> > * if it doesn't resolve DW_TAG_typedef, the flow goes into the
> > die_get_real_type, which stores the result in the local variable
> > sized_type. But it never copied into the type_die, and never returned
> > as a result of the check_variable.
> >
> > Hence we either need to add DW_TAG_typedef into __die_get_real_type, or
> > copy sized_type into type_die. After some testing both seems to be
> > achieving the goal.
>
> Why is the code in `check_variable` resolving typedefs itself instead of using
> `die_get_real_type` instead?
Looks like it was done in 90d78e7b8e5 ("perf annotate-data: Show typedef
names properly") for the purposes of resolving structs without a name
slightly better.
> On Tue, Mar 31, 2026 at 09:22:31PM +0200, Dmitry Dolgov wrote:
> > On Mon, Mar 30, 2026 at 11:42:25PM -0700, Namhyung Kim wrote:
> >
> > We have this:
> >
> > Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
> > {
> > do {
> > vr_die = __die_get_real_type(vr_die, die_mem);
> > } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
> >
> > return vr_die;
> > }
>
> Indeed, I didn't finish the analysis, fooled that the diff was solving
> the issue. Adding DW_TAG_typedef into __die_get_real_type still fixes
> the problem, but due to different reasons:
>
> * check_variable calls __die_get_real_type directly at the beginning and
> stores the result in type_die, which is the result of the function.
>
> * if it doesn't resolve DW_TAG_typedef, the flow goes into the
> die_get_real_type, which stores the result in the local variable
> sized_type. But it never copied into the type_die, and never returned
> as a result of the check_variable.
>
> Hence we either need to add DW_TAG_typedef into __die_get_real_type, or
> copy sized_type into type_die. After some testing both seems to be
> achieving the goal.
Any thoughts on this ^ ?
On Wed, Mar 04, 2026 at 11:44:16AM +0100, Dmitry Dolgov wrote: > > On Mon, Mar 02, 2026 at 03:58:21PM -0800, Ian Rogers wrote: > > The typedef creates an issue where the struct or the typedef may > > appear in the output and cause the "perf data type profiling tests" to > > fail. Let's remove the typedef to keep the test passing. > > Yes, makes sense to me, thanks. As mentioned in the previous message, it > sounds fishy to me that perf record and perf mem record capture > different data type -- I'll try to get to the bottom of it (I was sort > of hoping to finish the cross compilation topic first, but since it's > not moving that fast, why not do some debugging here). > > Reviewed-by: Dmitrii Dolgov <9erthalion6@gmail.com> Thanks, applied to perf-tools, for v7.0. - Arnaldo
© 2016 - 2026 Red Hat, Inc.