Home | History | Annotate | Download | only in tests
      1 #include <stdbool.h>
      2 #include <inttypes.h>
      3 
      4 #include "util.h"
      5 #include "event.h"
      6 #include "evsel.h"
      7 
      8 #include "tests.h"
      9 
     10 #define COMP(m) do {					\
     11 	if (s1->m != s2->m) {				\
     12 		pr_debug("Samples differ at '"#m"'\n");	\
     13 		return false;				\
     14 	}						\
     15 } while (0)
     16 
     17 #define MCOMP(m) do {					\
     18 	if (memcmp(&s1->m, &s2->m, sizeof(s1->m))) {	\
     19 		pr_debug("Samples differ at '"#m"'\n");	\
     20 		return false;				\
     21 	}						\
     22 } while (0)
     23 
     24 static bool samples_same(const struct perf_sample *s1,
     25 			 const struct perf_sample *s2, u64 type, u64 regs_user,
     26 			 u64 read_format)
     27 {
     28 	size_t i;
     29 
     30 	if (type & PERF_SAMPLE_IDENTIFIER)
     31 		COMP(id);
     32 
     33 	if (type & PERF_SAMPLE_IP)
     34 		COMP(ip);
     35 
     36 	if (type & PERF_SAMPLE_TID) {
     37 		COMP(pid);
     38 		COMP(tid);
     39 	}
     40 
     41 	if (type & PERF_SAMPLE_TIME)
     42 		COMP(time);
     43 
     44 	if (type & PERF_SAMPLE_ADDR)
     45 		COMP(addr);
     46 
     47 	if (type & PERF_SAMPLE_ID)
     48 		COMP(id);
     49 
     50 	if (type & PERF_SAMPLE_STREAM_ID)
     51 		COMP(stream_id);
     52 
     53 	if (type & PERF_SAMPLE_CPU)
     54 		COMP(cpu);
     55 
     56 	if (type & PERF_SAMPLE_PERIOD)
     57 		COMP(period);
     58 
     59 	if (type & PERF_SAMPLE_READ) {
     60 		if (read_format & PERF_FORMAT_GROUP)
     61 			COMP(read.group.nr);
     62 		else
     63 			COMP(read.one.value);
     64 		if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
     65 			COMP(read.time_enabled);
     66 		if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
     67 			COMP(read.time_running);
     68 		/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
     69 		if (read_format & PERF_FORMAT_GROUP) {
     70 			for (i = 0; i < s1->read.group.nr; i++)
     71 				MCOMP(read.group.values[i]);
     72 		} else {
     73 			COMP(read.one.id);
     74 		}
     75 	}
     76 
     77 	if (type & PERF_SAMPLE_CALLCHAIN) {
     78 		COMP(callchain->nr);
     79 		for (i = 0; i < s1->callchain->nr; i++)
     80 			COMP(callchain->ips[i]);
     81 	}
     82 
     83 	if (type & PERF_SAMPLE_RAW) {
     84 		COMP(raw_size);
     85 		if (memcmp(s1->raw_data, s2->raw_data, s1->raw_size)) {
     86 			pr_debug("Samples differ at 'raw_data'\n");
     87 			return false;
     88 		}
     89 	}
     90 
     91 	if (type & PERF_SAMPLE_BRANCH_STACK) {
     92 		COMP(branch_stack->nr);
     93 		for (i = 0; i < s1->branch_stack->nr; i++)
     94 			MCOMP(branch_stack->entries[i]);
     95 	}
     96 
     97 	if (type & PERF_SAMPLE_REGS_USER) {
     98 		size_t sz = hweight_long(regs_user) * sizeof(u64);
     99 
    100 		COMP(user_regs.abi);
    101 		if (s1->user_regs.abi &&
    102 		    (!s1->user_regs.regs || !s2->user_regs.regs ||
    103 		     memcmp(s1->user_regs.regs, s2->user_regs.regs, sz))) {
    104 			pr_debug("Samples differ at 'user_regs'\n");
    105 			return false;
    106 		}
    107 	}
    108 
    109 	if (type & PERF_SAMPLE_STACK_USER) {
    110 		COMP(user_stack.size);
    111 		if (memcmp(s1->user_stack.data, s1->user_stack.data,
    112 			   s1->user_stack.size)) {
    113 			pr_debug("Samples differ at 'user_stack'\n");
    114 			return false;
    115 		}
    116 	}
    117 
    118 	if (type & PERF_SAMPLE_WEIGHT)
    119 		COMP(weight);
    120 
    121 	if (type & PERF_SAMPLE_DATA_SRC)
    122 		COMP(data_src);
    123 
    124 	return true;
    125 }
    126 
    127 static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
    128 {
    129 	struct perf_evsel evsel = {
    130 		.needs_swap = false,
    131 		.attr = {
    132 			.sample_type = sample_type,
    133 			.sample_regs_user = sample_regs_user,
    134 			.read_format = read_format,
    135 		},
    136 	};
    137 	union perf_event *event;
    138 	union {
    139 		struct ip_callchain callchain;
    140 		u64 data[64];
    141 	} callchain = {
    142 		/* 3 ips */
    143 		.data = {3, 201, 202, 203},
    144 	};
    145 	union {
    146 		struct branch_stack branch_stack;
    147 		u64 data[64];
    148 	} branch_stack = {
    149 		/* 1 branch_entry */
    150 		.data = {1, 211, 212, 213},
    151 	};
    152 	u64 user_regs[64];
    153 	const u64 raw_data[] = {0x123456780a0b0c0dULL, 0x1102030405060708ULL};
    154 	const u64 data[] = {0x2211443366558877ULL, 0, 0xaabbccddeeff4321ULL};
    155 	struct perf_sample sample = {
    156 		.ip		= 101,
    157 		.pid		= 102,
    158 		.tid		= 103,
    159 		.time		= 104,
    160 		.addr		= 105,
    161 		.id		= 106,
    162 		.stream_id	= 107,
    163 		.period		= 108,
    164 		.weight		= 109,
    165 		.cpu		= 110,
    166 		.raw_size	= sizeof(raw_data),
    167 		.data_src	= 111,
    168 		.raw_data	= (void *)raw_data,
    169 		.callchain	= &callchain.callchain,
    170 		.branch_stack	= &branch_stack.branch_stack,
    171 		.user_regs	= {
    172 			.abi	= PERF_SAMPLE_REGS_ABI_64,
    173 			.regs	= user_regs,
    174 		},
    175 		.user_stack	= {
    176 			.size	= sizeof(data),
    177 			.data	= (void *)data,
    178 		},
    179 		.read		= {
    180 			.time_enabled = 0x030a59d664fca7deULL,
    181 			.time_running = 0x011b6ae553eb98edULL,
    182 		},
    183 	};
    184 	struct sample_read_value values[] = {{1, 5}, {9, 3}, {2, 7}, {6, 4},};
    185 	struct perf_sample sample_out;
    186 	size_t i, sz, bufsz;
    187 	int err, ret = -1;
    188 
    189 	for (i = 0; i < sizeof(user_regs); i++)
    190 		*(i + (u8 *)user_regs) = i & 0xfe;
    191 
    192 	if (read_format & PERF_FORMAT_GROUP) {
    193 		sample.read.group.nr     = 4;
    194 		sample.read.group.values = values;
    195 	} else {
    196 		sample.read.one.value = 0x08789faeb786aa87ULL;
    197 		sample.read.one.id    = 99;
    198 	}
    199 
    200 	sz = perf_event__sample_event_size(&sample, sample_type,
    201 					   sample_regs_user, read_format);
    202 	bufsz = sz + 4096; /* Add a bit for overrun checking */
    203 	event = malloc(bufsz);
    204 	if (!event) {
    205 		pr_debug("malloc failed\n");
    206 		return -1;
    207 	}
    208 
    209 	memset(event, 0xff, bufsz);
    210 	event->header.type = PERF_RECORD_SAMPLE;
    211 	event->header.misc = 0;
    212 	event->header.size = sz;
    213 
    214 	err = perf_event__synthesize_sample(event, sample_type,
    215 					    sample_regs_user, read_format,
    216 					    &sample, false);
    217 	if (err) {
    218 		pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
    219 			 "perf_event__synthesize_sample", sample_type, err);
    220 		goto out_free;
    221 	}
    222 
    223 	/* The data does not contain 0xff so we use that to check the size */
    224 	for (i = bufsz; i > 0; i--) {
    225 		if (*(i - 1 + (u8 *)event) != 0xff)
    226 			break;
    227 	}
    228 	if (i != sz) {
    229 		pr_debug("Event size mismatch: actual %zu vs expected %zu\n",
    230 			 i, sz);
    231 		goto out_free;
    232 	}
    233 
    234 	evsel.sample_size = __perf_evsel__sample_size(sample_type);
    235 
    236 	err = perf_evsel__parse_sample(&evsel, event, &sample_out);
    237 	if (err) {
    238 		pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
    239 			 "perf_evsel__parse_sample", sample_type, err);
    240 		goto out_free;
    241 	}
    242 
    243 	if (!samples_same(&sample, &sample_out, sample_type,
    244 			  sample_regs_user, read_format)) {
    245 		pr_debug("parsing failed for sample_type %#"PRIx64"\n",
    246 			 sample_type);
    247 		goto out_free;
    248 	}
    249 
    250 	ret = 0;
    251 out_free:
    252 	free(event);
    253 	if (ret && read_format)
    254 		pr_debug("read_format %#"PRIx64"\n", read_format);
    255 	return ret;
    256 }
    257 
    258 /**
    259  * test__sample_parsing - test sample parsing.
    260  *
    261  * This function implements a test that synthesizes a sample event, parses it
    262  * and then checks that the parsed sample matches the original sample.  The test
    263  * checks sample format bits separately and together.  If the test passes %0 is
    264  * returned, otherwise %-1 is returned.
    265  */
    266 int test__sample_parsing(void)
    267 {
    268 	const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15};
    269 	u64 sample_type;
    270 	u64 sample_regs_user;
    271 	size_t i;
    272 	int err;
    273 
    274 	/*
    275 	 * Fail the test if it has not been updated when new sample format bits
    276 	 * were added.
    277 	 */
    278 	if (PERF_SAMPLE_MAX > PERF_SAMPLE_IDENTIFIER << 1) {
    279 		pr_debug("sample format has changed - test needs updating\n");
    280 		return -1;
    281 	}
    282 
    283 	/* Test each sample format bit separately */
    284 	for (sample_type = 1; sample_type != PERF_SAMPLE_MAX;
    285 	     sample_type <<= 1) {
    286 		/* Test read_format variations */
    287 		if (sample_type == PERF_SAMPLE_READ) {
    288 			for (i = 0; i < ARRAY_SIZE(rf); i++) {
    289 				err = do_test(sample_type, 0, rf[i]);
    290 				if (err)
    291 					return err;
    292 			}
    293 			continue;
    294 		}
    295 
    296 		if (sample_type == PERF_SAMPLE_REGS_USER)
    297 			sample_regs_user = 0x3fff;
    298 		else
    299 			sample_regs_user = 0;
    300 
    301 		err = do_test(sample_type, sample_regs_user, 0);
    302 		if (err)
    303 			return err;
    304 	}
    305 
    306 	/* Test all sample format bits together */
    307 	sample_type = PERF_SAMPLE_MAX - 1;
    308 	sample_regs_user = 0x3fff;
    309 	for (i = 0; i < ARRAY_SIZE(rf); i++) {
    310 		err = do_test(sample_type, sample_regs_user, rf[i]);
    311 		if (err)
    312 			return err;
    313 	}
    314 
    315 	return 0;
    316 }
    317