17d9d4c6eSKan Liang // SPDX-License-Identifier: GPL-2.0-only
27d9d4c6eSKan Liang #include <stdbool.h>
37d9d4c6eSKan Liang #include <inttypes.h>
47d9d4c6eSKan Liang #include <stdlib.h>
57d9d4c6eSKan Liang #include <string.h>
67d9d4c6eSKan Liang #include <linux/bitops.h>
77d9d4c6eSKan Liang #include <linux/kernel.h>
87d9d4c6eSKan Liang #include <linux/types.h>
97d9d4c6eSKan Liang
107d9d4c6eSKan Liang #include "event.h"
117d9d4c6eSKan Liang #include "evsel.h"
127d9d4c6eSKan Liang #include "debug.h"
139823147dSArnaldo Carvalho de Melo #include "util/sample.h"
147d9d4c6eSKan Liang #include "util/synthetic-events.h"
157d9d4c6eSKan Liang
167d9d4c6eSKan Liang #include "tests/tests.h"
177d9d4c6eSKan Liang #include "arch-tests.h"
187d9d4c6eSKan Liang
197d9d4c6eSKan Liang #define COMP(m) do { \
207d9d4c6eSKan Liang if (s1->m != s2->m) { \
217d9d4c6eSKan Liang pr_debug("Samples differ at '"#m"'\n"); \
227d9d4c6eSKan Liang return false; \
237d9d4c6eSKan Liang } \
247d9d4c6eSKan Liang } while (0)
257d9d4c6eSKan Liang
samples_same(const struct perf_sample * s1,const struct perf_sample * s2,u64 type)267d9d4c6eSKan Liang static bool samples_same(const struct perf_sample *s1,
277d9d4c6eSKan Liang const struct perf_sample *s2,
287d9d4c6eSKan Liang u64 type)
297d9d4c6eSKan Liang {
30*e65f91b2SKan Liang if (type & PERF_SAMPLE_WEIGHT_STRUCT) {
317d9d4c6eSKan Liang COMP(ins_lat);
32*e65f91b2SKan Liang COMP(retire_lat);
33*e65f91b2SKan Liang }
347d9d4c6eSKan Liang
357d9d4c6eSKan Liang return true;
367d9d4c6eSKan Liang }
377d9d4c6eSKan Liang
do_test(u64 sample_type)387d9d4c6eSKan Liang static int do_test(u64 sample_type)
397d9d4c6eSKan Liang {
407d9d4c6eSKan Liang struct evsel evsel = {
417d9d4c6eSKan Liang .needs_swap = false,
427d9d4c6eSKan Liang .core = {
437d9d4c6eSKan Liang . attr = {
447d9d4c6eSKan Liang .sample_type = sample_type,
457d9d4c6eSKan Liang .read_format = 0,
467d9d4c6eSKan Liang },
477d9d4c6eSKan Liang },
487d9d4c6eSKan Liang };
497d9d4c6eSKan Liang union perf_event *event;
507d9d4c6eSKan Liang struct perf_sample sample = {
517d9d4c6eSKan Liang .weight = 101,
527d9d4c6eSKan Liang .ins_lat = 102,
53*e65f91b2SKan Liang .retire_lat = 103,
547d9d4c6eSKan Liang };
557d9d4c6eSKan Liang struct perf_sample sample_out;
567d9d4c6eSKan Liang size_t i, sz, bufsz;
577d9d4c6eSKan Liang int err, ret = -1;
587d9d4c6eSKan Liang
597d9d4c6eSKan Liang sz = perf_event__sample_event_size(&sample, sample_type, 0);
607d9d4c6eSKan Liang bufsz = sz + 4096; /* Add a bit for overrun checking */
617d9d4c6eSKan Liang event = malloc(bufsz);
627d9d4c6eSKan Liang if (!event) {
637d9d4c6eSKan Liang pr_debug("malloc failed\n");
647d9d4c6eSKan Liang return -1;
657d9d4c6eSKan Liang }
667d9d4c6eSKan Liang
677d9d4c6eSKan Liang memset(event, 0xff, bufsz);
687d9d4c6eSKan Liang event->header.type = PERF_RECORD_SAMPLE;
697d9d4c6eSKan Liang event->header.misc = 0;
707d9d4c6eSKan Liang event->header.size = sz;
717d9d4c6eSKan Liang
727d9d4c6eSKan Liang err = perf_event__synthesize_sample(event, sample_type, 0, &sample);
737d9d4c6eSKan Liang if (err) {
747d9d4c6eSKan Liang pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
757d9d4c6eSKan Liang "perf_event__synthesize_sample", sample_type, err);
767d9d4c6eSKan Liang goto out_free;
777d9d4c6eSKan Liang }
787d9d4c6eSKan Liang
797d9d4c6eSKan Liang /* The data does not contain 0xff so we use that to check the size */
807d9d4c6eSKan Liang for (i = bufsz; i > 0; i--) {
817d9d4c6eSKan Liang if (*(i - 1 + (u8 *)event) != 0xff)
827d9d4c6eSKan Liang break;
837d9d4c6eSKan Liang }
847d9d4c6eSKan Liang if (i != sz) {
857d9d4c6eSKan Liang pr_debug("Event size mismatch: actual %zu vs expected %zu\n",
867d9d4c6eSKan Liang i, sz);
877d9d4c6eSKan Liang goto out_free;
887d9d4c6eSKan Liang }
897d9d4c6eSKan Liang
907d9d4c6eSKan Liang evsel.sample_size = __evsel__sample_size(sample_type);
917d9d4c6eSKan Liang
927d9d4c6eSKan Liang err = evsel__parse_sample(&evsel, event, &sample_out);
937d9d4c6eSKan Liang if (err) {
947d9d4c6eSKan Liang pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
957d9d4c6eSKan Liang "evsel__parse_sample", sample_type, err);
967d9d4c6eSKan Liang goto out_free;
977d9d4c6eSKan Liang }
987d9d4c6eSKan Liang
997d9d4c6eSKan Liang if (!samples_same(&sample, &sample_out, sample_type)) {
1007d9d4c6eSKan Liang pr_debug("parsing failed for sample_type %#"PRIx64"\n",
1017d9d4c6eSKan Liang sample_type);
1027d9d4c6eSKan Liang goto out_free;
1037d9d4c6eSKan Liang }
1047d9d4c6eSKan Liang
1057d9d4c6eSKan Liang ret = 0;
1067d9d4c6eSKan Liang out_free:
1077d9d4c6eSKan Liang free(event);
1087d9d4c6eSKan Liang
1097d9d4c6eSKan Liang return ret;
1107d9d4c6eSKan Liang }
1117d9d4c6eSKan Liang
1127d9d4c6eSKan Liang /**
1137d9d4c6eSKan Liang * test__x86_sample_parsing - test X86 specific sample parsing
1147d9d4c6eSKan Liang *
1157d9d4c6eSKan Liang * This function implements a test that synthesizes a sample event, parses it
1167d9d4c6eSKan Liang * and then checks that the parsed sample matches the original sample. If the
1177d9d4c6eSKan Liang * test passes %0 is returned, otherwise %-1 is returned.
1187d9d4c6eSKan Liang *
1197d9d4c6eSKan Liang * For now, the PERF_SAMPLE_WEIGHT_STRUCT is the only X86 specific sample type.
1207d9d4c6eSKan Liang * The test only checks the PERF_SAMPLE_WEIGHT_STRUCT type.
1217d9d4c6eSKan Liang */
test__x86_sample_parsing(struct test_suite * test __maybe_unused,int subtest __maybe_unused)12233f44bfdSIan Rogers int test__x86_sample_parsing(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
1237d9d4c6eSKan Liang {
1247d9d4c6eSKan Liang return do_test(PERF_SAMPLE_WEIGHT_STRUCT);
1257d9d4c6eSKan Liang }
126