[PATCH] perf-tool: get correct format attribute value

From: Megha Dey
Date: Wed Dec 20 2017 - 18:29:32 EST


pmu_format_value() does not always return the correct value when the
default format attribute value is overwritten on the perf command line.

This happens because in pmu_format_value(), the default value is not
actually being overwritten by the new value, but only bits either set
in the new or the default value are being set.

for eg:
For example: cat /sys/devices/cpu/events/bus-cycles
event=0x3c,umask=0x01

perf stat -e cpu/bus-cycles/ sleep 1
event->attr.config = 0x13c

perf stat -e cpu/bus-cycles,umask=2/ sleep
event->attr.config = 0x33c (Expected value is 0x23c, we should be
event->overwriting the umask value)

perf stat -e cpu/bus-cycles,umask=0/ sleep
event->attr.config = 0x13c (expected value is 0x3c)

To ensure we always get the correct value, we should clear the bits
corresponding to the particular format so that only bits set in the new
value are set. In other words, we overwrite the default with new value.

The following test case can be added to test for this failure:

diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
index 9abca26..0419833 100644
--- a/tools/perf/tests/pmu.c
+++ b/tools/perf/tests/pmu.c
@@ -78,6 +78,12 @@
.type_val = PARSE_EVENTS__TERM_TYPE_NUM,
.type_term = PARSE_EVENTS__TERM_TYPE_USER,
},
+ {
+ .config = (char *) "krava13",
+ .val.num = 5,
+ .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
+ .type_term = PARSE_EVENTS__TERM_TYPE_USER,
+ },
};

/*
@@ -164,7 +170,7 @@ int test__pmu(struct test *test __maybe_unused, int subtest __maybe_unused)

if (attr.config != 0xc00000000002a823)
break;
- if (attr.config1 != 0x8000400000000145)
+ if (attr.config1 != 0x8000a00000000145)
break;
if (attr.config2 != 0x0400000020041d07)
break;

Signed-off-by: Megha Dey <megha.dey@xxxxxxxxxxxxxxx>
---
tools/perf/util/pmu.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index b42011b..7e7e367 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -761,6 +761,8 @@ static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
{
unsigned long fbit, vbit;

+ *v = *v & (~(*format));
+
for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {

if (!test_bit(fbit, format))
--
1.9.1