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