0001
0002
0003
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 "ebb.h"
0014
0015
0016
0017
0018
0019
0020
0021 extern void thirty_two_instruction_loop(uint64_t loops);
0022
0023 static bool counters_frozen = true;
0024
0025 static int do_count_loop(struct event *event, uint64_t instructions,
0026 uint64_t overhead, bool report)
0027 {
0028 int64_t difference, expected;
0029 double percentage;
0030
0031 clear_ebb_stats();
0032
0033 counters_frozen = false;
0034 mb();
0035 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
0036
0037 thirty_two_instruction_loop(instructions >> 5);
0038
0039 counters_frozen = true;
0040 mb();
0041 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC);
0042
0043 count_pmc(4, sample_period);
0044
0045 event->result.value = ebb_state.stats.pmc_count[4-1];
0046 expected = instructions + overhead;
0047 difference = event->result.value - expected;
0048 percentage = (double)difference / event->result.value * 100;
0049
0050 if (report) {
0051 printf("Looped for %lu instructions, overhead %lu\n", instructions, overhead);
0052 printf("Expected %lu\n", expected);
0053 printf("Actual %llu\n", event->result.value);
0054 printf("Delta %ld, %f%%\n", difference, percentage);
0055 printf("Took %d EBBs\n", ebb_state.stats.ebb_count);
0056 }
0057
0058 if (difference < 0)
0059 difference = -difference;
0060
0061
0062 difference *= 10000 * 100;
0063 if (difference / event->result.value)
0064 return -1;
0065
0066 return 0;
0067 }
0068
0069
0070 static uint64_t determine_overhead(struct event *event)
0071 {
0072 uint64_t current, overhead;
0073 int i;
0074
0075 do_count_loop(event, 0, 0, false);
0076 overhead = event->result.value;
0077
0078 for (i = 0; i < 100; i++) {
0079 do_count_loop(event, 0, 0, false);
0080 current = event->result.value;
0081 if (current < overhead) {
0082 printf("Replacing overhead %lu with %lu\n", overhead, current);
0083 overhead = current;
0084 }
0085 }
0086
0087 return overhead;
0088 }
0089
0090 static void pmc4_ebb_callee(void)
0091 {
0092 uint64_t val;
0093
0094 val = mfspr(SPRN_BESCR);
0095 if (!(val & BESCR_PMEO)) {
0096 ebb_state.stats.spurious++;
0097 goto out;
0098 }
0099
0100 ebb_state.stats.ebb_count++;
0101 count_pmc(4, sample_period);
0102 out:
0103 if (counters_frozen)
0104 reset_ebb_with_clear_mask(MMCR0_PMAO);
0105 else
0106 reset_ebb();
0107 }
0108
0109 int instruction_count(void)
0110 {
0111 struct event event;
0112 uint64_t overhead;
0113
0114 SKIP_IF(!ebb_is_supported());
0115
0116 event_init_named(&event, 0x400FA, "PM_RUN_INST_CMPL");
0117 event_leader_ebb_init(&event);
0118 event.attr.exclude_kernel = 1;
0119 event.attr.exclude_hv = 1;
0120 event.attr.exclude_idle = 1;
0121
0122 FAIL_IF(event_open(&event));
0123 FAIL_IF(ebb_event_enable(&event));
0124
0125 sample_period = COUNTER_OVERFLOW;
0126
0127 setup_ebb_handler(pmc4_ebb_callee);
0128 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
0129 ebb_global_enable();
0130
0131 overhead = determine_overhead(&event);
0132 printf("Overhead of null loop: %lu instructions\n", overhead);
0133
0134
0135 FAIL_IF(do_count_loop(&event, 0x100000, overhead, true));
0136
0137
0138 FAIL_IF(do_count_loop(&event, 0xa00000, overhead, true));
0139
0140
0141 FAIL_IF(do_count_loop(&event, 0x6400000, overhead, true));
0142
0143
0144 FAIL_IF(do_count_loop(&event, 0x40000000, overhead, true));
0145
0146
0147 FAIL_IF(do_count_loop(&event, 0x400000000, overhead, true));
0148
0149
0150 FAIL_IF(do_count_loop(&event, 0x1000000000, overhead, true));
0151
0152
0153 FAIL_IF(do_count_loop(&event, 0x2000000000, overhead, true));
0154
0155 ebb_global_disable();
0156 event_close(&event);
0157
0158 printf("Finished OK\n");
0159
0160 return 0;
0161 }
0162
0163 int main(void)
0164 {
0165 test_harness_set_timeout(300);
0166 return test_harness(instruction_count, "instruction_count");
0167 }