File: test_utils_tls.impl.hpp

package info (click to toggle)
opencv 4.10.0%2Bdfsg-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 282,092 kB
  • sloc: cpp: 1,178,079; xml: 682,621; python: 49,092; lisp: 31,150; java: 25,469; ansic: 11,039; javascript: 6,085; sh: 1,214; cs: 601; perl: 494; objc: 210; makefile: 173
file content (128 lines) | stat: -rw-r--r-- 3,244 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
// 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.

// This is .hpp file included from test_utils.cpp

#include <thread>  // std::thread

#include "opencv2/core/utils/tls.hpp"

namespace opencv_test { namespace {

class TLSReporter
{
public:
    static int g_last_id;
    static int g_allocated;

    int id;

    TLSReporter()
    {
        id = CV_XADD(&g_last_id, 1);
        CV_XADD(&g_allocated, 1);
    }
    ~TLSReporter()
    {
        CV_XADD(&g_allocated, -1);
    }
};

int TLSReporter::g_last_id = 0;
int TLSReporter::g_allocated = 0;

template<typename T>
static void callNThreadsWithTLS(int N, TLSData<T>& tls)
{
    std::vector<std::thread> threads(N);
    for (int i = 0; i < N; i++)
    {
        threads[i] = std::thread([&]() {
            TLSReporter* pData = tls.get();
            (void)pData;
        });
    }
    for (int i = 0; i < N; i++)
    {
        threads[i].join();
    }
    threads.clear();
}

TEST(Core_TLS, HandleThreadTermination)
{
    const int init_id = TLSReporter::g_last_id;
    const int init_allocated = TLSReporter::g_allocated;

    const int N = 4;
    TLSData<TLSReporter> tls;

    // use TLS
    ASSERT_NO_THROW(callNThreadsWithTLS(N, tls));

    EXPECT_EQ(init_id + N, TLSReporter::g_last_id);
    EXPECT_EQ(init_allocated + 0, TLSReporter::g_allocated);
}


static void testTLSAccumulator(bool detachFirst)
{
    const int init_id = TLSReporter::g_last_id;
    const int init_allocated = TLSReporter::g_allocated;

    const int N = 4;
    TLSDataAccumulator<TLSReporter> tls;

    {  // empty TLS checks
        std::vector<TLSReporter*>& data0 = tls.detachData();
        EXPECT_EQ((size_t)0, data0.size());
        tls.cleanupDetachedData();
    }

    // use TLS
    ASSERT_NO_THROW(callNThreadsWithTLS(N, tls));

    EXPECT_EQ(init_id + N, TLSReporter::g_last_id);
    EXPECT_EQ(init_allocated + N, TLSReporter::g_allocated);

    if (detachFirst)
    {
        std::vector<TLSReporter*>& data1 = tls.detachData();
        EXPECT_EQ((size_t)N, data1.size());

        // no data through gather after detachData()
        std::vector<TLSReporter*> data2;
        tls.gather(data2);
        EXPECT_EQ((size_t)0, data2.size());

        tls.cleanupDetachedData();

        EXPECT_EQ(init_id + N, TLSReporter::g_last_id);
        EXPECT_EQ(init_allocated + 0, TLSReporter::g_allocated);
        EXPECT_EQ((size_t)0, data1.size());
    }
    else
    {
        std::vector<TLSReporter*> data2;
        tls.gather(data2);
        EXPECT_EQ((size_t)N, data2.size());

        std::vector<TLSReporter*>& data1 = tls.detachData();
        EXPECT_EQ((size_t)N, data1.size());

        tls.cleanupDetachedData();

        EXPECT_EQ((size_t)0, data1.size());
        // data2 is not empty, but it has invalid contents
        EXPECT_EQ((size_t)N, data2.size());
    }

    EXPECT_EQ(init_id + N, TLSReporter::g_last_id);
    EXPECT_EQ(init_allocated + 0, TLSReporter::g_allocated);
}

TEST(Core_TLS, AccumulatorHoldData_detachData) { testTLSAccumulator(true); }
TEST(Core_TLS, AccumulatorHoldData_gather) { testTLSAccumulator(false); }

}}  // namespace