1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | #include <stdbool.h> |
3 | #include <inttypes.h> |
4 | #include <stdlib.h> |
5 | #include <string.h> |
6 | #include <linux/bitops.h> |
7 | #include <linux/kernel.h> |
8 | #include <linux/types.h> |
9 | |
10 | #include "event.h" |
11 | #include "evsel.h" |
12 | #include "debug.h" |
13 | #include "util/sample.h" |
14 | #include "util/synthetic-events.h" |
15 | |
16 | #include "tests/tests.h" |
17 | #include "arch-tests.h" |
18 | |
19 | #define COMP(m) do { \ |
20 | if (s1->m != s2->m) { \ |
21 | pr_debug("Samples differ at '"#m"'\n"); \ |
22 | return false; \ |
23 | } \ |
24 | } while (0) |
25 | |
26 | static bool samples_same(const struct perf_sample *s1, |
27 | const struct perf_sample *s2, |
28 | u64 type) |
29 | { |
30 | if (type & PERF_SAMPLE_WEIGHT_STRUCT) { |
31 | COMP(ins_lat); |
32 | COMP(retire_lat); |
33 | } |
34 | |
35 | return true; |
36 | } |
37 | |
38 | static int do_test(u64 sample_type) |
39 | { |
40 | struct evsel evsel = { |
41 | .needs_swap = false, |
42 | .core = { |
43 | . attr = { |
44 | .sample_type = sample_type, |
45 | .read_format = 0, |
46 | }, |
47 | }, |
48 | }; |
49 | union perf_event *event; |
50 | struct perf_sample sample = { |
51 | .weight = 101, |
52 | .ins_lat = 102, |
53 | .retire_lat = 103, |
54 | }; |
55 | struct perf_sample sample_out; |
56 | size_t i, sz, bufsz; |
57 | int err, ret = -1; |
58 | |
59 | sz = perf_event__sample_event_size(&sample, sample_type, 0); |
60 | bufsz = sz + 4096; /* Add a bit for overrun checking */ |
61 | event = malloc(bufsz); |
62 | if (!event) { |
63 | pr_debug("malloc failed\n" ); |
64 | return -1; |
65 | } |
66 | |
67 | memset(event, 0xff, bufsz); |
68 | event->header.type = PERF_RECORD_SAMPLE; |
69 | event->header.misc = 0; |
70 | event->header.size = sz; |
71 | |
72 | err = perf_event__synthesize_sample(event, sample_type, 0, &sample); |
73 | if (err) { |
74 | pr_debug("%s failed for sample_type %#" PRIx64", error %d\n" , |
75 | "perf_event__synthesize_sample" , sample_type, err); |
76 | goto out_free; |
77 | } |
78 | |
79 | /* The data does not contain 0xff so we use that to check the size */ |
80 | for (i = bufsz; i > 0; i--) { |
81 | if (*(i - 1 + (u8 *)event) != 0xff) |
82 | break; |
83 | } |
84 | if (i != sz) { |
85 | pr_debug("Event size mismatch: actual %zu vs expected %zu\n" , |
86 | i, sz); |
87 | goto out_free; |
88 | } |
89 | |
90 | evsel.sample_size = __evsel__sample_size(sample_type); |
91 | |
92 | err = evsel__parse_sample(&evsel, event, &sample_out); |
93 | if (err) { |
94 | pr_debug("%s failed for sample_type %#" PRIx64", error %d\n" , |
95 | "evsel__parse_sample" , sample_type, err); |
96 | goto out_free; |
97 | } |
98 | |
99 | if (!samples_same(s1: &sample, s2: &sample_out, type: sample_type)) { |
100 | pr_debug("parsing failed for sample_type %#" PRIx64"\n" , |
101 | sample_type); |
102 | goto out_free; |
103 | } |
104 | |
105 | ret = 0; |
106 | out_free: |
107 | free(event); |
108 | |
109 | return ret; |
110 | } |
111 | |
112 | /** |
113 | * test__x86_sample_parsing - test X86 specific sample parsing |
114 | * |
115 | * This function implements a test that synthesizes a sample event, parses it |
116 | * and then checks that the parsed sample matches the original sample. If the |
117 | * test passes %0 is returned, otherwise %-1 is returned. |
118 | * |
119 | * For now, the PERF_SAMPLE_WEIGHT_STRUCT is the only X86 specific sample type. |
120 | * The test only checks the PERF_SAMPLE_WEIGHT_STRUCT type. |
121 | */ |
122 | int test__x86_sample_parsing(struct test_suite *test __maybe_unused, int subtest __maybe_unused) |
123 | { |
124 | return do_test(sample_type: PERF_SAMPLE_WEIGHT_STRUCT); |
125 | } |
126 | |