aboutsummaryrefslogtreecommitdiffstats
path: root/src/argon2-impl-select.c
blob: b4c18a7bde930420750a4297ae5c7478ecd87f6f (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
#include <time.h>
#include <string.h>

#include "argon2-impl-select.h"

#include "argon2.h"

#define BENCH_SAMPLES 512
#define BENCH_MEM_BLOCKS 512

static argon2_impl selected_argon_impl = {
    "(default)", NULL, fill_segment_default
};

/* the benchmark routine is not thread-safe, so we can use a global var here: */
static block memory[BENCH_MEM_BLOCKS];

static uint64_t benchmark_impl(const argon2_impl *impl) {
    clock_t time;
    unsigned int i;
    uint64_t bench;
    argon2_instance_t instance;
    argon2_position_t pos;

    memset(memory, 0, sizeof(memory));

    instance.version = ARGON2_VERSION_NUMBER;
    instance.memory = memory;
    instance.passes = 1;
    instance.memory_blocks = BENCH_MEM_BLOCKS;
    instance.segment_length = BENCH_MEM_BLOCKS / ARGON2_SYNC_POINTS;
    instance.lane_length = instance.segment_length * ARGON2_SYNC_POINTS;
    instance.lanes = 1;
    instance.threads = 1;
    instance.type = Argon2_i;

    pos.lane = 0;
    pos.pass = 0;
    pos.slice = 0;
    pos.index = 0;

    /* warm-up cache: */
    impl->fill_segment(&instance, pos);

    /* OK, now measure: */
    bench = 0;
    time = clock();
    for (i = 0; i < BENCH_SAMPLES; i++) {
        impl->fill_segment(&instance, pos);
    }
    time = clock() - time;
    bench = (uint64_t)time;
    return bench;
}

static void select_impl(FILE *out, const char *prefix)
{
    argon2_impl_list impls;
    unsigned int i;
    const argon2_impl *best_impl = NULL;
    uint64_t best_bench = UINT_MAX;

    argon2_get_impl_list(&impls);

    for (i = 0; i < impls.count; i++) {
        const argon2_impl *impl = &impls.entries[i];
        uint64_t bench;

        bench = benchmark_impl(impl);

        if (bench < best_bench) {
            best_bench = bench;
            best_impl = impl;
        }
    }

    if (best_impl != NULL) {
        selected_argon_impl = *best_impl;
    } 
}

void fill_segment(const argon2_instance_t *instance, argon2_position_t position)
{
    selected_argon_impl.fill_segment(instance, position);
}

void argon2_select_impl(FILE *out, const char *prefix)
{
    if (prefix == NULL) {
        prefix = "";
    }
    select_impl(out, prefix);
}