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