Gamp v0.0.8
Gamp: Graphics, Audio, Multimedia and Processing
Loading...
Searching...
No Matches
test_hashset_perf01.cpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2020 Gothel Software e.K.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24#include <cassert>
25#include <cinttypes>
26#include <cstring>
27#include <random>
28#include <vector>
29#include <unordered_set>
30
31#include <jau/test/catch2_ext.hpp>
32
33#include "test_datatype01.hpp"
34
35#include <jau/basic_types.hpp>
36#include <jau/basic_algos.hpp>
38#include <jau/callocator.hpp>
40#include <jau/darray.hpp>
41#include <jau/cow_darray.hpp>
42#include <jau/cow_vector.hpp>
43
44using namespace jau;
45
46static uint8_t start_addr_b[] = {0x20, 0x26, 0x2A, 0x01, 0x20, 0x10};
48
49template<class T>
50const static DataType01 * findDataSet01_hash(T& data, DataType01 const & elem) noexcept {
51 auto search = data.find(elem);
52 if( search != data.end() ) {
53 return &(*search);
54 }
55 return nullptr;
56}
57
58template<class T>
59static int test_00_list_itr(T& data) {
60 int some_number = 0; // add some validated work, avoiding any 'optimization away'
61 jau::for_each_const(data, [&some_number](const DataType01 & e) {
62 some_number += e.nop();
63 } );
64 REQUIRE(some_number > 0);
65 return some_number;
66}
67
68template<class T, typename Size_type>
69static void test_00_seq_find_itr(T& data) {
71 const Size_type size = data.size();
72 Size_type fi = 0, i=0;
73
74 for(; i<size && a0.next(); ++i) {
75 DataType01 elem(a0, static_cast<uint8_t>(1));
76 const DataType01 *found = jau::find_const<T>(data, elem);
77 if( nullptr != found ) {
78 ++fi;
79 found->nop();
80 }
81 }
82 REQUIRE(fi == i);
83}
84
85template<class T>
86static void test_00_seq_find_hash(T& data) {
88 const std::size_t size = data.size();
89 std::size_t fi = 0, i=0;
90
91 for(; i<size && a0.next(); ++i) {
92 DataType01 elem(a0, static_cast<uint8_t>(1));
93 const DataType01 *found = findDataSet01_hash(data, elem);
94 if( nullptr != found ) {
95 ++fi;
96 found->nop();
97 }
98 }
99 REQUIRE(fi == i);
100}
101
102template<class T, typename Size_type>
103static void test_00_seq_fill(T& data, const Size_type size) {
105 Size_type i=0;
106
107 for(; i<size && a0.next(); ++i) {
108 data.emplace_back( a0, static_cast<uint8_t>(1) );
109 }
110 REQUIRE(i == data.size());
111}
112
113template<class T, typename Size_type>
114static void test_00_seq_fill_unique_itr(T& data, const Size_type size) {
116 Size_type i=0, fi=0;
117
118 for(; i<size && a0.next(); ++i) {
119 DataType01 elem(a0, static_cast<uint8_t>(1));
120 const DataType01* exist = jau::find_const<T>(data, elem);
121 if( nullptr == exist ) {
122 data.push_back( std::move( elem ) );
123 ++fi;
124 }
125 }
126 REQUIRE(i == data.size());
127 REQUIRE(fi == size);
128}
129
130template<class T>
131static void test_00_seq_fill_unique_hash(T& data, const std::size_t size) {
133 std::size_t i=0, fi=0;
134
135 for(; i<size && a0.next(); ++i) {
136 if( data.emplace(a0, static_cast<uint8_t>(1)).second ) {
137 ++fi;
138 }
139 }
140 REQUIRE(i == data.size());
141 REQUIRE(fi == size);
142}
143
144template<class T>
145static void print_mem(const std::string& pre, const T& data) {
146 std::size_t bytes_element = sizeof(DataType01);
147 std::size_t elements = data.size();
148 std::size_t bytes_net = elements * bytes_element;
149 std::size_t bytes_total = data.get_allocator().memory_usage;
150 double overhead = 0 == bytes_total ? 0.0 : ( 0 == bytes_net ? 10.0 : (double)bytes_total / (double)bytes_net );
151 jau_printf("Mem: %s: Elements %'5zu x %zu bytes; %s, %lf ratio\n",
152 pre.c_str(), elements, bytes_element, data.get_allocator().toString(), overhead);
153 // 5: 1,000
154 // 7: 100,000
155 // 9: 1,000,000
156}
157
158
159/****************************************************************************************
160 ****************************************************************************************/
161
162template<class T, typename Size_type>
163static bool test_01_seq_fill_list_itr(const std::string& type_id, const Size_type size0, const Size_type reserve0, const bool do_print_mem) {
164 T data;
165 REQUIRE(0 == data.get_allocator().memory_usage);
166 REQUIRE(data.size() == 0);
167 // if( do_print_mem ) { print_mem(type_id+" 01 (empty)", data); }
168
169 if( 0 < reserve0 ) {
170 data.reserve(reserve0);
171 REQUIRE(data.size() == 0);
172 REQUIRE(0 != data.get_allocator().memory_usage);
173 REQUIRE(data.capacity() == reserve0);
174 }
175
177 REQUIRE(0 != data.get_allocator().memory_usage);
178 REQUIRE(data.size() == size0);
179
181 REQUIRE(0 != data.get_allocator().memory_usage);
182 REQUIRE(data.size() == size0);
183 if( do_print_mem ) { print_mem(type_id+" 01 (full_)", data); }
184
185 data.clear();
186 REQUIRE(data.size() == 0);
187 // if( do_print_mem ) { print_mem(type_id+" 01 (clear)", data); }
188 // REQUIRE(0 == data.get_allocator().memory_usage);
189 return data.size() == 0;
190}
191
192template<class T>
193static std::size_t get_capacity(const T& data) {
194 const std::size_t bucket_count = data.bucket_count();
195 std::size_t capacity = 0;
196 for(std::size_t i=0; i<bucket_count; i++) {
197 capacity = data.bucket_size(i);
198 }
199 return capacity;
200}
201
202static bool test_01_seq_fill_list_hash(const std::string& type_id, const std::size_t size0, const std::size_t reserve0, const bool do_print_mem) {
203 typedef std::unordered_set<DataType01, std::hash<DataType01>, std::equal_to<DataType01>, counting_allocator<DataType01>> DataType01Set;
204 DataType01Set data;
205 REQUIRE(0 == data.get_allocator().memory_usage);
206 REQUIRE(data.size() == 0);
207 // if( do_print_mem ) { print_mem(type_id+" 01 (empty)", data); }
208
209 if( 0 < reserve0 ) {
210 data.reserve(reserve0);
211 REQUIRE(data.size() == 0);
212 REQUIRE(0 != data.get_allocator().memory_usage);
213 REQUIRE(get_capacity<DataType01Set>(data) >= reserve0);
214 }
215
216 test_00_seq_fill_unique_hash(data, size0);
217 REQUIRE(0 != data.get_allocator().memory_usage);
218 REQUIRE(data.size() == size0);
219
221 REQUIRE(0 != data.get_allocator().memory_usage);
222 REQUIRE(data.size() == size0);
223 if( do_print_mem ) { print_mem(type_id+" 01 (full_)", data); }
224
225 data.clear();
226 REQUIRE(data.size() == 0);
227 // if( do_print_mem ) { print_mem(type_id+" 01 (clear)", data); }
228 // REQUIRE(0 == data.get_allocator().memory_usage);
229 return data.size() == 0;
230}
231
232template<class T, typename Size_type>
233static bool test_02_seq_fillunique_find_itr(const std::string& type_id, const Size_type size0, const Size_type reserve0) {
234 (void)type_id;
235 T data;
236 REQUIRE(data.size() == 0);
237
238 if( 0 < reserve0 ) {
239 data.reserve(reserve0);
240 REQUIRE(data.size() == 0);
241 REQUIRE(data.capacity() == reserve0);
242 }
243
245 REQUIRE(data.size() == size0);
246
248 REQUIRE(data.size() == size0);
249
250 data.clear();
251 REQUIRE(data.size() == 0);
252 return data.size() == 0;
253}
254
255static bool test_02_seq_fillunique_find_hash(const std::string& type_id, const std::size_t size0, const std::size_t reserve0) {
256 (void)type_id;
257 typedef std::unordered_set<DataType01, std::hash<DataType01>, std::equal_to<DataType01>, std::allocator<DataType01>> DataType01Set;
258 DataType01Set data;
259 REQUIRE(data.size() == 0);
260
261 if( 0 < reserve0 ) {
262 data.reserve(reserve0);
263 REQUIRE(data.size() == 0);
264 // REQUIRE(0 != data.get_allocator().memory_usage);
265 // REQUIRE(get_capacity<DataType01Set>(data) >= reserve0);
266 }
267
268 test_00_seq_fill_unique_hash(data, size0);
269 REQUIRE(data.size() == size0);
270
272 REQUIRE(data.size() == size0);
273
274 data.clear();
275 REQUIRE(data.size() == 0);
276 return data.size() == 0;
277}
278
279/****************************************************************************************
280 ****************************************************************************************/
281
282template<class T, typename Size_type>
283static bool footprint_fillseq_list_itr(const std::string& type_id, const bool do_rserv) {
284 // test_01_seq_fill_list_itr<T, Size_type>(type_id, 25, do_rserv? 25 : 0, true);
285 test_01_seq_fill_list_itr<T, Size_type>(type_id, 50, do_rserv? 50 : 0, true);
286 if( !catch_auto_run ) {
287 test_01_seq_fill_list_itr<T, Size_type>(type_id, 100, do_rserv? 100 : 0, true);
288 test_01_seq_fill_list_itr<T, Size_type>(type_id, 1000, do_rserv? 1000 : 0, true);
289 }
290 return true;
291}
292
293static bool footprint_fillseq_list_hash(const std::string& type_id, const bool do_rserv) {
294 // test_01_seq_fill_list_hash(type_id, 25, do_rserv? 25 : 0, true);
295 test_01_seq_fill_list_hash(type_id, 50, do_rserv? 50 : 0, true);
296 if( !catch_auto_run ) {
297 test_01_seq_fill_list_hash(type_id, 100, do_rserv? 100 : 0, true);
298 test_01_seq_fill_list_hash(type_id, 1000, do_rserv? 1000 : 0, true);
299 }
300 return true;
301}
302
303template<class T, typename Size_type>
304static bool benchmark_fillunique_find_itr(const std::string& title_pre, const std::string& type_id,
305 const bool do_rserv) {
306 if( catch_perf_analysis ) {
307 BENCHMARK(title_pre+" FillUni_List 1000") {
308 return test_02_seq_fillunique_find_itr<T, Size_type>(type_id, 1000, do_rserv? 1000 : 0);
309 };
310 // test_02_seq_fillunique_find_itr<T, Size_type>(type_id, 100000, do_rserv? 100000 : 0);
311 return true;
312 }
313 if( catch_auto_run ) {
314 test_02_seq_fillunique_find_itr<T, Size_type>(type_id, 50, do_rserv? 50 : 0);
315 return true;
316 }
317 // BENCHMARK(title_pre+" FillUni_List 25") {
318 // return test_02_seq_fillunique_find_itr<T, Size_type>(type_id, 25, do_rserv? 25 : 0);
319 // };
320 BENCHMARK(title_pre+" FillUni_List 50") {
321 return test_02_seq_fillunique_find_itr<T, Size_type>(type_id, 50, do_rserv? 50 : 0);
322 };
323 BENCHMARK(title_pre+" FillUni_List 100") {
324 return test_02_seq_fillunique_find_itr<T, Size_type>(type_id, 100, do_rserv? 100 : 0);
325 };
326 BENCHMARK(title_pre+" FillUni_List 1000") {
327 return test_02_seq_fillunique_find_itr<T, Size_type>(type_id, 1000, do_rserv? 1000 : 0);
328 };
329 return true;
330}
331
332static bool benchmark_fillunique_find_hash(const std::string& title_pre, const std::string& type_id,
333 const bool do_rserv) {
334 if( catch_perf_analysis ) {
335 BENCHMARK(title_pre+" FillUni_List 1000") {
336 return test_02_seq_fillunique_find_hash(type_id, 1000, do_rserv? 1000 : 0);
337 };
338 // test_02_seq_fillunique_find_hash(type_id, 100000, do_rserv? 100000 : 0, false);
339 return true;
340 }
341 if( catch_auto_run ) {
342 test_02_seq_fillunique_find_hash(type_id, 50, do_rserv? 50 : 0);
343 return true;
344 }
345 // BENCHMARK(title_pre+" FillUni_List 25") {
346 // return test_02_seq_fillunique_find_hash(type_id, 25, do_rserv? 25 : 0);
347 // };
348 BENCHMARK(title_pre+" FillUni_List 50") {
349 return test_02_seq_fillunique_find_hash(type_id, 50, do_rserv? 50 : 0);
350 };
351 BENCHMARK(title_pre+" FillUni_List 100") {
352 return test_02_seq_fillunique_find_hash(type_id, 100, do_rserv? 100 : 0);
353 };
354 BENCHMARK(title_pre+" FillUni_List 1000") {
355 return test_02_seq_fillunique_find_hash(type_id, 1000, do_rserv? 1000 : 0);
356 };
357 return true;
358}
359
360/****************************************************************************************
361 ****************************************************************************************/
362TEST_CASE( "Memory Footprint 01 - Fill Sequential and List", "[datatype][footprint]" ) {
363 if( catch_perf_analysis ) {
364 footprint_fillseq_list_hash("hash__set_empty_", false);
367 return;
368 }
369 footprint_fillseq_list_hash("hash__set_empty_", false);
374}
375
376TEST_CASE( "Perf Test 02 - Fill Unique and List, empty and reserve", "[datatype][unique]" ) {
377 if( catch_perf_analysis ) {
378 benchmark_fillunique_find_hash("HashSet_NoOrdr_empty", "hash__set_empty_", false);
379 benchmark_fillunique_find_itr< jau::cow_vector<DataType01, std::allocator<DataType01>>, std::size_t>("COW_Vector_empty_itr", "cowstdvec_empty_", false);
381
382 return;
383 }
384 benchmark_fillunique_find_hash("HashSet_NoOrdr_empty", "hash__set_empty_", false);
385 benchmark_fillunique_find_itr< std::vector<DataType01, std::allocator<DataType01>>, std::size_t>("STD_Vector_empty_itr", "stdvec_empty_", false);
387 benchmark_fillunique_find_itr< jau::cow_vector<DataType01, std::allocator<DataType01>>, std::size_t>("COW_Vector_empty_itr", "cowstdvec_empty_", false);
389
390 benchmark_fillunique_find_hash("HashSet_NoOrdr_rserv", "hash__set_empty_", true);
391 benchmark_fillunique_find_itr< std::vector<DataType01, std::allocator<DataType01>>, std::size_t>("STD_Vector_rserv_itr", "stdvec_rserv", true);
393 benchmark_fillunique_find_itr< jau::cow_vector<DataType01, std::allocator<DataType01>>, std::size_t>("COW_Vector_rserv_itr", "cowstdvec_rserv", true);
395
396}
int nop() const noexcept
#define jau_printf(fmt,...)
Definition debug.hpp:253
const T::value_type * find_const(T &data, typename T::value_type const &elem, std::enable_if_t< is_cow_type< T >::value, bool >=true) noexcept
constexpr UnaryFunction for_each_const(T &data, UnaryFunction f, std::enable_if_t< is_cow_type< T >::value, bool >=true) noexcept
uint_bytes_t< sizeof(unsigned long int)> nsize_t
Natural 'size_t' alternative using uint<XX>_t with xx = sizeof(unsigned long int)*8 as its natural si...
Definition int_types.hpp:89
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition backtrace.hpp:32
bool next() noexcept
Performance counter std::allocator specialization.
static bool benchmark_fillunique_find_itr(const std::string &title_pre, const std::string &type_id, const bool do_rserv)
static uint8_t start_addr_b[]
static bool footprint_fillseq_list_itr(const std::string &type_id, const bool do_rserv)
static Addr48Bit start_addr(start_addr_b)
static bool footprint_fillseq_list_hash(const std::string &type_id, const bool do_rserv)
static bool test_02_seq_fillunique_find_itr(const std::string &type_id, const Size_type size0, const Size_type reserve0)
static void print_mem(const std::string &pre, const T &data)
static bool test_02_seq_fillunique_find_hash(const std::string &type_id, const std::size_t size0, const std::size_t reserve0)
static bool benchmark_fillunique_find_hash(const std::string &title_pre, const std::string &type_id, const bool do_rserv)
static void test_00_seq_fill(T &data, const Size_type size)
static void test_00_seq_find_hash(T &data)
static bool benchmark_fillunique_find_itr(const std::string &title_pre, const std::string &type_id, const bool do_rserv)
static bool test_01_seq_fill_list_hash(const std::string &type_id, const std::size_t size0, const std::size_t reserve0, const bool do_print_mem)
static bool footprint_fillseq_list_itr(const std::string &type_id, const bool do_rserv)
static const DataType01 * findDataSet01_hash(T &data, DataType01 const &elem) noexcept
static void test_00_seq_fill_unique_hash(T &data, const std::size_t size)
static std::size_t get_capacity(const T &data)
static bool test_01_seq_fill_list_itr(const std::string &type_id, const Size_type size0, const Size_type reserve0, const bool do_print_mem)
static void test_00_seq_find_itr(T &data)
static Addr48Bit start_addr(start_addr_b)
static void test_00_seq_fill_unique_itr(T &data, const Size_type size)
static int test_00_list_itr(T &data)
TEST_CASE("Memory Footprint 01 - Fill Sequential and List", "[datatype][footprint]")