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 "event.h"
0014 #include "utils.h"
0015 #include "lib.h"
0016
0017 extern void thirty_two_instruction_loop_with_ll_sc(u64 loops, u64 *ll_sc_target);
0018
0019 static void setup_event(struct event *e, u64 config, int type, char *name)
0020 {
0021 event_init_opts(e, config, type, 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 u64 dummy;
0035
0036 prctl(PR_TASK_PERF_EVENTS_ENABLE);
0037
0038
0039 thirty_two_instruction_loop_with_ll_sc(instructions >> 5, &dummy);
0040
0041 prctl(PR_TASK_PERF_EVENTS_DISABLE);
0042
0043 event_read(&events[0]);
0044 event_read(&events[1]);
0045 event_read(&events[2]);
0046
0047 expected = instructions + overhead + (events[2].result.value * 10);
0048 difference = events[0].result.value - expected;
0049 percentage = (double)difference / events[0].result.value * 100;
0050
0051 if (report) {
0052 printf("-----\n");
0053 event_report(&events[0]);
0054 event_report(&events[1]);
0055 event_report(&events[2]);
0056
0057 printf("Looped for %llu instructions, overhead %llu\n", instructions, overhead);
0058 printf("Expected %llu\n", expected);
0059 printf("Actual %llu\n", events[0].result.value);
0060 printf("Delta %lld, %f%%\n", difference, percentage);
0061 }
0062
0063 event_reset(&events[0]);
0064 event_reset(&events[1]);
0065 event_reset(&events[2]);
0066
0067 if (difference < 0)
0068 difference = -difference;
0069
0070
0071 difference *= 10000 * 100;
0072 if (difference / events[0].result.value)
0073 return -1;
0074
0075 return 0;
0076 }
0077
0078
0079 static u64 determine_overhead(struct event *events)
0080 {
0081 u64 current, overhead;
0082 int i;
0083
0084 do_count_loop(events, 0, 0, false);
0085 overhead = events[0].result.value;
0086
0087 for (i = 0; i < 100; i++) {
0088 do_count_loop(events, 0, 0, false);
0089 current = events[0].result.value;
0090 if (current < overhead) {
0091 printf("Replacing overhead %llu with %llu\n", overhead, current);
0092 overhead = current;
0093 }
0094 }
0095
0096 return overhead;
0097 }
0098
0099 #define PM_MRK_STCX_FAIL 0x03e158
0100 #define PM_STCX_FAIL 0x01e058
0101
0102 static int test_body(void)
0103 {
0104 struct event events[3];
0105 u64 overhead;
0106
0107
0108 SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_2_07));
0109
0110 setup_event(&events[0], PERF_COUNT_HW_INSTRUCTIONS, PERF_TYPE_HARDWARE, "instructions");
0111 setup_event(&events[1], PERF_COUNT_HW_CPU_CYCLES, PERF_TYPE_HARDWARE, "cycles");
0112 setup_event(&events[2], PM_STCX_FAIL, PERF_TYPE_RAW, "stcx_fail");
0113
0114 if (event_open(&events[0])) {
0115 perror("perf_event_open");
0116 return -1;
0117 }
0118
0119 if (event_open_with_group(&events[1], events[0].fd)) {
0120 perror("perf_event_open");
0121 return -1;
0122 }
0123
0124 if (event_open_with_group(&events[2], events[0].fd)) {
0125 perror("perf_event_open");
0126 return -1;
0127 }
0128
0129 overhead = determine_overhead(events);
0130 printf("Overhead of null loop: %llu instructions\n", overhead);
0131
0132
0133 FAIL_IF(do_count_loop(events, 1000000, overhead, true));
0134
0135
0136 FAIL_IF(do_count_loop(events, 10000000, overhead, true));
0137
0138
0139 FAIL_IF(do_count_loop(events, 100000000, overhead, true));
0140
0141
0142 FAIL_IF(do_count_loop(events, 1000000000, overhead, true));
0143
0144
0145 FAIL_IF(do_count_loop(events, 16000000000, overhead, true));
0146
0147
0148 FAIL_IF(do_count_loop(events, 64000000000, overhead, true));
0149
0150 event_close(&events[0]);
0151 event_close(&events[1]);
0152
0153 return 0;
0154 }
0155
0156 static int count_ll_sc(void)
0157 {
0158 return eat_cpu(test_body);
0159 }
0160
0161 int main(void)
0162 {
0163 return test_harness(count_ll_sc, "count_ll_sc");
0164 }