blob: 8196ff74a07c0f0854be1c129e06ab3879bff1e4 [file] [log] [blame]
#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;
}