#include #include #include #include #include static uint64_t time_get_ns (void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC_RAW, &ts); return (uint64_t)ts.tv_sec * 1000UL*1000UL*1000UL + (uint64_t)ts.tv_nsec; } uint64_t read_energy_uj (void) { FILE *f = fopen("/sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj", "r"); if (!f) { perror("Failed to open energy counter (Are you running with sudo?)"); return 0; } uint64_t energy; if (fscanf(f, "%lu", &energy) != 1) { energy = 0; } fclose(f); return energy; } #define BLACK_BOX(x) \ __asm__ __volatile__("" : "+g"(x)) #define MIN(A,B) (A) < (B) ? (A) : (B) void bench_ ( char const* const name, #ifdef CONST_BUFFER size_t(*f)(char const*, size_t), char const* buffer, #else size_t(*f)(char*, size_t), char* buffer, #endif size_t buffer_size, FILE* out ) { int64_t budget = 5UL*1000UL*1000UL*1000UL; uint64_t best = UINT64_MAX; uint64_t best_energy = UINT64_MAX; #ifndef CONST_BUFFER char* const tmp_buf = (char*)malloc(buffer_size); memcpy(tmp_buf, buffer, buffer_size); #endif uint64_t res = f(buffer, buffer_size); fprintf(out, " \n" " %zu\n", name, res ); while (budget > 0) { #ifndef CONST_BUFFER memcpy(buffer, tmp_buf, buffer_size); #endif uint64_t start_energy = read_energy_uj(); uint64_t start = time_get_ns(); res = f(buffer, buffer_size); uint64_t elapsed = time_get_ns() - start; best = MIN(best, elapsed); best_energy = MIN(best_energy, read_energy_uj() - start_energy); budget -= elapsed; BLACK_BOX(res); } fprintf(out, " \n" " %f\n", best, ((double)(buffer_size) / (1024.0*1024.0)) / ((double)(best) / (1000.0*1000.0*1000.0)) ); if (best_energy != 0) { fprintf(out, " %f\n", ((double)(best_energy) / (1000.0*1000.0)) / ((double)(buffer_size) / (1024.0*1024.0*1024.0)) ); } fprintf(out, " \n"); } #define bench(FN) bench_(#FN, FN, buffer, buf_size, out)