xref: /openbmc/linux/tools/perf/arch/x86/tests/sample-parsing.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
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