| #include <stdint.h> |
| #include <stdlib.h> |
| |
| #ifdef __akaros__ |
| |
| #include <parlib/stdio.h> |
| #include <parlib/uthread.h> |
| #include <parlib/timing.h> |
| #include <parlib/event.h> |
| #include <benchutil/measure.h> |
| |
| static void ev_handle_null(struct event_msg *ev_msg, unsigned int ev_type, |
| void *data) |
| { |
| } |
| |
| static void os_init(void) |
| { |
| uthread_mcp_init(); |
| register_ev_handler(EV_FREE_APPLE_PIE, ev_handle_null, NULL); |
| } |
| |
| #else |
| |
| /* Build on linux from $AKAROS_ROOT: |
| * gcc -static --std=gnu99 tests/interference.c -o lin-interference |
| */ |
| |
| #include <stdio.h> |
| #include "../user/parlib/include/parlib/tsc-compat.h" |
| #include "misc-compat.h" |
| |
| struct sample_stats { |
| int (*get_sample)(void **data, int i, int j, uint64_t *sample); |
| uint64_t avg_time; |
| uint64_t var_time; |
| uint64_t max_time; |
| uint64_t min_time; |
| unsigned int lat_50; |
| unsigned int lat_75; |
| unsigned int lat_90; |
| unsigned int lat_99; |
| uint64_t total_samples; |
| }; |
| |
| void compute_stats(void **data, int nr_i, int nr_j, struct sample_stats *stats) |
| { |
| /* TODO: could try to link against benchutil. */ |
| } |
| |
| static void os_init(void) |
| { |
| printf("Linux: If you get a segfault, make sure rdpmc is allowed.\n" |
| "Linux: Set /sys/bus/event_source/devices/cpu/rdpmc = 2 on recent kernels (4.0), or 1 for older kernels.\n"); |
| } |
| |
| #endif |
| |
| static uint64_t *delays; |
| |
| static int get_delay(void **data, int i, int j, uint64_t *sample) |
| { |
| uint64_t **delay_array = (uint64_t**)data; |
| |
| *sample = delay_array[i][j]; |
| return 0; |
| } |
| |
| static inline __attribute__((always_inline)) |
| uint64_t pmc_cycles(void) |
| { |
| unsigned int a = 0, d = 0; |
| int ecx = (1 << 30) + 1; |
| |
| asm volatile("lfence; rdpmc" : "=a"(a), "=d"(d) : "c"(ecx)); |
| return ((uint64_t)a) | (((uint64_t)d) << 32); |
| } |
| |
| int main(int argc, char **argv) |
| { |
| #define THRESHOLD 200 |
| uint64_t start, diff; |
| struct sample_stats stats[1]; |
| size_t idx = 0; |
| size_t nr_below_thresh = 0; |
| size_t nr_over_thresh = 0; |
| size_t total = 0; |
| int pcoreid; |
| uint64_t low_samples[THRESHOLD] = {0}; |
| int nr_samples = 1000; |
| uint64_t deadline = sec2tsc(5); /* assumes TSC and cycles are close */ |
| |
| /* Normally we'd use a 2D array, but since we're just one thread, we |
| * just need our first thread's array. */ |
| delays = malloc(sizeof(uint64_t) * nr_samples); |
| os_init(); |
| pcoreid = get_pcoreid(); |
| udelay(1000); |
| deadline += pmc_cycles(); |
| |
| do { |
| if (idx >= nr_samples) |
| break; |
| total++; |
| start = pmc_cycles(); |
| diff = pmc_cycles() - start; |
| if (diff < COUNT_OF(low_samples)) |
| low_samples[diff]++; |
| if (diff < THRESHOLD) { |
| nr_below_thresh++; |
| } else { |
| nr_over_thresh++; |
| delays[idx++] = diff; |
| } |
| if (!start) { |
| printf("rdpmc got 0, is perf stat -e cycles running? (aborting)\n"); |
| break; |
| } |
| } while (start < deadline); |
| |
| printf("\n\nStats for interference\n"); |
| stats->get_sample = get_delay; |
| compute_stats((void**)&delays, 1, idx, stats); |
| |
| printf("\n\nStats for low rdtsc times (tsc ticks for two rdtscs)\n"); |
| for (int i = 0; i < COUNT_OF(low_samples); i++) { |
| if (low_samples[i]) |
| printf("\t[ %2d ] : %lu\n", i, low_samples[i]); |
| } |
| |
| printf("Pcoreid was %d (and is now %d)\n\n", pcoreid, get_pcoreid()); |
| printf("Total loops %lu, threshold %u\n", total, THRESHOLD); |
| printf("Nr over thresh %lu (%f%% total)\n", nr_over_thresh, |
| nr_over_thresh * 100.0 / total); |
| printf("Nr below thresh %lu (%f%% total)\n", nr_below_thresh, |
| nr_below_thresh * 100.0 / total); |
| return 0; |
| } |