summaryrefslogtreecommitdiff
path: root/benchmarks/harness.h
blob: 72164b47a0392931f929c7060061aba57c1a4bd6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <stdint.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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,
        "  <benchmark name=\"%s\">\n"
        "    <res>%zu</res>\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,
        "    <time unit=\"ns\">%zu</time>\n"
        "    <throughput unit=\"MiB/s\">%f</throughput>\n",
        best,
        ((double)(buffer_size) / (1024.0*1024.0)) / ((double)(best) / (1000.0*1000.0*1000.0))
    );

    if (best_energy != 0) {
        fprintf(out,
            "    <energy-consumption unit=\"J/GiB\">%f</energy-consumption>\n",
            ((double)(best_energy) / (1000.0*1000.0)) / ((double)(buffer_size) / (1024.0*1024.0*1024.0))
        );
    }
    fprintf(out, "  </benchmark>\n");
}

#define bench(FN) bench_(#FN, FN, buffer, buf_size, out)