summaryrefslogtreecommitdiff
path: root/tests/benchmarks/signals/tst_bench_signals.cpp
blob: b1e2f7bd7545c6d165d72cf9307081f7717d03cb (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
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
133
134
135
136
137
138
139
140
141
142
143
// Copyright (C) 2018 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

#include <QtTest>

#include <functional>
#include <vector>


/*
Config: Using QtTest library 5.10.0, Qt 5.10.0 (x86_64-little_endian-lp64 shared (dynamic)
    debug build; by GCC 7.2.1 20171205)

PASS   : BenchmarkSignals::qtMemfun()
     0.000068 msecs per iteration (total: 72, iterations: 1048576)
PASS   : BenchmarkSignals::qtLambda()
     0.000066 msecs per iteration (total: 70, iterations: 1048576)
PASS   : BenchmarkSignals::manualBind()
     0.00011 msecs per iteration (total: 60, iterations: 524288)
PASS   : BenchmarkSignals::manualLambda()
     0.000043 msecs per iteration (total: 91, iterations: 2097152)


CONFIG += release

********* Start testing of BenchmarkSignals *********
PASS   : BenchmarkSignals::qtMemfun()
     0.000061 msecs per iteration (total: 64, iterations: 1048576)
PASS   : BenchmarkSignals::qtLambda()
     0.000058 msecs per iteration (total: 61, iterations: 1048576)

 // Not completely surprising, as all the top call can be inlined

PASS   : BenchmarkSignals::manualBind()
     0.0000078 msecs per iteration (total: 66, iterations: 8388608)
PASS   : BenchmarkSignals::manualLambda()
     0.00000596 msecs per iteration (total: 100, iterations: 16777216)
PASS   : BenchmarkSignals::cleanupTestCase()


The latter in instructions:

PASS   : BenchmarkSignals::qtMemfun()
     445 instruction reads per iteration (total: 445, iterations: 1)
PASS   : BenchmarkSignals::qtLambda()
     440 instruction reads per iteration (total: 440, iterations: 1)
PASS   : BenchmarkSignals::manualBind()
     113 instruction reads per iteration (total: 113, iterations: 1)
PASS   : BenchmarkSignals::manualLambda()
     107 instruction reads per iteration (total: 107, iterations: 1)

*/


template <typename Type>
class NaiveSignal
{
public:
    using Callable = std::function<Type>;

    void connect(const Callable &callable) { m_callables.push_back(callable); }

    template <typename ...Args>
    void operator()(Args ...args) const
    {
        for (const Callable &callable : m_callables)
            callable(args...);
   }

private:
    std::vector<Callable> m_callables;
};


class BenchmarkSignals : public QObject
{
    Q_OBJECT

public:
    BenchmarkSignals() {}

private slots:
    void qtMemfun();
    void qtLambda();
    void manualBind();
    void manualLambda();
};

class Tester : public QObject
{
    Q_OBJECT

public:
    NaiveSignal<void(int)> naiveSignal;

signals:
    void qtSignal(int);

public:
    void doit(int i) { sum += i; }
    int sum = 0;
};

void BenchmarkSignals::qtMemfun()
{
    Tester tester;
    connect(&tester, &Tester::qtSignal, &tester, &Tester::doit);
    QBENCHMARK {
        tester.qtSignal(1);
    }
}

void BenchmarkSignals::qtLambda()
{
    Tester tester;
    connect(&tester, &Tester::qtSignal, [&](int x) { tester.sum += x; });
    QBENCHMARK {
        tester.qtSignal(1);
    }
}

void BenchmarkSignals::manualBind()
{
    Tester tester;
    tester.naiveSignal.connect(std::bind(&Tester::doit, &tester, std::placeholders::_1));
    QBENCHMARK {
        tester.naiveSignal(1);
    }
}

void BenchmarkSignals::manualLambda()
{
    Tester tester;
    tester.naiveSignal.connect([&](int x) { tester.sum += x; });
    QBENCHMARK {
        tester.naiveSignal(1);
    }
}

QTEST_MAIN(BenchmarkSignals)

#include "tst_bench_signals.moc"