aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib/src/vespa/vespalib/test/thread_meets.h
blob: 26ca560641d1db58e83b5bde784a46915f234274 (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
133
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#pragma once

#include <vespa/vespalib/util/rendezvous.h>

namespace vespalib::test {

/**
 * Generally useful rendezvous implementations.
 **/
struct ThreadMeets {
    // can be used as a simple thread barrier
    struct Nop : vespalib::Rendezvous<bool,bool> {
        explicit Nop(size_t N) : vespalib::Rendezvous<bool,bool>(N) {}
        void operator()() { rendezvous(false); }
        void mingle() override;
    };
    // calculate the average value across threads
    struct Avg : Rendezvous<double, double> {
        explicit Avg(size_t n) : Rendezvous<double, double>(n) {}
        double operator()(double value) { return rendezvous(value); }
        void mingle() override;
    };
    // threads vote for true/false, majority wins (false on tie)
    struct Vote : Rendezvous<bool, bool> {
        explicit Vote(size_t n) : Rendezvous<bool, bool>(n) {}
        bool operator()(bool flag) { return rendezvous(flag); }
        void mingle() override;
    };
    // sum of values across all threads
    template <typename T>
    struct Sum : vespalib::Rendezvous<T,T> {
        using vespalib::Rendezvous<T,T>::in;
        using vespalib::Rendezvous<T,T>::out;
        using vespalib::Rendezvous<T,T>::size;
        using vespalib::Rendezvous<T,T>::rendezvous;
        explicit Sum(size_t N) : vespalib::Rendezvous<T,T>(N) {}
        T operator()(T value) { return rendezvous(value); }
        void mingle() override {
            T acc = in(0);
            for (size_t i = 1; i < size(); ++i) {
                acc += in(i);
            }
            for (size_t i = 0; i < size(); ++i) {
                out(i) = acc;
            }
        }
    };
    // maximum of values across all threads
    template <typename T>
    struct Max : vespalib::Rendezvous<T,T> {
        using vespalib::Rendezvous<T,T>::in;
        using vespalib::Rendezvous<T,T>::out;
        using vespalib::Rendezvous<T,T>::size;
        using vespalib::Rendezvous<T,T>::rendezvous;
        explicit Max(size_t N) : vespalib::Rendezvous<T,T>(N) {}
        T operator()(T value) { return rendezvous(value); }
        void mingle() override {
            T max = in(0);
            for (size_t i = 1; i < size(); ++i) {
                if (in(i) > max) {
                    max = in(i);
                }
            }
            for (size_t i = 0; i < size(); ++i) {
                out(i) = max;
            }
        }
    };
    // minimum of values across all threads
    template <typename T>
    struct Min : vespalib::Rendezvous<T,T> {
        using vespalib::Rendezvous<T,T>::in;
        using vespalib::Rendezvous<T,T>::out;
        using vespalib::Rendezvous<T,T>::size;
        using vespalib::Rendezvous<T,T>::rendezvous;
        explicit Min(size_t N) : vespalib::Rendezvous<T,T>(N) {}
        T operator()(T value) { return rendezvous(value); }
        void mingle() override {
            T min = in(0);
            for (size_t i = 1; i < size(); ++i) {
                if (in(i) < min) {
                    min = in(i);
                }
            }
            for (size_t i = 0; i < size(); ++i) {
                out(i) = min;
            }
        }
    };
    // range of values across all threads
    template <typename T>
    struct Range : vespalib::Rendezvous<T,T> {
        using vespalib::Rendezvous<T,T>::in;
        using vespalib::Rendezvous<T,T>::out;
        using vespalib::Rendezvous<T,T>::size;
        using vespalib::Rendezvous<T,T>::rendezvous;
        explicit Range(size_t N) : vespalib::Rendezvous<T,T>(N) {}
        T operator()(T value) { return rendezvous(value); }
        void mingle() override {
            T min = in(0);
            T max = in(0);
            for (size_t i = 1; i < size(); ++i) {
                if (in(i) < min) {
                    min = in(i);
                }
                if (in(i) > max) {
                    max = in(i);
                }
            }
            T result = (max - min);
            for (size_t i = 0; i < size(); ++i) {
                out(i) = result;
            }
        }
    };
    // swap values between 2 threads
    template <typename T>
    struct Swap : vespalib::Rendezvous<T,T> {
        using vespalib::Rendezvous<T,T>::in;
        using vespalib::Rendezvous<T,T>::out;
        using vespalib::Rendezvous<T,T>::rendezvous;
        Swap() : vespalib::Rendezvous<T,T>(2) {}
        T operator()(T input) { return rendezvous(input); }
        void mingle() override {
            out(1) = std::move(in(0));
            out(0) = std::move(in(1));
        }
    };
};

}