1*d86ed7fbStbbdev /*
2*d86ed7fbStbbdev     Copyright (c) 2005-2020 Intel Corporation
3*d86ed7fbStbbdev 
4*d86ed7fbStbbdev     Licensed under the Apache License, Version 2.0 (the "License");
5*d86ed7fbStbbdev     you may not use this file except in compliance with the License.
6*d86ed7fbStbbdev     You may obtain a copy of the License at
7*d86ed7fbStbbdev 
8*d86ed7fbStbbdev         http://www.apache.org/licenses/LICENSE-2.0
9*d86ed7fbStbbdev 
10*d86ed7fbStbbdev     Unless required by applicable law or agreed to in writing, software
11*d86ed7fbStbbdev     distributed under the License is distributed on an "AS IS" BASIS,
12*d86ed7fbStbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d86ed7fbStbbdev     See the License for the specific language governing permissions and
14*d86ed7fbStbbdev     limitations under the License.
15*d86ed7fbStbbdev */
16*d86ed7fbStbbdev 
17*d86ed7fbStbbdev #include <cstring>
18*d86ed7fbStbbdev #include <cctype>
19*d86ed7fbStbbdev #include <cstdlib>
20*d86ed7fbStbbdev #include <cstdio>
21*d86ed7fbStbbdev 
22*d86ed7fbStbbdev #include <string>
23*d86ed7fbStbbdev 
24*d86ed7fbStbbdev // Apple clang and MSVC defines their own specializations for std::hash<std::basic_string<T, Traits, Alloc>>
25*d86ed7fbStbbdev #if !(_LIBCPP_VERSION) && !(_CPPLIB_VER)
26*d86ed7fbStbbdev 
27*d86ed7fbStbbdev namespace std {
28*d86ed7fbStbbdev 
29*d86ed7fbStbbdev template <typename CharT, typename Traits, typename Allocator>
30*d86ed7fbStbbdev class hash<std::basic_string<CharT, Traits, Allocator>> {
31*d86ed7fbStbbdev public:
32*d86ed7fbStbbdev     std::size_t operator()(const std::basic_string<CharT, Traits, Allocator>& s) const {
33*d86ed7fbStbbdev         std::size_t h = 0;
34*d86ed7fbStbbdev         for (const CharT* c = s.c_str(); *c; ++c) {
35*d86ed7fbStbbdev             h = h * hash_multiplier ^ char_hash(*c);
36*d86ed7fbStbbdev         }
37*d86ed7fbStbbdev         return h;
38*d86ed7fbStbbdev     }
39*d86ed7fbStbbdev 
40*d86ed7fbStbbdev private:
41*d86ed7fbStbbdev     static constexpr std::size_t hash_multiplier = (std::size_t)(
42*d86ed7fbStbbdev         (sizeof(std::size_t) == sizeof(unsigned)) ? 2654435769U : 11400714819323198485ULL);
43*d86ed7fbStbbdev 
44*d86ed7fbStbbdev     std::hash<CharT> char_hash;
45*d86ed7fbStbbdev }; // strunt hash<std::basic_string>
46*d86ed7fbStbbdev 
47*d86ed7fbStbbdev } // namespace std
48*d86ed7fbStbbdev 
49*d86ed7fbStbbdev #endif // !(_LIBCPP_VERSION || _CPPLIB_VER)
50*d86ed7fbStbbdev 
51*d86ed7fbStbbdev #include "oneapi/tbb/concurrent_hash_map.h"
52*d86ed7fbStbbdev #include "oneapi/tbb/blocked_range.h"
53*d86ed7fbStbbdev #include "oneapi/tbb/parallel_for.h"
54*d86ed7fbStbbdev #include "oneapi/tbb/tick_count.h"
55*d86ed7fbStbbdev #include "oneapi/tbb/tbb_allocator.h"
56*d86ed7fbStbbdev #include "oneapi/tbb/global_control.h"
57*d86ed7fbStbbdev 
58*d86ed7fbStbbdev #include "common/utility/utility.hpp"
59*d86ed7fbStbbdev #include "common/utility/get_default_num_threads.hpp"
60*d86ed7fbStbbdev 
61*d86ed7fbStbbdev #include <map>
62*d86ed7fbStbbdev 
63*d86ed7fbStbbdev //! Count collisions
64*d86ed7fbStbbdev std::map<std::size_t, int> hashes;
65*d86ed7fbStbbdev int c = 0;
66*d86ed7fbStbbdev 
67*d86ed7fbStbbdev //! String type
68*d86ed7fbStbbdev typedef std::basic_string<char, std::char_traits<char>, oneapi::tbb::tbb_allocator<char>> MyString;
69*d86ed7fbStbbdev 
70*d86ed7fbStbbdev //! Set to true to counts.
71*d86ed7fbStbbdev static bool verbose = false;
72*d86ed7fbStbbdev static bool silent = false;
73*d86ed7fbStbbdev static bool count_collisions = false;
74*d86ed7fbStbbdev //! Problem size
75*d86ed7fbStbbdev long N = 1000000;
76*d86ed7fbStbbdev const int size_factor = 2;
77*d86ed7fbStbbdev 
78*d86ed7fbStbbdev //! A concurrent hash table that maps strings to ints.
79*d86ed7fbStbbdev typedef oneapi::tbb::concurrent_hash_map<MyString, int> StringTable;
80*d86ed7fbStbbdev 
81*d86ed7fbStbbdev //! Function object for counting occurrences of strings.
82*d86ed7fbStbbdev struct Tally {
83*d86ed7fbStbbdev     StringTable& table;
84*d86ed7fbStbbdev     Tally(StringTable& table_) : table(table_) {}
85*d86ed7fbStbbdev     void operator()(const oneapi::tbb::blocked_range<MyString*> range) const {
86*d86ed7fbStbbdev         for (MyString* p = range.begin(); p != range.end(); ++p) {
87*d86ed7fbStbbdev             StringTable::accessor a;
88*d86ed7fbStbbdev             table.insert(a, *p);
89*d86ed7fbStbbdev             a->second += 1;
90*d86ed7fbStbbdev         }
91*d86ed7fbStbbdev     }
92*d86ed7fbStbbdev };
93*d86ed7fbStbbdev 
94*d86ed7fbStbbdev static MyString* Data;
95*d86ed7fbStbbdev 
96*d86ed7fbStbbdev static void CountOccurrences(int nthreads) {
97*d86ed7fbStbbdev     StringTable table;
98*d86ed7fbStbbdev 
99*d86ed7fbStbbdev     oneapi::tbb::tick_count t0 = oneapi::tbb::tick_count::now();
100*d86ed7fbStbbdev     oneapi::tbb::parallel_for(oneapi::tbb::blocked_range<MyString*>(Data, Data + N, 1000),
101*d86ed7fbStbbdev                               Tally(table));
102*d86ed7fbStbbdev     oneapi::tbb::tick_count t1 = oneapi::tbb::tick_count::now();
103*d86ed7fbStbbdev 
104*d86ed7fbStbbdev     int n = 0;
105*d86ed7fbStbbdev     for (StringTable::iterator i = table.begin(); i != table.end(); ++i) {
106*d86ed7fbStbbdev         if (verbose && nthreads)
107*d86ed7fbStbbdev             printf("%s %d\n", i->first.c_str(), i->second);
108*d86ed7fbStbbdev         if (!silent && count_collisions) {
109*d86ed7fbStbbdev             // it doesn't count real collisions in hash_map, a mask should be applied on hash value
110*d86ed7fbStbbdev             hashes[std::hash<MyString>()(i->first) & 0xFFFF]++;
111*d86ed7fbStbbdev         }
112*d86ed7fbStbbdev         n += i->second;
113*d86ed7fbStbbdev     }
114*d86ed7fbStbbdev     if (!silent && count_collisions) {
115*d86ed7fbStbbdev         for (auto i = hashes.begin(); i != hashes.end(); ++i)
116*d86ed7fbStbbdev             c += i->second - 1;
117*d86ed7fbStbbdev         printf("hashes = %d  collisions = %d  ", hashes.size(), c);
118*d86ed7fbStbbdev         c = 0;
119*d86ed7fbStbbdev         hashes.clear();
120*d86ed7fbStbbdev     }
121*d86ed7fbStbbdev 
122*d86ed7fbStbbdev     if (!silent)
123*d86ed7fbStbbdev         printf(
124*d86ed7fbStbbdev             "total = %d  unique = %u  time = %g\n", n, unsigned(table.size()), (t1 - t0).seconds());
125*d86ed7fbStbbdev }
126*d86ed7fbStbbdev 
127*d86ed7fbStbbdev /// Generator of random words
128*d86ed7fbStbbdev 
129*d86ed7fbStbbdev struct Sound {
130*d86ed7fbStbbdev     const char* chars;
131*d86ed7fbStbbdev     int rates[3]; // beginning, middle, ending
132*d86ed7fbStbbdev };
133*d86ed7fbStbbdev Sound Vowels[] = {
134*d86ed7fbStbbdev     { "e", { 445, 6220, 1762 } }, { "a", { 704, 5262, 514 } }, { "i", { 402, 5224, 162 } },
135*d86ed7fbStbbdev     { "o", { 248, 3726, 191 } },  { "u", { 155, 1669, 23 } },  { "y", { 4, 400, 989 } },
136*d86ed7fbStbbdev     { "io", { 5, 512, 18 } },     { "ia", { 1, 329, 111 } },   { "ea", { 21, 370, 16 } },
137*d86ed7fbStbbdev     { "ou", { 32, 298, 4 } },     { "ie", { 0, 177, 140 } },   { "ee", { 2, 183, 57 } },
138*d86ed7fbStbbdev     { "ai", { 17, 206, 7 } },     { "oo", { 1, 215, 7 } },     { "au", { 40, 111, 2 } },
139*d86ed7fbStbbdev     { "ua", { 0, 102, 4 } },      { "ui", { 0, 104, 1 } },     { "ei", { 6, 94, 3 } },
140*d86ed7fbStbbdev     { "ue", { 0, 67, 28 } },      { "ay", { 1, 42, 52 } },     { "ey", { 1, 14, 80 } },
141*d86ed7fbStbbdev     { "oa", { 5, 84, 3 } },       { "oi", { 2, 81, 1 } },      { "eo", { 1, 71, 5 } },
142*d86ed7fbStbbdev     { "iou", { 0, 61, 0 } },      { "oe", { 2, 46, 9 } },      { "eu", { 12, 43, 0 } },
143*d86ed7fbStbbdev     { "iu", { 0, 45, 0 } },       { "ya", { 12, 19, 5 } },     { "ae", { 7, 18, 10 } },
144*d86ed7fbStbbdev     { "oy", { 0, 10, 13 } },      { "ye", { 8, 7, 7 } },       { "ion", { 0, 0, 20 } },
145*d86ed7fbStbbdev     { "ing", { 0, 0, 20 } },      { "ium", { 0, 0, 10 } },     { "er", { 0, 0, 20 } }
146*d86ed7fbStbbdev };
147*d86ed7fbStbbdev Sound Consonants[] = {
148*d86ed7fbStbbdev     { "r", { 483, 1414, 1110 } }, { "n", { 312, 1548, 1114 } }, { "t", { 363, 1653, 251 } },
149*d86ed7fbStbbdev     { "l", { 424, 1341, 489 } },  { "c", { 734, 735, 260 } },   { "m", { 732, 785, 161 } },
150*d86ed7fbStbbdev     { "d", { 558, 612, 389 } },   { "s", { 574, 570, 405 } },   { "p", { 519, 361, 98 } },
151*d86ed7fbStbbdev     { "b", { 528, 356, 30 } },    { "v", { 197, 598, 16 } },    { "ss", { 3, 191, 567 } },
152*d86ed7fbStbbdev     { "g", { 285, 430, 42 } },    { "st", { 142, 323, 180 } },  { "h", { 470, 89, 30 } },
153*d86ed7fbStbbdev     { "nt", { 0, 350, 231 } },    { "ng", { 0, 117, 442 } },    { "f", { 319, 194, 19 } },
154*d86ed7fbStbbdev     { "ll", { 1, 414, 83 } },     { "w", { 249, 131, 64 } },    { "k", { 154, 179, 47 } },
155*d86ed7fbStbbdev     { "nd", { 0, 279, 92 } },     { "bl", { 62, 235, 0 } },     { "z", { 35, 223, 16 } },
156*d86ed7fbStbbdev     { "sh", { 112, 69, 79 } },    { "ch", { 139, 95, 25 } },    { "th", { 70, 143, 39 } },
157*d86ed7fbStbbdev     { "tt", { 0, 219, 19 } },     { "tr", { 131, 104, 0 } },    { "pr", { 186, 41, 0 } },
158*d86ed7fbStbbdev     { "nc", { 0, 223, 2 } },      { "j", { 184, 32, 1 } },      { "nn", { 0, 188, 20 } },
159*d86ed7fbStbbdev     { "rt", { 0, 148, 51 } },     { "ct", { 0, 160, 29 } },     { "rr", { 0, 182, 3 } },
160*d86ed7fbStbbdev     { "gr", { 98, 87, 0 } },      { "ck", { 0, 92, 86 } },      { "rd", { 0, 81, 88 } },
161*d86ed7fbStbbdev     { "x", { 8, 102, 48 } },      { "ph", { 47, 101, 10 } },    { "br", { 115, 43, 0 } },
162*d86ed7fbStbbdev     { "cr", { 92, 60, 0 } },      { "rm", { 0, 131, 18 } },     { "ns", { 0, 124, 18 } },
163*d86ed7fbStbbdev     { "sp", { 81, 55, 4 } },      { "sm", { 25, 29, 85 } },     { "sc", { 53, 83, 1 } },
164*d86ed7fbStbbdev     { "rn", { 0, 100, 30 } },     { "cl", { 78, 42, 0 } },      { "mm", { 0, 116, 0 } },
165*d86ed7fbStbbdev     { "pp", { 0, 114, 2 } },      { "mp", { 0, 99, 14 } },      { "rs", { 0, 96, 16 } },
166*d86ed7fbStbbdev     { "rl", { 0, 97, 7 } },       { "rg", { 0, 81, 15 } },      { "pl", { 56, 39, 0 } },
167*d86ed7fbStbbdev     { "sn", { 32, 62, 1 } },      { "str", { 38, 56, 0 } },     { "dr", { 47, 44, 0 } },
168*d86ed7fbStbbdev     { "fl", { 77, 13, 1 } },      { "fr", { 77, 11, 0 } },      { "ld", { 0, 47, 38 } },
169*d86ed7fbStbbdev     { "ff", { 0, 62, 20 } },      { "lt", { 0, 61, 19 } },      { "rb", { 0, 75, 4 } },
170*d86ed7fbStbbdev     { "mb", { 0, 72, 7 } },       { "rc", { 0, 76, 1 } },       { "gg", { 0, 74, 1 } },
171*d86ed7fbStbbdev     { "pt", { 1, 56, 10 } },      { "bb", { 0, 64, 1 } },       { "sl", { 48, 17, 0 } },
172*d86ed7fbStbbdev     { "dd", { 0, 59, 2 } },       { "gn", { 3, 50, 4 } },       { "rk", { 0, 30, 28 } },
173*d86ed7fbStbbdev     { "nk", { 0, 35, 20 } },      { "gl", { 40, 14, 0 } },      { "wh", { 45, 6, 0 } },
174*d86ed7fbStbbdev     { "ntr", { 0, 50, 0 } },      { "rv", { 0, 47, 1 } },       { "ght", { 0, 19, 29 } },
175*d86ed7fbStbbdev     { "sk", { 23, 17, 5 } },      { "nf", { 0, 46, 0 } },       { "cc", { 0, 45, 0 } },
176*d86ed7fbStbbdev     { "ln", { 0, 41, 0 } },       { "sw", { 36, 4, 0 } },       { "rp", { 0, 36, 4 } },
177*d86ed7fbStbbdev     { "dn", { 0, 38, 0 } },       { "ps", { 14, 19, 5 } },      { "nv", { 0, 38, 0 } },
178*d86ed7fbStbbdev     { "tch", { 0, 21, 16 } },     { "nch", { 0, 26, 11 } },     { "lv", { 0, 35, 0 } },
179*d86ed7fbStbbdev     { "wn", { 0, 14, 21 } },      { "rf", { 0, 32, 3 } },       { "lm", { 0, 30, 5 } },
180*d86ed7fbStbbdev     { "dg", { 0, 34, 0 } },       { "ft", { 0, 18, 15 } },      { "scr", { 23, 10, 0 } },
181*d86ed7fbStbbdev     { "rch", { 0, 24, 6 } },      { "rth", { 0, 23, 7 } },      { "rh", { 13, 15, 0 } },
182*d86ed7fbStbbdev     { "mpl", { 0, 29, 0 } },      { "cs", { 0, 1, 27 } },       { "gh", { 4, 10, 13 } },
183*d86ed7fbStbbdev     { "ls", { 0, 23, 3 } },       { "ndr", { 0, 25, 0 } },      { "tl", { 0, 23, 1 } },
184*d86ed7fbStbbdev     { "ngl", { 0, 25, 0 } },      { "lk", { 0, 15, 9 } },       { "rw", { 0, 23, 0 } },
185*d86ed7fbStbbdev     { "lb", { 0, 23, 1 } },       { "tw", { 15, 8, 0 } },       { "chr", { 18, 4, 0 } },
186*d86ed7fbStbbdev     { "dl", { 0, 23, 0 } },       { "ctr", { 0, 22, 0 } },      { "nst", { 0, 21, 0 } },
187*d86ed7fbStbbdev     { "lc", { 0, 22, 0 } },       { "sch", { 16, 4, 0 } },      { "ths", { 0, 1, 20 } },
188*d86ed7fbStbbdev     { "nl", { 0, 21, 0 } },       { "lf", { 0, 15, 6 } },       { "ssn", { 0, 20, 0 } },
189*d86ed7fbStbbdev     { "xt", { 0, 18, 1 } },       { "xp", { 0, 20, 0 } },       { "rst", { 0, 15, 5 } },
190*d86ed7fbStbbdev     { "nh", { 0, 19, 0 } },       { "wr", { 14, 5, 0 } }
191*d86ed7fbStbbdev };
192*d86ed7fbStbbdev const int VowelsNumber = sizeof(Vowels) / sizeof(Sound);
193*d86ed7fbStbbdev const int ConsonantsNumber = sizeof(Consonants) / sizeof(Sound);
194*d86ed7fbStbbdev int VowelsRatesSum[3] = { 0, 0, 0 }, ConsonantsRatesSum[3] = { 0, 0, 0 };
195*d86ed7fbStbbdev 
196*d86ed7fbStbbdev int CountRateSum(Sound sounds[], const int num, const int part) {
197*d86ed7fbStbbdev     int sum = 0;
198*d86ed7fbStbbdev     for (int i = 0; i < num; i++)
199*d86ed7fbStbbdev         sum += sounds[i].rates[part];
200*d86ed7fbStbbdev     return sum;
201*d86ed7fbStbbdev }
202*d86ed7fbStbbdev 
203*d86ed7fbStbbdev const char* GetLetters(int type, const int part) {
204*d86ed7fbStbbdev     Sound* sounds;
205*d86ed7fbStbbdev     int rate, i = 0;
206*d86ed7fbStbbdev     if (type & 1)
207*d86ed7fbStbbdev         sounds = Vowels, rate = rand() % VowelsRatesSum[part];
208*d86ed7fbStbbdev     else
209*d86ed7fbStbbdev         sounds = Consonants, rate = rand() % ConsonantsRatesSum[part];
210*d86ed7fbStbbdev     do {
211*d86ed7fbStbbdev         rate -= sounds[i++].rates[part];
212*d86ed7fbStbbdev     } while (rate > 0);
213*d86ed7fbStbbdev     return sounds[--i].chars;
214*d86ed7fbStbbdev }
215*d86ed7fbStbbdev 
216*d86ed7fbStbbdev static void CreateData() {
217*d86ed7fbStbbdev     for (int i = 0; i < 3; i++) {
218*d86ed7fbStbbdev         ConsonantsRatesSum[i] = CountRateSum(Consonants, ConsonantsNumber, i);
219*d86ed7fbStbbdev         VowelsRatesSum[i] = CountRateSum(Vowels, VowelsNumber, i);
220*d86ed7fbStbbdev     }
221*d86ed7fbStbbdev     for (int i = 0; i < N; ++i) {
222*d86ed7fbStbbdev         int type = rand();
223*d86ed7fbStbbdev         Data[i] = GetLetters(type++, 0);
224*d86ed7fbStbbdev         for (int j = 0; j < type % size_factor; ++j)
225*d86ed7fbStbbdev             Data[i] += GetLetters(type++, 1);
226*d86ed7fbStbbdev         Data[i] += GetLetters(type, 2);
227*d86ed7fbStbbdev     }
228*d86ed7fbStbbdev     MyString planet = Data[12];
229*d86ed7fbStbbdev     planet[0] = toupper(planet[0]);
230*d86ed7fbStbbdev     MyString helloworld = Data[0];
231*d86ed7fbStbbdev     helloworld[0] = toupper(helloworld[0]);
232*d86ed7fbStbbdev     helloworld += ", " + Data[1] + " " + Data[2] + " " + Data[3] + " " + Data[4] + " " + Data[5];
233*d86ed7fbStbbdev     if (!silent)
234*d86ed7fbStbbdev         printf("Message from planet '%s': %s!\nAnalyzing whole text...\n",
235*d86ed7fbStbbdev                planet.c_str(),
236*d86ed7fbStbbdev                helloworld.c_str());
237*d86ed7fbStbbdev }
238*d86ed7fbStbbdev 
239*d86ed7fbStbbdev int main(int argc, char* argv[]) {
240*d86ed7fbStbbdev     StringTable table;
241*d86ed7fbStbbdev     oneapi::tbb::tick_count mainStartTime = oneapi::tbb::tick_count::now();
242*d86ed7fbStbbdev     srand(2);
243*d86ed7fbStbbdev 
244*d86ed7fbStbbdev     //! Working threads count
245*d86ed7fbStbbdev     // The 1st argument is the function to obtain 'auto' value; the 2nd is the default value
246*d86ed7fbStbbdev     // The example interprets 0 threads as "run serially, then fully subscribed"
247*d86ed7fbStbbdev     utility::thread_number_range threads(utility::get_default_num_threads, 0);
248*d86ed7fbStbbdev 
249*d86ed7fbStbbdev     utility::parse_cli_arguments(
250*d86ed7fbStbbdev         argc,
251*d86ed7fbStbbdev         argv,
252*d86ed7fbStbbdev         utility::cli_argument_pack()
253*d86ed7fbStbbdev             //"-h" option for displaying help is present implicitly
254*d86ed7fbStbbdev             .positional_arg(threads, "n-of-threads", utility::thread_number_range_desc)
255*d86ed7fbStbbdev             .positional_arg(N, "n-of-strings", "number of strings")
256*d86ed7fbStbbdev             .arg(verbose, "verbose", "verbose mode")
257*d86ed7fbStbbdev             .arg(silent, "silent", "no output except elapsed time")
258*d86ed7fbStbbdev             .arg(count_collisions, "count_collisions", "print the count of collisions"));
259*d86ed7fbStbbdev 
260*d86ed7fbStbbdev     if (silent)
261*d86ed7fbStbbdev         verbose = false;
262*d86ed7fbStbbdev 
263*d86ed7fbStbbdev     Data = new MyString[N];
264*d86ed7fbStbbdev     CreateData();
265*d86ed7fbStbbdev 
266*d86ed7fbStbbdev     if (threads.first) {
267*d86ed7fbStbbdev         for (int p = threads.first; p <= threads.last; p = threads.step(p)) {
268*d86ed7fbStbbdev             if (!silent)
269*d86ed7fbStbbdev                 printf("threads = %d  ", p);
270*d86ed7fbStbbdev             oneapi::tbb::global_control c(oneapi::tbb::global_control::max_allowed_parallelism, p);
271*d86ed7fbStbbdev             CountOccurrences(p);
272*d86ed7fbStbbdev         }
273*d86ed7fbStbbdev     }
274*d86ed7fbStbbdev     else { // Number of threads wasn't set explicitly. Run serial and parallel version
275*d86ed7fbStbbdev         { // serial run
276*d86ed7fbStbbdev             if (!silent)
277*d86ed7fbStbbdev                 printf("serial run   ");
278*d86ed7fbStbbdev             oneapi::tbb::global_control c(oneapi::tbb::global_control::max_allowed_parallelism, 1);
279*d86ed7fbStbbdev             CountOccurrences(1);
280*d86ed7fbStbbdev         }
281*d86ed7fbStbbdev         { // parallel run (number of threads is selected automatically)
282*d86ed7fbStbbdev             if (!silent)
283*d86ed7fbStbbdev                 printf("parallel run ");
284*d86ed7fbStbbdev             oneapi::tbb::global_control c(oneapi::tbb::global_control::max_allowed_parallelism,
285*d86ed7fbStbbdev                                           utility::get_default_num_threads());
286*d86ed7fbStbbdev             CountOccurrences(0);
287*d86ed7fbStbbdev         }
288*d86ed7fbStbbdev     }
289*d86ed7fbStbbdev 
290*d86ed7fbStbbdev     delete[] Data;
291*d86ed7fbStbbdev 
292*d86ed7fbStbbdev     utility::report_elapsed_time((oneapi::tbb::tick_count::now() - mainStartTime).seconds());
293*d86ed7fbStbbdev 
294*d86ed7fbStbbdev     return 0;
295*d86ed7fbStbbdev }
296