Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright 2013, Michael Ellerman, IBM Corp.
0004  */
0005 
0006 #define _GNU_SOURCE
0007 
0008 #include <stdio.h>
0009 #include <stdbool.h>
0010 #include <string.h>
0011 #include <sys/prctl.h>
0012 
0013 #include "event.h"
0014 #include "utils.h"
0015 #include "lib.h"
0016 
0017 extern void thirty_two_instruction_loop(u64 loops);
0018 
0019 static void setup_event(struct event *e, u64 config, char *name)
0020 {
0021     event_init_opts(e, config, PERF_TYPE_HARDWARE, name);
0022 
0023     e->attr.disabled = 1;
0024     e->attr.exclude_kernel = 1;
0025     e->attr.exclude_hv = 1;
0026     e->attr.exclude_idle = 1;
0027 }
0028 
0029 static int do_count_loop(struct event *events, u64 instructions,
0030              u64 overhead, bool report)
0031 {
0032     s64 difference, expected;
0033     double percentage;
0034 
0035     prctl(PR_TASK_PERF_EVENTS_ENABLE);
0036 
0037     /* Run for 1M instructions */
0038     thirty_two_instruction_loop(instructions >> 5);
0039 
0040     prctl(PR_TASK_PERF_EVENTS_DISABLE);
0041 
0042     event_read(&events[0]);
0043     event_read(&events[1]);
0044 
0045     expected = instructions + overhead;
0046     difference = events[0].result.value - expected;
0047     percentage = (double)difference / events[0].result.value * 100;
0048 
0049     if (report) {
0050         event_report(&events[0]);
0051         event_report(&events[1]);
0052 
0053         printf("Looped for %llu instructions, overhead %llu\n", instructions, overhead);
0054         printf("Expected %llu\n", expected);
0055         printf("Actual   %llu\n", events[0].result.value);
0056         printf("Delta    %lld, %f%%\n", difference, percentage);
0057     }
0058 
0059     event_reset(&events[0]);
0060     event_reset(&events[1]);
0061 
0062     if (difference < 0)
0063         difference = -difference;
0064 
0065     /* Tolerate a difference below 0.0001 % */
0066     difference *= 10000 * 100;
0067     if (difference / events[0].result.value)
0068         return -1;
0069 
0070     return 0;
0071 }
0072 
0073 /* Count how many instructions it takes to do a null loop */
0074 static u64 determine_overhead(struct event *events)
0075 {
0076     u64 current, overhead;
0077     int i;
0078 
0079     do_count_loop(events, 0, 0, false);
0080     overhead = events[0].result.value;
0081 
0082     for (i = 0; i < 100; i++) {
0083         do_count_loop(events, 0, 0, false);
0084         current = events[0].result.value;
0085         if (current < overhead) {
0086             printf("Replacing overhead %llu with %llu\n", overhead, current);
0087             overhead = current;
0088         }
0089     }
0090 
0091     return overhead;
0092 }
0093 
0094 static int test_body(void)
0095 {
0096     struct event events[2];
0097     u64 overhead;
0098 
0099     setup_event(&events[0], PERF_COUNT_HW_INSTRUCTIONS, "instructions");
0100     setup_event(&events[1], PERF_COUNT_HW_CPU_CYCLES, "cycles");
0101 
0102     if (event_open(&events[0])) {
0103         perror("perf_event_open");
0104         return -1;
0105     }
0106 
0107     if (event_open_with_group(&events[1], events[0].fd)) {
0108         perror("perf_event_open");
0109         return -1;
0110     }
0111 
0112     overhead = determine_overhead(events);
0113     printf("Overhead of null loop: %llu instructions\n", overhead);
0114 
0115     /* Run for 1Mi instructions */
0116     FAIL_IF(do_count_loop(events, 1000000, overhead, true));
0117 
0118     /* Run for 10Mi instructions */
0119     FAIL_IF(do_count_loop(events, 10000000, overhead, true));
0120 
0121     /* Run for 100Mi instructions */
0122     FAIL_IF(do_count_loop(events, 100000000, overhead, true));
0123 
0124     /* Run for 1Bi instructions */
0125     FAIL_IF(do_count_loop(events, 1000000000, overhead, true));
0126 
0127     /* Run for 16Bi instructions */
0128     FAIL_IF(do_count_loop(events, 16000000000, overhead, true));
0129 
0130     /* Run for 64Bi instructions */
0131     FAIL_IF(do_count_loop(events, 64000000000, overhead, true));
0132 
0133     event_close(&events[0]);
0134     event_close(&events[1]);
0135 
0136     return 0;
0137 }
0138 
0139 static int count_instructions(void)
0140 {
0141     return eat_cpu(test_body);
0142 }
0143 
0144 int main(void)
0145 {
0146     return test_harness(count_instructions, "count_instructions");
0147 }