Home | History | Annotate | Download | only in pmu
      1 /*
      2  * Copyright 2014, Michael Ellerman, IBM Corp.
      3  * Licensed under GPLv2.
      4  */
      5 
      6 #define _GNU_SOURCE
      7 
      8 #include <elf.h>
      9 #include <limits.h>
     10 #include <stdio.h>
     11 #include <stdbool.h>
     12 #include <string.h>
     13 #include <sys/prctl.h>
     14 
     15 #include "event.h"
     16 #include "lib.h"
     17 #include "utils.h"
     18 
     19 /*
     20  * Test that per-event excludes work.
     21  */
     22 
     23 static int per_event_excludes(void)
     24 {
     25 	struct event *e, events[4];
     26 	char *platform;
     27 	int i;
     28 
     29 	platform = (char *)get_auxv_entry(AT_BASE_PLATFORM);
     30 	FAIL_IF(!platform);
     31 	SKIP_IF(strcmp(platform, "power8") != 0);
     32 
     33 	/*
     34 	 * We need to create the events disabled, otherwise the running/enabled
     35 	 * counts don't match up.
     36 	 */
     37 	e = &events[0];
     38 	event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
     39 			PERF_TYPE_HARDWARE, "instructions");
     40 	e->attr.disabled = 1;
     41 
     42 	e = &events[1];
     43 	event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
     44 			PERF_TYPE_HARDWARE, "instructions(k)");
     45 	e->attr.disabled = 1;
     46 	e->attr.exclude_user = 1;
     47 	e->attr.exclude_hv = 1;
     48 
     49 	e = &events[2];
     50 	event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
     51 			PERF_TYPE_HARDWARE, "instructions(h)");
     52 	e->attr.disabled = 1;
     53 	e->attr.exclude_user = 1;
     54 	e->attr.exclude_kernel = 1;
     55 
     56 	e = &events[3];
     57 	event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
     58 			PERF_TYPE_HARDWARE, "instructions(u)");
     59 	e->attr.disabled = 1;
     60 	e->attr.exclude_hv = 1;
     61 	e->attr.exclude_kernel = 1;
     62 
     63 	FAIL_IF(event_open(&events[0]));
     64 
     65 	/*
     66 	 * The open here will fail if we don't have per event exclude support,
     67 	 * because the second event has an incompatible set of exclude settings
     68 	 * and we're asking for the events to be in a group.
     69 	 */
     70 	for (i = 1; i < 4; i++)
     71 		FAIL_IF(event_open_with_group(&events[i], events[0].fd));
     72 
     73 	/*
     74 	 * Even though the above will fail without per-event excludes we keep
     75 	 * testing in order to be thorough.
     76 	 */
     77 	prctl(PR_TASK_PERF_EVENTS_ENABLE);
     78 
     79 	/* Spin for a while */
     80 	for (i = 0; i < INT_MAX; i++)
     81 		asm volatile("" : : : "memory");
     82 
     83 	prctl(PR_TASK_PERF_EVENTS_DISABLE);
     84 
     85 	for (i = 0; i < 4; i++) {
     86 		FAIL_IF(event_read(&events[i]));
     87 		event_report(&events[i]);
     88 	}
     89 
     90 	/*
     91 	 * We should see that all events have enabled == running. That
     92 	 * shows that they were all on the PMU at once.
     93 	 */
     94 	for (i = 0; i < 4; i++)
     95 		FAIL_IF(events[i].result.running != events[i].result.enabled);
     96 
     97 	/*
     98 	 * We can also check that the result for instructions is >= all the
     99 	 * other counts. That's because it is counting all instructions while
    100 	 * the others are counting a subset.
    101 	 */
    102 	for (i = 1; i < 4; i++)
    103 		FAIL_IF(events[0].result.value < events[i].result.value);
    104 
    105 	for (i = 0; i < 4; i++)
    106 		event_close(&events[i]);
    107 
    108 	return 0;
    109 }
    110 
    111 int main(void)
    112 {
    113 	return test_harness(per_event_excludes, "per_event_excludes");
    114 }
    115