File: last_written_value_tests.cpp

package info (click to toggle)
opencv 4.5.1%2Bdfsg-5
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 268,248 kB
  • sloc: cpp: 969,170; xml: 682,525; python: 36,732; lisp: 30,170; java: 25,155; ansic: 7,927; javascript: 5,643; objc: 2,041; sh: 935; cs: 601; perl: 494; makefile: 145
file content (156 lines) | stat: -rw-r--r-- 4,409 bytes parent folder | download
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
144
145
146
147
148
149
150
151
152
153
154
155
156
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2020 Intel Corporation

#include "../test_precomp.hpp"

#include <unordered_set>
#include <thread>

#include "executor/last_value.hpp"

namespace opencv_test {
using namespace cv::gapi;

TEST(LastValue, PushPop) {
    own::last_written_value<int> v;
    for (int i = 0; i < 100; i++) {
        v.push(i);

        int x = 1;
        v.pop(x);
        EXPECT_EQ(x, i);
    }
}

TEST(LastValue, TryPop) {
    own::last_written_value<int> v;
    int x = 0;
    EXPECT_FALSE(v.try_pop(x));

    v.push(1);
    EXPECT_TRUE(v.try_pop(x));
    EXPECT_EQ(1, x);
}

TEST(LastValue, Clear) {
    own::last_written_value<int> v;
    v.push(42);
    v.clear();

    int x = 0;
    EXPECT_FALSE(v.try_pop(x));
}

TEST(LastValue, Overwrite) {
    own::last_written_value<int> v;
    v.push(42);
    v.push(0);

    int x = -1;
    EXPECT_TRUE(v.try_pop(x));
    EXPECT_EQ(0, x);
}

// In this test, every writer thread produces its own range of integer
// numbers, writing those to a shared queue.
//
// Every reader thread pops elements from the queue (until -1 is
// reached) and stores those in its own associated set.
//
// Finally, the master thread waits for completion of all other
// threads and verifies that all the necessary data is
// produced/obtained.
namespace {
using StressParam = std::tuple<int   // Num writer threads
                              ,int   // Num elements per writer
                              ,int>; // Num reader threads
constexpr int STOP_SIGN = -1;
constexpr int BASE      = 1000;
}
struct LastValue_: public ::testing::TestWithParam<StressParam> {
    using V = own::last_written_value<int>;
    using S = std::unordered_set<int>;

    static void writer(int base, int writes, V& v) {
        for (int i = 0; i < writes; i++) {
            if (i % 2) {
                std::this_thread::sleep_for(std::chrono::milliseconds{1});
            }
            v.push(base + i);
        }
        v.push(STOP_SIGN);
    }

    static void reader(V& v, S& s) {
        int x = 0;
        while (true) {
            v.pop(x);
            if (x == STOP_SIGN) {
                // If this thread was lucky enough to read this STOP_SIGN,
                // push it back to v to make other possible readers able
                // to read it again (note due to the last_written_value
                // semantic, those STOP_SIGN could be simply lost i.e.
                // overwritten.
                v.push(STOP_SIGN);
                return;
            }
            s.insert(x);
        }
    }
};

TEST_P(LastValue_, Test)
{
    int num_writers = 0;
    int num_writes  = 0;
    int num_readers = 0;
    std::tie(num_writers, num_writes, num_readers) = GetParam();

    CV_Assert(num_writers <   20);
    CV_Assert(num_writes  < BASE);

    V v;

    // Start reader threads
    std::vector<S> storage(num_readers);
    std::vector<std::thread> readers;
    for (S& s : storage) {
        readers.emplace_back(reader, std::ref(v), std::ref(s));
    }

    // Start writer threads, also pre-generate reference numbers
    S reference;
    std::vector<std::thread> writers;
    for (int w = 0; w < num_writers; w++) {
        writers.emplace_back(writer, w*BASE, num_writes, std::ref(v));
        for (int r = 0; r < num_writes; r++) {
            reference.insert(w*BASE + r);
        }
    }

    // Wait for completions
    for (auto &t : readers) t.join();
    for (auto &t : writers) t.join();

    // Validate the result. Some values are read, and the values are
    // correct (i.e. such values have been written)
    std::size_t num_values_read = 0u;
    for (const auto &s : storage) {
        num_values_read += s.size();
        for (auto &x : s) {
            EXPECT_TRUE(reference.count(x) > 0);
        }
    }
    // NOTE: Some combinations may end-up in 0 values read
    // it is normal, the main thing is that the test shouldn't hang!
    EXPECT_LE(0u, num_values_read);
}

INSTANTIATE_TEST_CASE_P(LastValueStress, LastValue_,
                        Combine( Values(1, 2, 4, 8, 16)  // writers
                               , Values(32, 96, 256)     // writes
                               , Values(1, 2, 10)));     // readers
} // namespace opencv_test