File: concurrent_lru_cache_common.h

package info (click to toggle)
onetbb 2022.3.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 19,440 kB
  • sloc: cpp: 129,228; ansic: 9,745; python: 808; xml: 183; objc: 176; makefile: 66; sh: 66; awk: 41; javascript: 37
file content (257 lines) | stat: -rw-r--r-- 8,195 bytes parent folder | download | duplicates (4)
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
/*
    Copyright (c) 2005-2022 Intel Corporation

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

#ifndef __TBB_test_common_concurrent_lru_cache_common
#define __TBB_test_common_concurrent_lru_cache_common


#include "test.h"
#include "utils.h"
#include <tbb/concurrent_lru_cache.h>

//-----------------------------------------------------------------------------
// Concurrent LRU Cache Tests: Cache Helpers
//-----------------------------------------------------------------------------

namespace concurrent_lru_cache_helpers {

    // call counter

    template<std::size_t id>
    struct tag{};

    template<typename Tag, typename Type>
    struct call_counter {
        static int calls;

        static Type call(Type t) {
            ++calls;
            return t;
        }
    };

    template<typename Tag, typename Type>
    int call_counter<Tag, Type>::calls = 0;

    // cloner

    template<typename ValueType>
    struct cloner {
        ValueType& my_ref_to_original;

        cloner(ValueType& ref_to_original) : my_ref_to_original(ref_to_original) {}

        template<typename KeyType>
        ValueType operator()(KeyType) const { return my_ref_to_original; }
    };

    // map searcher

    template <typename KeyType, typename ValueType>
    struct map_searcher {
        using map_type = std::map<KeyType, ValueType>;
        using map_iter = typename map_type::iterator;

        map_type& my_map_ref;

        map_searcher(map_type& map_ref) : my_map_ref(map_ref) {}

        ValueType& operator()(KeyType k) {
            map_iter it = my_map_ref.find(k);
            if (it == my_map_ref.end())
                it = my_map_ref.insert(it, std::make_pair(k, ValueType()));

            return it->second;
        }
    };

    // array searcher

    template<typename key_type, typename value_type, std::size_t array_size>
    struct array_searcher {
        using array_type = value_type[array_size];

        array_type const& my_array_ref;

        array_searcher(array_type const& array_ref) : my_array_ref(array_ref) {}

        const value_type& operator()(key_type k) const {
            std::size_t index = k;
            REQUIRE_MESSAGE(k < array_size, "incorrect test setup");
            return my_array_ref[index];
        }
    };

    // instance counter

    template<typename CounterType = std::size_t>
    struct instance_counter {
        CounterType* my_p_count;

        instance_counter() : my_p_count(new CounterType) {
            *my_p_count = 1;
        }

        instance_counter(instance_counter const& other) : my_p_count(other.my_p_count) {
            ++(*my_p_count);
        }

        instance_counter& operator=(instance_counter other) {
            std::swap(this->my_p_count, other.my_p_count);
            return *this;
        }

        ~instance_counter() {
            bool is_last = ! --(*my_p_count);
#if __GNUC__ == 12
        // GCC 12 warns about using my_p_count after delete.
        // The test was investigated and no problems were detected
        // The following statement silence the warning
        static bool unused_is_last = is_last;
        utils::suppress_unused_warning(unused_is_last);
#endif
            if (is_last)
                delete(my_p_count);
        }
        std::size_t instances_count() const { return *my_p_count; }
    };

    using instance_serial_counter = instance_counter<>;
    using instance_concurrent_counter = instance_counter<std::atomic<std::size_t>>;
};

//-----------------------------------------------------------------------------
// Concurrent LRU Cache Tests: Cache Presets
//-----------------------------------------------------------------------------

namespace concurrent_lru_cache_presets {

    namespace helpers = concurrent_lru_cache_helpers;

    // base preset with common typedefs and fields

    template<typename... CacheTypes>
    struct preset_base {
        using cache_type = tbb::concurrent_lru_cache<CacheTypes...>;
        using handle_type = typename cache_type::handle;

        preset_base() {}
        preset_base(const preset_base&) = delete;
        preset_base(preset_base&&) = delete;
        preset_base& operator=(const preset_base&) = delete;
        preset_base& operator=(preset_base&&) = delete;
    };

    // default preset

    template<typename Key, typename Value>
    struct preset_default : preset_base<Key, Value> {
        using cache_type = typename preset_base<Key, Value>::cache_type;
        using handle_type = typename cache_type::handle;
        using callback_type = typename cache_type::value_function_type;

        const std::size_t number_of_lru_history_items;
        cache_type cache;

        preset_default(callback_type callback, std::size_t history_items) :
            number_of_lru_history_items(history_items),
            cache(callback, number_of_lru_history_items) {};
    };

    // preset1

    struct preset1 : preset_base<std::string, std::string> {
        const std::size_t number_of_lru_history_items;
        cache_type cache;
        handle_type default_ctor_check;

        static std::string callback(std::string key) { return key; }

        preset1() :
            number_of_lru_history_items(1),
            cache(&callback, number_of_lru_history_items) {};
    };

    // preset for call counting

    template<std::size_t tag_id>
    struct preset_call_count : preset_base<int, int> {
        using cache_miss_tag = helpers::tag<tag_id>;
        using counter_type = helpers::call_counter<cache_miss_tag, int>;

        const std::size_t number_of_lru_history_items;
        cache_type cache;

        preset_call_count() :
            number_of_lru_history_items(8),
            cache(&counter_type::call, number_of_lru_history_items) {}
    };

    // preset for instance counting

    struct preset_instance_count : preset_base<
        std::size_t, helpers::instance_serial_counter,
        helpers::cloner<helpers::instance_serial_counter>> {

        using cloner_type = helpers::cloner<helpers::instance_serial_counter>;

        helpers::instance_serial_counter source;
        cloner_type cloner;
        const std::size_t number_of_lru_history_items;
        cache_type cache;

        preset_instance_count() :
            cloner(source),
            number_of_lru_history_items(8),
            cache(cloner, number_of_lru_history_items) {}
    };

    // preset for instance counting with external map

    struct preset_map_instance_count : preset_base<
        std::size_t, helpers::instance_serial_counter,
        helpers::map_searcher<std::size_t, helpers::instance_serial_counter>> {

        using map_searcher_type = helpers::map_searcher<std::size_t, helpers::instance_serial_counter>;
        using objects_map_type = map_searcher_type::map_type;

        static const std::size_t number_of_lru_history_items;
        map_searcher_type::map_type objects_map;
        cache_type cache;

        preset_map_instance_count() :
            cache(map_searcher_type(objects_map), number_of_lru_history_items) {}

        bool is_evicted(std::size_t key) {
            objects_map_type::iterator it = objects_map.find(key);

            REQUIRE_MESSAGE(
                it != objects_map.end(),
                "no value for key - error in test logic ?");

            return it->second.instances_count() == 1;
        }

        void fill_up_cache(std::size_t lower_bound, std::size_t upper_bound) {
            for (std::size_t i = lower_bound; i < upper_bound; ++i)
                cache[i];
        }
    };

    const std::size_t preset_map_instance_count::number_of_lru_history_items = 8;
};

#endif // __TBB_test_common_concurrent_lru_cache_common