summaryrefslogtreecommitdiffstats
path: root/vespalib/src/tests/eval/function_speed/function_speed_test.cpp
blob: 888d4c6cab845e2f73c3c602defc79c4b44cb47d (plain) (blame)
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/vespalib/eval/function.h>
#include <vespa/vespalib/eval/llvm/compiled_function.h>
#include <vespa/vespalib/util/benchmark_timer.h>
#include <vespa/vespalib/eval/interpreted_function.h>

using namespace vespalib::eval;

std::vector<vespalib::string> params_5({"p", "o", "q", "f", "w"});

double sum_sum = 0.0;

const char *function_str = "(0.35*p + 0.15*o + 0.30*q + 0.20*f) * w";
Function function_ast = Function::parse(params_5, function_str);
InterpretedFunction interpreted_function(SimpleTensorEngine::ref(), function_ast);
CompiledFunction compiled_function(function_ast, PassParams::SEPARATE);
auto jit_function = compiled_function.get_function<5>();

double gcc_function(double p, double o, double q, double f, double w) {
    return (0.35*p + 0.15*o + 0.30*q + 0.20*f) * w;
}

InterpretedFunction::Context icontext;

double interpret_function(double p, double o, double q, double f, double w) {
    icontext.clear_params();
    icontext.add_param(p);
    icontext.add_param(o);
    icontext.add_param(q);
    icontext.add_param(f);
    icontext.add_param(w);
    return interpreted_function.eval(icontext).as_double();
}

//-----------------------------------------------------------------------------

const char *big_function_str = "(0.35*p + 0.15*o + 0.30*q + 0.20*f) * w + "
    "(0.35*p + 0.15*o + 0.30*q + 0.20*f) * w + "
    "(0.35*p + 0.15*o + 0.30*q + 0.20*f) * w + "
    "(0.35*p + 0.15*o + 0.30*q + 0.20*f) * w";

Function big_function_ast = Function::parse(params_5, big_function_str);
InterpretedFunction big_interpreted_function(SimpleTensorEngine::ref(), big_function_ast);
CompiledFunction big_compiled_function(big_function_ast, PassParams::SEPARATE);
auto big_jit_function = big_compiled_function.get_function<5>();

double big_gcc_function(double p, double o, double q, double f, double w) {
    return (0.35*p + 0.15*o + 0.30*q + 0.20*f) * w +
        (0.35*p + 0.15*o + 0.30*q + 0.20*f) * w +
        (0.35*p + 0.15*o + 0.30*q + 0.20*f) * w +
        (0.35*p + 0.15*o + 0.30*q + 0.20*f) * w;
}

InterpretedFunction::Context big_icontext;

double big_interpret_function(double p, double o, double q, double f, double w) {
    big_icontext.clear_params();
    big_icontext.add_param(p);
    big_icontext.add_param(o);
    big_icontext.add_param(q);
    big_icontext.add_param(f);
    big_icontext.add_param(w);
    return big_interpreted_function.eval(big_icontext).as_double();
}

//-----------------------------------------------------------------------------

double measure_best(CompiledFunction::expand<5>::type function) {
    double sum = 0.0;
    vespalib::BenchmarkTimer timer(1.0);
    while (timer.has_budget()) {
        timer.before();
        for (int p = 0; p < 10; ++p) {
            for (int o = 0; o < 10; ++o) {
                for (int q = 0; q < 10; ++q) {
                    for (int f = 0; f < 10; ++f) {
                        for (int w = 0; w < 10; ++w) {
                            sum += function(p, o, q, f, w);
                        }
                    }
                }
            }
        }
        timer.after();
    }
    return (timer.min_time() * 1000.0);
}

//-----------------------------------------------------------------------------

TEST("require that small functions return the same result") {
    EXPECT_EQUAL(interpret_function(1,2,3,4,5), jit_function(1,2,3,4,5));
    EXPECT_EQUAL(interpret_function(1,2,3,4,5), gcc_function(1,2,3,4,5));
    EXPECT_EQUAL(interpret_function(5,4,3,2,1), jit_function(5,4,3,2,1));
    EXPECT_EQUAL(interpret_function(5,4,3,2,1), gcc_function(5,4,3,2,1));
}

TEST("require that big functions return the same result") {
    EXPECT_EQUAL(big_interpret_function(1,2,3,4,5), big_jit_function(1,2,3,4,5));
    EXPECT_EQUAL(big_interpret_function(1,2,3,4,5), big_gcc_function(1,2,3,4,5));
    EXPECT_EQUAL(big_interpret_function(5,4,3,2,1), big_jit_function(5,4,3,2,1));
    EXPECT_EQUAL(big_interpret_function(5,4,3,2,1), big_gcc_function(5,4,3,2,1));
}

TEST("measure small function eval/jit/gcc speed") {
    double interpret_time = measure_best(interpret_function);
    double jit_time = measure_best(jit_function);
    double gcc_time = measure_best(gcc_function);
    double jit_vs_interpret_speed = (1.0/jit_time)/(1.0/interpret_time);
    double gcc_vs_jit_speed = (1.0/gcc_time)/(1.0/jit_time);
    fprintf(stderr, "interpret: %g ms\n", interpret_time);
    fprintf(stderr, "jit compiled: %g ms\n", jit_time);
    fprintf(stderr, "gcc compiled: %g ms\n", gcc_time);
    fprintf(stderr, "jit speed compared to interpret: %g\n", jit_vs_interpret_speed);
    fprintf(stderr, "gcc speed compared to jit: %g\n", gcc_vs_jit_speed);
}

TEST("measure big function eval/jit/gcc speed") {
    double interpret_time = measure_best(big_interpret_function);
    double jit_time = measure_best(big_jit_function);
    double gcc_time = measure_best(big_gcc_function);
    double jit_vs_interpret_speed = (1.0/jit_time)/(1.0/interpret_time);
    double gcc_vs_jit_speed = (1.0/gcc_time)/(1.0/jit_time);
    fprintf(stderr, "interpret: %g ms\n", interpret_time);
    fprintf(stderr, "jit compiled: %g ms\n", jit_time);
    fprintf(stderr, "gcc compiled: %g ms\n", gcc_time);
    fprintf(stderr, "jit speed compared to interpret: %g\n", jit_vs_interpret_speed);
    fprintf(stderr, "gcc speed compared to jit: %g\n", gcc_vs_jit_speed);
}

TEST_MAIN() { TEST_RUN_ALL(); }