Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2013, Michael Ellerman, IBM Corp.
0003  * Licensed under GPLv2.
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     /* Run for 1M instructions */
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     /* Tolerate a difference below 0.0001 % */
0071     difference *= 10000 * 100;
0072     if (difference / events[0].result.value)
0073         return -1;
0074 
0075     return 0;
0076 }
0077 
0078 /* Count how many instructions it takes to do a null loop */
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     // The STCX_FAIL event we use works on Power8 or later
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     /* Run for 1Mi instructions */
0133     FAIL_IF(do_count_loop(events, 1000000, overhead, true));
0134 
0135     /* Run for 10Mi instructions */
0136     FAIL_IF(do_count_loop(events, 10000000, overhead, true));
0137 
0138     /* Run for 100Mi instructions */
0139     FAIL_IF(do_count_loop(events, 100000000, overhead, true));
0140 
0141     /* Run for 1Bi instructions */
0142     FAIL_IF(do_count_loop(events, 1000000000, overhead, true));
0143 
0144     /* Run for 16Bi instructions */
0145     FAIL_IF(do_count_loop(events, 16000000000, overhead, true));
0146 
0147     /* Run for 64Bi instructions */
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 }