linux/tools/testing/selftests/powerpc/pmu/count_instructions.c
<<
>>
Prefs
   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
  16extern void thirty_two_instruction_loop(u64 loops);
  17
  18static void setup_event(struct event *e, u64 config, char *name)
  19{
  20        event_init_opts(e, config, PERF_TYPE_HARDWARE, name);
  21
  22        e->attr.disabled = 1;
  23        e->attr.exclude_kernel = 1;
  24        e->attr.exclude_hv = 1;
  25        e->attr.exclude_idle = 1;
  26}
  27
  28static int do_count_loop(struct event *events, u64 instructions,
  29                         u64 overhead, bool report)
  30{
  31        s64 difference, expected;
  32        double percentage;
  33
  34        prctl(PR_TASK_PERF_EVENTS_ENABLE);
  35
  36        /* Run for 1M instructions */
  37        thirty_two_instruction_loop(instructions >> 5);
  38
  39        prctl(PR_TASK_PERF_EVENTS_DISABLE);
  40
  41        event_read(&events[0]);
  42        event_read(&events[1]);
  43
  44        expected = instructions + overhead;
  45        difference = events[0].result.value - expected;
  46        percentage = (double)difference / events[0].result.value * 100;
  47
  48        if (report) {
  49                event_report(&events[0]);
  50                event_report(&events[1]);
  51
  52                printf("Looped for %llu instructions, overhead %llu\n", instructions, overhead);
  53                printf("Expected %llu\n", expected);
  54                printf("Actual   %llu\n", events[0].result.value);
  55                printf("Delta    %lld, %f%%\n", difference, percentage);
  56        }
  57
  58        event_reset(&events[0]);
  59        event_reset(&events[1]);
  60
  61        if (difference < 0)
  62                difference = -difference;
  63
  64        /* Tolerate a difference below 0.0001 % */
  65        difference *= 10000 * 100;
  66        if (difference / events[0].result.value)
  67                return -1;
  68
  69        return 0;
  70}
  71
  72/* Count how many instructions it takes to do a null loop */
  73static u64 determine_overhead(struct event *events)
  74{
  75        u64 current, overhead;
  76        int i;
  77
  78        do_count_loop(events, 0, 0, false);
  79        overhead = events[0].result.value;
  80
  81        for (i = 0; i < 100; i++) {
  82                do_count_loop(events, 0, 0, false);
  83                current = events[0].result.value;
  84                if (current < overhead) {
  85                        printf("Replacing overhead %llu with %llu\n", overhead, current);
  86                        overhead = current;
  87                }
  88        }
  89
  90        return overhead;
  91}
  92
  93static int count_instructions(void)
  94{
  95        struct event events[2];
  96        u64 overhead;
  97
  98        setup_event(&events[0], PERF_COUNT_HW_INSTRUCTIONS, "instructions");
  99        setup_event(&events[1], PERF_COUNT_HW_CPU_CYCLES, "cycles");
 100
 101        if (event_open(&events[0])) {
 102                perror("perf_event_open");
 103                return -1;
 104        }
 105
 106        if (event_open_with_group(&events[1], events[0].fd)) {
 107                perror("perf_event_open");
 108                return -1;
 109        }
 110
 111        overhead = determine_overhead(events);
 112        printf("Overhead of null loop: %llu instructions\n", overhead);
 113
 114        /* Run for 1M instructions */
 115        FAIL_IF(do_count_loop(events, 0x100000, overhead, true));
 116
 117        /* Run for 10M instructions */
 118        FAIL_IF(do_count_loop(events, 0xa00000, overhead, true));
 119
 120        /* Run for 100M instructions */
 121        FAIL_IF(do_count_loop(events, 0x6400000, overhead, true));
 122
 123        /* Run for 1G instructions */
 124        FAIL_IF(do_count_loop(events, 0x40000000, overhead, true));
 125
 126        event_close(&events[0]);
 127        event_close(&events[1]);
 128
 129        return 0;
 130}
 131
 132int main(void)
 133{
 134        return test_harness(count_instructions, "count_instructions");
 135}
 136