root/tools/testing/selftests/powerpc/pmu/count_instructions.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. setup_event
  2. do_count_loop
  3. determine_overhead
  4. test_body
  5. count_instructions
  6. main

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright 2013, Michael Ellerman, IBM Corp.
   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 }

/* [<][>][^][v][top][bottom][index][help] */