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