162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci#include <stdbool.h> 362306a36Sopenharmony_ci#include <inttypes.h> 462306a36Sopenharmony_ci#include <stdlib.h> 562306a36Sopenharmony_ci#include <string.h> 662306a36Sopenharmony_ci#include <linux/bitops.h> 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/types.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "event.h" 1162306a36Sopenharmony_ci#include "evsel.h" 1262306a36Sopenharmony_ci#include "debug.h" 1362306a36Sopenharmony_ci#include "util/sample.h" 1462306a36Sopenharmony_ci#include "util/synthetic-events.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "tests/tests.h" 1762306a36Sopenharmony_ci#include "arch-tests.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define COMP(m) do { \ 2062306a36Sopenharmony_ci if (s1->m != s2->m) { \ 2162306a36Sopenharmony_ci pr_debug("Samples differ at '"#m"'\n"); \ 2262306a36Sopenharmony_ci return false; \ 2362306a36Sopenharmony_ci } \ 2462306a36Sopenharmony_ci} while (0) 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic bool samples_same(const struct perf_sample *s1, 2762306a36Sopenharmony_ci const struct perf_sample *s2, 2862306a36Sopenharmony_ci u64 type) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci if (type & PERF_SAMPLE_WEIGHT_STRUCT) { 3162306a36Sopenharmony_ci COMP(ins_lat); 3262306a36Sopenharmony_ci COMP(retire_lat); 3362306a36Sopenharmony_ci } 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci return true; 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic int do_test(u64 sample_type) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct evsel evsel = { 4162306a36Sopenharmony_ci .needs_swap = false, 4262306a36Sopenharmony_ci .core = { 4362306a36Sopenharmony_ci . attr = { 4462306a36Sopenharmony_ci .sample_type = sample_type, 4562306a36Sopenharmony_ci .read_format = 0, 4662306a36Sopenharmony_ci }, 4762306a36Sopenharmony_ci }, 4862306a36Sopenharmony_ci }; 4962306a36Sopenharmony_ci union perf_event *event; 5062306a36Sopenharmony_ci struct perf_sample sample = { 5162306a36Sopenharmony_ci .weight = 101, 5262306a36Sopenharmony_ci .ins_lat = 102, 5362306a36Sopenharmony_ci .retire_lat = 103, 5462306a36Sopenharmony_ci }; 5562306a36Sopenharmony_ci struct perf_sample sample_out; 5662306a36Sopenharmony_ci size_t i, sz, bufsz; 5762306a36Sopenharmony_ci int err, ret = -1; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci sz = perf_event__sample_event_size(&sample, sample_type, 0); 6062306a36Sopenharmony_ci bufsz = sz + 4096; /* Add a bit for overrun checking */ 6162306a36Sopenharmony_ci event = malloc(bufsz); 6262306a36Sopenharmony_ci if (!event) { 6362306a36Sopenharmony_ci pr_debug("malloc failed\n"); 6462306a36Sopenharmony_ci return -1; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci memset(event, 0xff, bufsz); 6862306a36Sopenharmony_ci event->header.type = PERF_RECORD_SAMPLE; 6962306a36Sopenharmony_ci event->header.misc = 0; 7062306a36Sopenharmony_ci event->header.size = sz; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci err = perf_event__synthesize_sample(event, sample_type, 0, &sample); 7362306a36Sopenharmony_ci if (err) { 7462306a36Sopenharmony_ci pr_debug("%s failed for sample_type %#"PRIx64", error %d\n", 7562306a36Sopenharmony_ci "perf_event__synthesize_sample", sample_type, err); 7662306a36Sopenharmony_ci goto out_free; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci /* The data does not contain 0xff so we use that to check the size */ 8062306a36Sopenharmony_ci for (i = bufsz; i > 0; i--) { 8162306a36Sopenharmony_ci if (*(i - 1 + (u8 *)event) != 0xff) 8262306a36Sopenharmony_ci break; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci if (i != sz) { 8562306a36Sopenharmony_ci pr_debug("Event size mismatch: actual %zu vs expected %zu\n", 8662306a36Sopenharmony_ci i, sz); 8762306a36Sopenharmony_ci goto out_free; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci evsel.sample_size = __evsel__sample_size(sample_type); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci err = evsel__parse_sample(&evsel, event, &sample_out); 9362306a36Sopenharmony_ci if (err) { 9462306a36Sopenharmony_ci pr_debug("%s failed for sample_type %#"PRIx64", error %d\n", 9562306a36Sopenharmony_ci "evsel__parse_sample", sample_type, err); 9662306a36Sopenharmony_ci goto out_free; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (!samples_same(&sample, &sample_out, sample_type)) { 10062306a36Sopenharmony_ci pr_debug("parsing failed for sample_type %#"PRIx64"\n", 10162306a36Sopenharmony_ci sample_type); 10262306a36Sopenharmony_ci goto out_free; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci ret = 0; 10662306a36Sopenharmony_ciout_free: 10762306a36Sopenharmony_ci free(event); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return ret; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/** 11362306a36Sopenharmony_ci * test__x86_sample_parsing - test X86 specific sample parsing 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci * This function implements a test that synthesizes a sample event, parses it 11662306a36Sopenharmony_ci * and then checks that the parsed sample matches the original sample. If the 11762306a36Sopenharmony_ci * test passes %0 is returned, otherwise %-1 is returned. 11862306a36Sopenharmony_ci * 11962306a36Sopenharmony_ci * For now, the PERF_SAMPLE_WEIGHT_STRUCT is the only X86 specific sample type. 12062306a36Sopenharmony_ci * The test only checks the PERF_SAMPLE_WEIGHT_STRUCT type. 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_ciint test__x86_sample_parsing(struct test_suite *test __maybe_unused, int subtest __maybe_unused) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci return do_test(PERF_SAMPLE_WEIGHT_STRUCT); 12562306a36Sopenharmony_ci} 126