151c0b2f7Stbbdev /*
2b15aabb3Stbbdev Copyright (c) 2005-2021 Intel Corporation
351c0b2f7Stbbdev
451c0b2f7Stbbdev Licensed under the Apache License, Version 2.0 (the "License");
551c0b2f7Stbbdev you may not use this file except in compliance with the License.
651c0b2f7Stbbdev You may obtain a copy of the License at
751c0b2f7Stbbdev
851c0b2f7Stbbdev http://www.apache.org/licenses/LICENSE-2.0
951c0b2f7Stbbdev
1051c0b2f7Stbbdev Unless required by applicable law or agreed to in writing, software
1151c0b2f7Stbbdev distributed under the License is distributed on an "AS IS" BASIS,
1251c0b2f7Stbbdev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351c0b2f7Stbbdev See the License for the specific language governing permissions and
1451c0b2f7Stbbdev limitations under the License.
1551c0b2f7Stbbdev */
1651c0b2f7Stbbdev
1751c0b2f7Stbbdev #include "common/test.h"
1851c0b2f7Stbbdev #include "common/utils.h"
1951c0b2f7Stbbdev #include "common/utils_report.h"
2051c0b2f7Stbbdev #include "common/checktype.h"
2151c0b2f7Stbbdev
2249e08aacStbbdev #include "oneapi/tbb/detail/_utils.h"
2351c0b2f7Stbbdev
2451c0b2f7Stbbdev #include "tbb/enumerable_thread_specific.h"
2551c0b2f7Stbbdev #include "tbb/parallel_for.h"
2651c0b2f7Stbbdev #include "tbb/blocked_range.h"
2751c0b2f7Stbbdev #include "tbb/tbb_allocator.h"
2851c0b2f7Stbbdev #include "tbb/global_control.h"
2951c0b2f7Stbbdev #include "tbb/cache_aligned_allocator.h"
3051c0b2f7Stbbdev
3151c0b2f7Stbbdev #include <cstring>
3251c0b2f7Stbbdev #include <cstdio>
3351c0b2f7Stbbdev #include <vector>
3451c0b2f7Stbbdev #include <deque>
3551c0b2f7Stbbdev #include <list>
3651c0b2f7Stbbdev #include <map>
3751c0b2f7Stbbdev #include <utility>
3851c0b2f7Stbbdev #include <atomic>
3951c0b2f7Stbbdev
4051c0b2f7Stbbdev //! \file test_enumerable_thread_specific.cpp
4151c0b2f7Stbbdev //! \brief Test for [tls.enumerable_thread_specific] specification
4251c0b2f7Stbbdev
4351c0b2f7Stbbdev //! Minimum number of threads
4451c0b2f7Stbbdev static int MinThread = 1;
4551c0b2f7Stbbdev
4651c0b2f7Stbbdev //! Maximum number of threads
4751c0b2f7Stbbdev static int MaxThread = 4;
4851c0b2f7Stbbdev
4951c0b2f7Stbbdev static std::atomic<int> construction_counter;
5051c0b2f7Stbbdev static std::atomic<int> destruction_counter;
5151c0b2f7Stbbdev
5251c0b2f7Stbbdev const int VALID_NUMBER_OF_KEYS = 100;
5351c0b2f7Stbbdev
5451c0b2f7Stbbdev //! A minimal class that occupies N bytes.
5551c0b2f7Stbbdev /** Defines default and copy constructor, and allows implicit operator&. Hides operator=. */
5651c0b2f7Stbbdev template<size_t N = tbb::detail::max_nfs_size>
57*90b0671bSAlex class minimalN: utils::NoAssign {
5851c0b2f7Stbbdev private:
5951c0b2f7Stbbdev int my_value;
6051c0b2f7Stbbdev bool is_constructed;
6151c0b2f7Stbbdev char pad[N-sizeof(int) - sizeof(bool)];
6251c0b2f7Stbbdev public:
minimalN()63*90b0671bSAlex minimalN() : utils::NoAssign(), my_value(0) { ++construction_counter; is_constructed = true; }
minimalN(const minimalN & m)64*90b0671bSAlex minimalN( const minimalN&m ) : utils::NoAssign(), my_value(m.my_value) { ++construction_counter; is_constructed = true; }
~minimalN()65*90b0671bSAlex ~minimalN() { ++destruction_counter; REQUIRE(is_constructed); is_constructed = false; }
set_value(const int i)6651c0b2f7Stbbdev void set_value( const int i ) { REQUIRE(is_constructed); my_value = i; }
value() const6751c0b2f7Stbbdev int value( ) const { REQUIRE(is_constructed); return my_value; }
6851c0b2f7Stbbdev };
6951c0b2f7Stbbdev
7051c0b2f7Stbbdev static size_t AlignMask = 0; // set to cache-line-size - 1
7151c0b2f7Stbbdev
7251c0b2f7Stbbdev template<typename T>
check_alignment(T & t,const char * aname)7351c0b2f7Stbbdev T& check_alignment(T& t, const char *aname) {
7451c0b2f7Stbbdev if( !tbb::detail::is_aligned(&t, AlignMask)) {
7551c0b2f7Stbbdev // TBB_REVAMP_TODO: previously was REPORT_ONCE
7651c0b2f7Stbbdev REPORT("alignment error with %s allocator (%x)\n", aname, (int)size_t(&t) & (AlignMask-1));
7751c0b2f7Stbbdev }
7851c0b2f7Stbbdev return t;
7951c0b2f7Stbbdev }
8051c0b2f7Stbbdev
8151c0b2f7Stbbdev template<typename T>
check_alignment(const T & t,const char * aname)8251c0b2f7Stbbdev const T& check_alignment(const T& t, const char *aname) {
8351c0b2f7Stbbdev if( !tbb::detail::is_aligned(&t, AlignMask)) {
8451c0b2f7Stbbdev // TBB_REVAMP_TODO: previously was REPORT_ONCE
8551c0b2f7Stbbdev REPORT("alignment error with %s allocator (%x)\n", aname, (int)size_t(&t) & (AlignMask-1));
8651c0b2f7Stbbdev }
8751c0b2f7Stbbdev return t;
8851c0b2f7Stbbdev }
8951c0b2f7Stbbdev
9051c0b2f7Stbbdev //
91*90b0671bSAlex // A helper class that simplifies writing the tests since minimalN does not
9251c0b2f7Stbbdev // define = or + operators.
9351c0b2f7Stbbdev //
9451c0b2f7Stbbdev
9551c0b2f7Stbbdev const size_t line_size = tbb::detail::max_nfs_size;
9651c0b2f7Stbbdev
97*90b0671bSAlex typedef tbb::enumerable_thread_specific<minimalN<line_size> > flogged_ets;
9851c0b2f7Stbbdev
9951c0b2f7Stbbdev class set_body {
10051c0b2f7Stbbdev flogged_ets *a;
10151c0b2f7Stbbdev
10251c0b2f7Stbbdev public:
set_body(flogged_ets * _a)10351c0b2f7Stbbdev set_body( flogged_ets*_a ) : a(_a) { }
10451c0b2f7Stbbdev
operator ()() const10551c0b2f7Stbbdev void operator() ( ) const {
10651c0b2f7Stbbdev for (int i = 0; i < VALID_NUMBER_OF_KEYS; ++i) {
10751c0b2f7Stbbdev check_alignment(a[i].local(), "default").set_value(i + 1);
10851c0b2f7Stbbdev }
10951c0b2f7Stbbdev }
11051c0b2f7Stbbdev
11151c0b2f7Stbbdev };
11251c0b2f7Stbbdev
do_std_threads(int max_threads,flogged_ets a[])11351c0b2f7Stbbdev void do_std_threads( int max_threads, flogged_ets a[] ) {
11451c0b2f7Stbbdev std::vector< std::thread * > threads;
11551c0b2f7Stbbdev
11651c0b2f7Stbbdev for (int p = 0; p < max_threads; ++p) {
11751c0b2f7Stbbdev threads.push_back( new std::thread ( set_body( a ) ) );
11851c0b2f7Stbbdev }
11951c0b2f7Stbbdev
12051c0b2f7Stbbdev for (int p = 0; p < max_threads; ++p) {
12151c0b2f7Stbbdev threads[p]->join();
12251c0b2f7Stbbdev }
12351c0b2f7Stbbdev
12451c0b2f7Stbbdev for(int p = 0; p < max_threads; ++p) {
12551c0b2f7Stbbdev delete threads[p];
12651c0b2f7Stbbdev }
12751c0b2f7Stbbdev }
12851c0b2f7Stbbdev
flog_key_creation_and_deletion()12951c0b2f7Stbbdev void flog_key_creation_and_deletion() {
13051c0b2f7Stbbdev const int FLOG_REPETITIONS = 100;
13151c0b2f7Stbbdev
13251c0b2f7Stbbdev for (int p = MinThread; p <= MaxThread; ++p) {
13351c0b2f7Stbbdev for (int j = 0; j < FLOG_REPETITIONS; ++j) {
13451c0b2f7Stbbdev construction_counter = 0;
13551c0b2f7Stbbdev destruction_counter = 0;
13651c0b2f7Stbbdev // causes VALID_NUMBER_OF_KEYS exemplar instances to be constructed
13751c0b2f7Stbbdev flogged_ets* a = new flogged_ets[VALID_NUMBER_OF_KEYS];
13851c0b2f7Stbbdev REQUIRE(int(construction_counter) == 0); // no exemplars or actual locals have been constructed
13951c0b2f7Stbbdev REQUIRE(int(destruction_counter) == 0); // and none have been destroyed
14051c0b2f7Stbbdev // causes p * VALID_NUMBER_OF_KEYS minimals to be created
14151c0b2f7Stbbdev do_std_threads(p, a);
14251c0b2f7Stbbdev for (int i = 0; i < VALID_NUMBER_OF_KEYS; ++i) {
14351c0b2f7Stbbdev int pcnt = 0;
14451c0b2f7Stbbdev for ( flogged_ets::iterator tli = a[i].begin(); tli != a[i].end(); ++tli ) {
14551c0b2f7Stbbdev REQUIRE( (*tli).value() == i+1 );
14651c0b2f7Stbbdev ++pcnt;
14751c0b2f7Stbbdev }
14851c0b2f7Stbbdev REQUIRE( pcnt == p); // should be one local per thread.
14951c0b2f7Stbbdev }
15051c0b2f7Stbbdev delete[] a;
15151c0b2f7Stbbdev }
15251c0b2f7Stbbdev REQUIRE( int(construction_counter) == (p)*VALID_NUMBER_OF_KEYS );
15351c0b2f7Stbbdev REQUIRE( int(destruction_counter) == (p)*VALID_NUMBER_OF_KEYS );
15451c0b2f7Stbbdev
15551c0b2f7Stbbdev construction_counter = 0;
15651c0b2f7Stbbdev destruction_counter = 0;
15751c0b2f7Stbbdev
15851c0b2f7Stbbdev // causes VALID_NUMBER_OF_KEYS exemplar instances to be constructed
15951c0b2f7Stbbdev flogged_ets* a = new flogged_ets[VALID_NUMBER_OF_KEYS];
16051c0b2f7Stbbdev
16151c0b2f7Stbbdev for (int j = 0; j < FLOG_REPETITIONS; ++j) {
16251c0b2f7Stbbdev // causes p * VALID_NUMBER_OF_KEYS minimals to be created
16351c0b2f7Stbbdev do_std_threads(p, a);
16451c0b2f7Stbbdev
16551c0b2f7Stbbdev for (int i = 0; i < VALID_NUMBER_OF_KEYS; ++i) {
16651c0b2f7Stbbdev for ( flogged_ets::iterator tli = a[i].begin(); tli != a[i].end(); ++tli ) {
16751c0b2f7Stbbdev REQUIRE( (*tli).value() == i+1 );
16851c0b2f7Stbbdev }
16951c0b2f7Stbbdev a[i].clear();
17051c0b2f7Stbbdev REQUIRE( static_cast<int>(a[i].end() - a[i].begin()) == 0 );
17151c0b2f7Stbbdev }
17251c0b2f7Stbbdev }
17351c0b2f7Stbbdev delete[] a;
17451c0b2f7Stbbdev REQUIRE( int(construction_counter) == (FLOG_REPETITIONS*p)*VALID_NUMBER_OF_KEYS );
17551c0b2f7Stbbdev REQUIRE( int(destruction_counter) == (FLOG_REPETITIONS*p)*VALID_NUMBER_OF_KEYS );
17651c0b2f7Stbbdev }
17751c0b2f7Stbbdev
17851c0b2f7Stbbdev }
17951c0b2f7Stbbdev
18051c0b2f7Stbbdev template <typename inner_container>
flog_segmented_interator()18151c0b2f7Stbbdev void flog_segmented_interator() {
18251c0b2f7Stbbdev
18351c0b2f7Stbbdev bool found_error = false;
18451c0b2f7Stbbdev typedef typename inner_container::value_type T;
18551c0b2f7Stbbdev typedef std::vector< inner_container > nested_vec;
18651c0b2f7Stbbdev inner_container my_inner_container;
18751c0b2f7Stbbdev my_inner_container.clear();
18851c0b2f7Stbbdev nested_vec my_vec;
18951c0b2f7Stbbdev
19051c0b2f7Stbbdev // simple nested vector (neither level empty)
19151c0b2f7Stbbdev const int maxval = 10;
19251c0b2f7Stbbdev for(int i=0; i < maxval; i++) {
19351c0b2f7Stbbdev my_vec.push_back(my_inner_container);
19451c0b2f7Stbbdev for(int j = 0; j < maxval; j++) {
19551c0b2f7Stbbdev my_vec.at(i).push_back((T)(maxval * i + j));
19651c0b2f7Stbbdev }
19751c0b2f7Stbbdev }
19851c0b2f7Stbbdev
19951c0b2f7Stbbdev tbb::detail::d1::segmented_iterator<nested_vec, T> my_si(my_vec);
20051c0b2f7Stbbdev
20151c0b2f7Stbbdev T ii;
20251c0b2f7Stbbdev for(my_si=my_vec.begin(), ii=0; my_si != my_vec.end(); ++my_si, ++ii) {
20351c0b2f7Stbbdev if((*my_si) != ii) {
20451c0b2f7Stbbdev found_error = true;
20551c0b2f7Stbbdev }
20651c0b2f7Stbbdev }
20751c0b2f7Stbbdev
20851c0b2f7Stbbdev // outer level empty
20951c0b2f7Stbbdev my_vec.clear();
21051c0b2f7Stbbdev for(my_si=my_vec.begin(); my_si != my_vec.end(); ++my_si) {
21151c0b2f7Stbbdev found_error = true;
21251c0b2f7Stbbdev }
21351c0b2f7Stbbdev
21451c0b2f7Stbbdev // inner levels empty
21551c0b2f7Stbbdev my_vec.clear();
21651c0b2f7Stbbdev for(int i =0; i < maxval; ++i) {
21751c0b2f7Stbbdev my_vec.push_back(my_inner_container);
21851c0b2f7Stbbdev }
21951c0b2f7Stbbdev for(my_si = my_vec.begin(); my_si != my_vec.end(); ++my_si) {
22051c0b2f7Stbbdev found_error = true;
22151c0b2f7Stbbdev }
22251c0b2f7Stbbdev
22351c0b2f7Stbbdev // every other inner container is empty
22451c0b2f7Stbbdev my_vec.clear();
22551c0b2f7Stbbdev for(int i=0; i < maxval; ++i) {
22651c0b2f7Stbbdev my_vec.push_back(my_inner_container);
22751c0b2f7Stbbdev if(i%2) {
22851c0b2f7Stbbdev for(int j = 0; j < maxval; ++j) {
22951c0b2f7Stbbdev my_vec.at(i).push_back((T)(maxval * (i/2) + j));
23051c0b2f7Stbbdev }
23151c0b2f7Stbbdev }
23251c0b2f7Stbbdev }
23351c0b2f7Stbbdev for(my_si = my_vec.begin(), ii=0; my_si != my_vec.end(); ++my_si, ++ii) {
23451c0b2f7Stbbdev if((*my_si) != ii) {
23551c0b2f7Stbbdev found_error = true;
23651c0b2f7Stbbdev }
23751c0b2f7Stbbdev }
23851c0b2f7Stbbdev
23951c0b2f7Stbbdev tbb::detail::d1::segmented_iterator<nested_vec, const T> my_csi(my_vec);
24051c0b2f7Stbbdev for(my_csi=my_vec.begin(), ii=0; my_csi != my_vec.end(); ++my_csi, ++ii) {
24151c0b2f7Stbbdev if((*my_csi) != ii) {
24251c0b2f7Stbbdev found_error = true;
24351c0b2f7Stbbdev }
24451c0b2f7Stbbdev }
24551c0b2f7Stbbdev
24651c0b2f7Stbbdev // outer level empty
24751c0b2f7Stbbdev my_vec.clear();
24851c0b2f7Stbbdev for(my_csi=my_vec.begin(); my_csi != my_vec.end(); ++my_csi) {
24951c0b2f7Stbbdev found_error = true;
25051c0b2f7Stbbdev }
25151c0b2f7Stbbdev
25251c0b2f7Stbbdev // inner levels empty
25351c0b2f7Stbbdev my_vec.clear();
25451c0b2f7Stbbdev for(int i =0; i < maxval; ++i) {
25551c0b2f7Stbbdev my_vec.push_back(my_inner_container);
25651c0b2f7Stbbdev }
25751c0b2f7Stbbdev for(my_csi = my_vec.begin(); my_csi != my_vec.end(); ++my_csi) {
25851c0b2f7Stbbdev found_error = true;
25951c0b2f7Stbbdev }
26051c0b2f7Stbbdev
26151c0b2f7Stbbdev // every other inner container is empty
26251c0b2f7Stbbdev my_vec.clear();
26351c0b2f7Stbbdev for(int i=0; i < maxval; ++i) {
26451c0b2f7Stbbdev my_vec.push_back(my_inner_container);
26551c0b2f7Stbbdev if(i%2) {
26651c0b2f7Stbbdev for(int j = 0; j < maxval; ++j) {
26751c0b2f7Stbbdev my_vec.at(i).push_back((T)(maxval * (i/2) + j));
26851c0b2f7Stbbdev }
26951c0b2f7Stbbdev }
27051c0b2f7Stbbdev }
27151c0b2f7Stbbdev for(my_csi = my_vec.begin(), ii=0; my_csi != my_vec.end(); ++my_csi, ++ii) {
27251c0b2f7Stbbdev if((*my_csi) != ii) {
27351c0b2f7Stbbdev found_error = true;
27451c0b2f7Stbbdev }
27551c0b2f7Stbbdev }
27651c0b2f7Stbbdev
27751c0b2f7Stbbdev
27851c0b2f7Stbbdev if(found_error) REPORT("segmented_iterator failed\n");
27951c0b2f7Stbbdev }
28051c0b2f7Stbbdev
28151c0b2f7Stbbdev template <typename Key, typename Val>
flog_segmented_iterator_map()28251c0b2f7Stbbdev void flog_segmented_iterator_map() {
28351c0b2f7Stbbdev typedef typename std::map<Key, Val> my_map;
28451c0b2f7Stbbdev typedef std::vector< my_map > nested_vec;
28551c0b2f7Stbbdev my_map my_inner_container;
28651c0b2f7Stbbdev my_inner_container.clear();
28751c0b2f7Stbbdev nested_vec my_vec;
28851c0b2f7Stbbdev my_vec.clear();
28951c0b2f7Stbbdev bool found_error = false;
29051c0b2f7Stbbdev
29151c0b2f7Stbbdev // simple nested vector (neither level empty)
29251c0b2f7Stbbdev const int maxval = 4;
29351c0b2f7Stbbdev for(int i=0; i < maxval; i++) {
29451c0b2f7Stbbdev my_vec.push_back(my_inner_container);
29551c0b2f7Stbbdev for(int j = 0; j < maxval; j++) {
29651c0b2f7Stbbdev my_vec.at(i).insert(std::make_pair<Key,Val>(maxval * i + j, 2*(maxval*i + j)));
29751c0b2f7Stbbdev }
29851c0b2f7Stbbdev }
29951c0b2f7Stbbdev
30051c0b2f7Stbbdev tbb::detail::d1::segmented_iterator<nested_vec, std::pair<const Key, Val> > my_si(my_vec);
30151c0b2f7Stbbdev Key ii;
30251c0b2f7Stbbdev for(my_si=my_vec.begin(), ii=0; my_si != my_vec.end(); ++my_si, ++ii) {
30351c0b2f7Stbbdev if(((*my_si).first != ii) || ((*my_si).second != 2*ii)) {
30451c0b2f7Stbbdev found_error = true;
30551c0b2f7Stbbdev }
30651c0b2f7Stbbdev }
30751c0b2f7Stbbdev
30851c0b2f7Stbbdev tbb::detail::d1::segmented_iterator<nested_vec, const std::pair<const Key, Val> > my_csi(my_vec);
30951c0b2f7Stbbdev for(my_csi=my_vec.begin(), ii=0; my_csi != my_vec.end(); ++my_csi, ++ii) {
31051c0b2f7Stbbdev if(((*my_csi).first != ii) || ((*my_csi).second != 2*ii)) {
31151c0b2f7Stbbdev found_error = true;
31251c0b2f7Stbbdev // INFO( "ii=%d, (*my_csi).first=%d, second=%d\n",ii, int((*my_csi).first), int((*my_csi).second));
31351c0b2f7Stbbdev }
31451c0b2f7Stbbdev }
31551c0b2f7Stbbdev if(found_error) REPORT("segmented_iterator_map failed\n");
31651c0b2f7Stbbdev }
31751c0b2f7Stbbdev
run_segmented_iterator_tests()31851c0b2f7Stbbdev void run_segmented_iterator_tests() {
31951c0b2f7Stbbdev // only the following containers can be used with the segmented iterator.
32051c0b2f7Stbbdev flog_segmented_interator<std::vector< int > >();
32151c0b2f7Stbbdev flog_segmented_interator<std::vector< double > >();
32251c0b2f7Stbbdev flog_segmented_interator<std::deque< int > >();
32351c0b2f7Stbbdev flog_segmented_interator<std::deque< double > >();
32451c0b2f7Stbbdev flog_segmented_interator<std::list< int > >();
32551c0b2f7Stbbdev flog_segmented_interator<std::list< double > >();
32651c0b2f7Stbbdev
32751c0b2f7Stbbdev flog_segmented_iterator_map<int, int>();
32851c0b2f7Stbbdev flog_segmented_iterator_map<int, double>();
32951c0b2f7Stbbdev }
33051c0b2f7Stbbdev
align_val(void * const p)33151c0b2f7Stbbdev int align_val(void * const p) {
33251c0b2f7Stbbdev size_t tmp = (size_t)p;
33351c0b2f7Stbbdev int a = 1;
33451c0b2f7Stbbdev while((tmp&0x1) == 0) { a <<=1; tmp >>= 1; }
33551c0b2f7Stbbdev return a;
33651c0b2f7Stbbdev }
33751c0b2f7Stbbdev
is_between(void * lowp,void * highp,void * testp)33851c0b2f7Stbbdev bool is_between(void* lowp, void *highp, void *testp) {
33951c0b2f7Stbbdev if((size_t)lowp < (size_t)testp && (size_t)testp < (size_t)highp) return true;
34051c0b2f7Stbbdev return (size_t)lowp > (size_t)testp && (size_t)testp > (size_t)highp;
34151c0b2f7Stbbdev }
34251c0b2f7Stbbdev
34351c0b2f7Stbbdev template<class U> struct alignment_of {
34451c0b2f7Stbbdev typedef struct { char t; U padded; } test_alignment;
34551c0b2f7Stbbdev static const size_t value = sizeof(test_alignment) - sizeof(U);
34651c0b2f7Stbbdev };
34751c0b2f7Stbbdev using tbb::detail::d1::ets_element;
34851c0b2f7Stbbdev template<typename T, typename OtherType>
allocate_ets_element_on_stack(const char *)34951c0b2f7Stbbdev void allocate_ets_element_on_stack(const char* /* name */) {
35051c0b2f7Stbbdev typedef T aligning_element_type;
35151c0b2f7Stbbdev const size_t my_align = alignment_of<aligning_element_type>::value;
35251c0b2f7Stbbdev OtherType c1;
35351c0b2f7Stbbdev ets_element<aligning_element_type> my_stack_element;
35451c0b2f7Stbbdev OtherType c2;
35551c0b2f7Stbbdev ets_element<aligning_element_type> my_stack_element2;
35651c0b2f7Stbbdev struct {
35751c0b2f7Stbbdev OtherType cxx;
35851c0b2f7Stbbdev ets_element<aligning_element_type> my_struct_element;
35951c0b2f7Stbbdev } mystruct1;
36051c0b2f7Stbbdev tbb::detail::suppress_unused_warning(c1,c2);
36151c0b2f7Stbbdev REQUIRE_MESSAGE(tbb::detail::is_aligned(my_stack_element.value(), my_align), "Error in first stack alignment" );
36251c0b2f7Stbbdev REQUIRE_MESSAGE(tbb::detail::is_aligned(my_stack_element2.value(), my_align), "Error in second stack alignment" );
36351c0b2f7Stbbdev REQUIRE_MESSAGE(tbb::detail::is_aligned(mystruct1.my_struct_element.value(), my_align), "Error in struct element alignment" );
36451c0b2f7Stbbdev }
36551c0b2f7Stbbdev
36651c0b2f7Stbbdev class BigType {
36751c0b2f7Stbbdev public:
BigType()36851c0b2f7Stbbdev BigType() { /* avoid cl warning C4345 about default initialization of POD types */ }
36951c0b2f7Stbbdev char my_data[12 * 1024 * 1024];
37051c0b2f7Stbbdev };
37151c0b2f7Stbbdev
37251c0b2f7Stbbdev template<template<class> class Allocator>
TestConstructorWithBigType(const char * allocator_name)37351c0b2f7Stbbdev void TestConstructorWithBigType(const char* allocator_name) {
37451c0b2f7Stbbdev typedef tbb::enumerable_thread_specific<BigType, Allocator<BigType> > CounterBigType;
37551c0b2f7Stbbdev // Test default constructor
37651c0b2f7Stbbdev CounterBigType MyCounters;
37751c0b2f7Stbbdev // Create a local instance.
37851c0b2f7Stbbdev typename CounterBigType::reference my_local = MyCounters.local();
37951c0b2f7Stbbdev my_local.my_data[0] = 'a';
38051c0b2f7Stbbdev // Test copy constructor
38151c0b2f7Stbbdev CounterBigType MyCounters2(MyCounters);
38251c0b2f7Stbbdev REQUIRE(check_alignment(MyCounters2.local(), allocator_name).my_data[0]=='a');
38351c0b2f7Stbbdev }
38451c0b2f7Stbbdev
init_tbb_alloc_mask()38551c0b2f7Stbbdev size_t init_tbb_alloc_mask() {
38651c0b2f7Stbbdev // TODO: use __TBB_alignof(T) to check for local() results instead of using internal knowledges of ets element padding
38751c0b2f7Stbbdev if(tbb::tbb_allocator<int>::allocator_type() == tbb::tbb_allocator<int>::standard) {
38851c0b2f7Stbbdev // scalable allocator is not available.
38951c0b2f7Stbbdev // INFO("tbb::tbb_allocator is not available\n");
39051c0b2f7Stbbdev return 1;
39151c0b2f7Stbbdev }
39251c0b2f7Stbbdev else {
39351c0b2f7Stbbdev // this value is for large objects, but will be correct for small.
39451c0b2f7Stbbdev return 64; // TBB_REVAMP_TODO: enable as estimatedCacheLineSize when tbbmalloc is available;
39551c0b2f7Stbbdev }
39651c0b2f7Stbbdev }
39751c0b2f7Stbbdev
39851c0b2f7Stbbdev static const size_t cache_allocator_mask = tbb::detail::r1::cache_line_size();
39951c0b2f7Stbbdev static const size_t tbb_allocator_mask = init_tbb_alloc_mask();
40051c0b2f7Stbbdev
40151c0b2f7Stbbdev //! Test for internal segmented_iterator type, used inside flattened2d class
40251c0b2f7Stbbdev //! \brief \ref error_guessing
40351c0b2f7Stbbdev TEST_CASE("Segmented iterator") {
40451c0b2f7Stbbdev AlignMask = tbb_allocator_mask;
40551c0b2f7Stbbdev run_segmented_iterator_tests();
40651c0b2f7Stbbdev }
40751c0b2f7Stbbdev
40851c0b2f7Stbbdev //! Test ETS keys creation/deletion
40951c0b2f7Stbbdev //! \brief \ref error_guessing \ref boundary
41051c0b2f7Stbbdev TEST_CASE("Key creation and deletion") {
41151c0b2f7Stbbdev AlignMask = tbb_allocator_mask;
41251c0b2f7Stbbdev flog_key_creation_and_deletion();
41351c0b2f7Stbbdev }
41451c0b2f7Stbbdev
41551c0b2f7Stbbdev //! Test construction with big ETS types
41651c0b2f7Stbbdev //! \brief \ref error_guessing
41751c0b2f7Stbbdev TEST_CASE("Constructor with big type") {
41851c0b2f7Stbbdev AlignMask = cache_allocator_mask;
41951c0b2f7Stbbdev TestConstructorWithBigType<tbb::cache_aligned_allocator>("tbb::cache_aligned_allocator");
42051c0b2f7Stbbdev AlignMask = tbb_allocator_mask;
42151c0b2f7Stbbdev TestConstructorWithBigType<tbb::tbb_allocator>("tbb::tbb_allocator");
42251c0b2f7Stbbdev }
42351c0b2f7Stbbdev
42451c0b2f7Stbbdev //! Test allocation of ETS elements on the stack (internal types)
42551c0b2f7Stbbdev //! \brief \ref error_guessing
42651c0b2f7Stbbdev TEST_CASE("Allocate ETS on stack") {
42751c0b2f7Stbbdev AlignMask = tbb_allocator_mask;
42851c0b2f7Stbbdev allocate_ets_element_on_stack<int,char>("int vs. char");
42951c0b2f7Stbbdev allocate_ets_element_on_stack<int,short>("int vs. short");
43051c0b2f7Stbbdev allocate_ets_element_on_stack<int,char[3]>("int vs. char[3]");
43151c0b2f7Stbbdev allocate_ets_element_on_stack<float,char>("float vs. char");
43251c0b2f7Stbbdev allocate_ets_element_on_stack<float,short>("float vs. short");
43351c0b2f7Stbbdev allocate_ets_element_on_stack<float,char[3]>("float vs. char[3]");
43451c0b2f7Stbbdev }
43551c0b2f7Stbbdev
436