GNU Linux-libre 4.14.302-gnu1
[releases.git] / tools / testing / selftests / powerpc / pmu / count_instructions.c
1 /*
2  * Copyright 2013, Michael Ellerman, IBM Corp.
3  * Licensed under GPLv2.
4  */
5
6 #define _GNU_SOURCE
7
8 #include <stdio.h>
9 #include <stdbool.h>
10 #include <string.h>
11 #include <sys/prctl.h>
12
13 #include "event.h"
14 #include "utils.h"
15 #include "lib.h"
16
17 extern void thirty_two_instruction_loop(u64 loops);
18
19 static void setup_event(struct event *e, u64 config, char *name)
20 {
21         event_init_opts(e, config, PERF_TYPE_HARDWARE, name);
22
23         e->attr.disabled = 1;
24         e->attr.exclude_kernel = 1;
25         e->attr.exclude_hv = 1;
26         e->attr.exclude_idle = 1;
27 }
28
29 static int do_count_loop(struct event *events, u64 instructions,
30                          u64 overhead, bool report)
31 {
32         s64 difference, expected;
33         double percentage;
34
35         prctl(PR_TASK_PERF_EVENTS_ENABLE);
36
37         /* Run for 1M instructions */
38         thirty_two_instruction_loop(instructions >> 5);
39
40         prctl(PR_TASK_PERF_EVENTS_DISABLE);
41
42         event_read(&events[0]);
43         event_read(&events[1]);
44
45         expected = instructions + overhead;
46         difference = events[0].result.value - expected;
47         percentage = (double)difference / events[0].result.value * 100;
48
49         if (report) {
50                 event_report(&events[0]);
51                 event_report(&events[1]);
52
53                 printf("Looped for %llu instructions, overhead %llu\n", instructions, overhead);
54                 printf("Expected %llu\n", expected);
55                 printf("Actual   %llu\n", events[0].result.value);
56                 printf("Delta    %lld, %f%%\n", difference, percentage);
57         }
58
59         event_reset(&events[0]);
60         event_reset(&events[1]);
61
62         if (difference < 0)
63                 difference = -difference;
64
65         /* Tolerate a difference below 0.0001 % */
66         difference *= 10000 * 100;
67         if (difference / events[0].result.value)
68                 return -1;
69
70         return 0;
71 }
72
73 /* Count how many instructions it takes to do a null loop */
74 static u64 determine_overhead(struct event *events)
75 {
76         u64 current, overhead;
77         int i;
78
79         do_count_loop(events, 0, 0, false);
80         overhead = events[0].result.value;
81
82         for (i = 0; i < 100; i++) {
83                 do_count_loop(events, 0, 0, false);
84                 current = events[0].result.value;
85                 if (current < overhead) {
86                         printf("Replacing overhead %llu with %llu\n", overhead, current);
87                         overhead = current;
88                 }
89         }
90
91         return overhead;
92 }
93
94 static int test_body(void)
95 {
96         struct event events[2];
97         u64 overhead;
98
99         setup_event(&events[0], PERF_COUNT_HW_INSTRUCTIONS, "instructions");
100         setup_event(&events[1], PERF_COUNT_HW_CPU_CYCLES, "cycles");
101
102         if (event_open(&events[0])) {
103                 perror("perf_event_open");
104                 return -1;
105         }
106
107         if (event_open_with_group(&events[1], events[0].fd)) {
108                 perror("perf_event_open");
109                 return -1;
110         }
111
112         overhead = determine_overhead(events);
113         printf("Overhead of null loop: %llu instructions\n", overhead);
114
115         /* Run for 1Mi instructions */
116         FAIL_IF(do_count_loop(events, 1000000, overhead, true));
117
118         /* Run for 10Mi instructions */
119         FAIL_IF(do_count_loop(events, 10000000, overhead, true));
120
121         /* Run for 100Mi instructions */
122         FAIL_IF(do_count_loop(events, 100000000, overhead, true));
123
124         /* Run for 1Bi instructions */
125         FAIL_IF(do_count_loop(events, 1000000000, overhead, true));
126
127         /* Run for 16Bi instructions */
128         FAIL_IF(do_count_loop(events, 16000000000, overhead, true));
129
130         /* Run for 64Bi instructions */
131         FAIL_IF(do_count_loop(events, 64000000000, overhead, true));
132
133         event_close(&events[0]);
134         event_close(&events[1]);
135
136         return 0;
137 }
138
139 static int count_instructions(void)
140 {
141         return eat_cpu(test_body);
142 }
143
144 int main(void)
145 {
146         return test_harness(count_instructions, "count_instructions");
147 }