1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4
5 #include <IceUtil/UUID.h>
6 #include <IceUtil/Random.h>
7 #include <IceUtil/Time.h>
8 #include <IceUtil/Thread.h>
9 #include <IceUtil/Mutex.h>
10 #include <IceUtil/MutexPtrLock.h>
11 #include <TestHelper.h>
12 #include <set>
13 #include <vector>
14
15 using namespace IceUtil;
16 using namespace std;
17
18 namespace
19 {
20
21 Mutex* staticMutex = 0;
22
23 class Init
24 {
25 public:
26
Init()27 Init()
28 {
29 staticMutex = new IceUtil::Mutex;
30 }
31
~Init()32 ~Init()
33 {
34 delete staticMutex;
35 staticMutex = 0;
36 }
37 };
38
39 Init init;
40
41 }
42
usage(const char * myName)43 inline void usage(const char* myName)
44 {
45 cerr << "Usage: " << myName << " [number of UUIDs to generate] [number of threads]" << endl;
46 }
47
48 template<typename T, typename GenerateFunc> class InsertThread : public Thread
49 {
50 public:
51
52 typedef set<T> ItemSet;
53
InsertThread(int threadId,ItemSet & itemSet,GenerateFunc func,long howMany,bool verbose)54 InsertThread(int threadId, ItemSet& itemSet, GenerateFunc func, long howMany, bool verbose)
55 : _threadId(threadId), _itemSet(itemSet), _func(func), _howMany(howMany), _verbose(verbose)
56 {
57 }
58
run()59 void run()
60 {
61 for(long i = 0; i < _howMany; i++)
62 {
63 T item = _func();
64
65 IceUtilInternal::MutexPtrLock<IceUtil::Mutex> lock(staticMutex);
66 pair<typename ItemSet::iterator, bool> ok = _itemSet.insert(item);
67 if(!ok.second)
68 {
69 cerr << "******* iteration " << i << endl;
70 cerr << "******* Duplicate item: " << *ok.first << endl;
71 }
72
73 test(ok.second);
74
75 if(_verbose && i > 0 && (i % 100000 == 0))
76 {
77 cout << "Thread " << _threadId << ": generated " << i << " UUIDs." << endl;
78 }
79 }
80 }
81
82 private:
83
84 int _threadId;
85 ItemSet& _itemSet;
86 GenerateFunc _func;
87 long _howMany;
88 bool _verbose;
89 };
90
91 struct GenerateUUID
92 {
93 string
operator ()GenerateUUID94 operator()()
95 {
96 return generateUUID();
97 }
98 };
99
100 struct GenerateRandomString
101 {
102 string
operator ()GenerateRandomString103 operator()()
104 {
105 string s;
106 s.resize(21);
107 char buf[21];
108 IceUtilInternal::generateRandom(buf, sizeof(buf));
109 for(unsigned int i = 0; i < sizeof(buf); ++i)
110 {
111 s[i] = 33 + static_cast<unsigned char>(buf[i]) % (127 - 33); // We use ASCII 33-126 (from ! to ~, w/o space).
112 }
113 // cerr << s << endl;
114 return s;
115 }
116 };
117
118 struct GenerateRandomInt
119 {
120 public:
121
122 int
operator ()GenerateRandomInt123 operator()()
124 {
125 return IceUtilInternal::random();
126 }
127
128 };
129
130 template<typename T, typename GenerateFunc> void
runTest(int threadCount,GenerateFunc func,long howMany,bool verbose,string name)131 runTest(int threadCount, GenerateFunc func, long howMany, bool verbose, string name)
132 {
133 cout << "Generating " << howMany << " " << name << "s using " << threadCount << " thread";
134 if(threadCount > 1)
135 {
136 cout << "s";
137 }
138 cout << "... ";
139
140 if(verbose)
141 {
142 cout << endl;
143 }
144 else
145 {
146 cout << flush;
147 }
148
149 set<T> itemSet;
150
151 vector<ThreadControl> threads;
152
153 Time start = Time::now();
154 for(int i = 0; i < threadCount; i++)
155 {
156 ThreadPtr t = new InsertThread<T, GenerateFunc>(i, itemSet, func, howMany / threadCount, verbose);
157 threads.push_back(t->start());
158 }
159 for(vector<ThreadControl>::iterator p = threads.begin(); p != threads.end(); ++p)
160 {
161 p->join();
162 }
163 Time finish = Time::now();
164
165 cout << "ok" << endl;
166
167 if(verbose)
168 {
169 cout << "Each " << name << " took an average of "
170 << (double) ((finish - start).toMicroSeconds()) / howMany
171 << " micro seconds to generate and insert into a set."
172 << endl;
173 }
174 }
175
176 class Client : public Test::TestHelper
177 {
178 public:
179
180 virtual void run(int argc, char* argv[]);
181 };
182
183 void
run(int argc,char * argv[])184 Client::run(int argc, char* argv[])
185 {
186 long howMany = 300000;
187 int threadCount = 3;
188 bool verbose = false;
189
190 if(argc > 3)
191 {
192 usage(argv[0]);
193 throw std::invalid_argument("too many arguments");
194 }
195
196 if(argc > 1)
197 {
198 howMany = atol(argv[1]);
199 if(howMany == 0)
200 {
201 usage(argv[0]);
202 throw invalid_argument("argv[1] howMany is not a number");
203 }
204 }
205
206 if(argc > 2)
207 {
208
209 threadCount = atoi(argv[2]);
210 if(threadCount <= 0)
211 {
212 usage(argv[0]);
213 throw invalid_argument("argv[2] threadCount is not a number");
214 }
215 verbose = true;
216 }
217
218 runTest<string, GenerateUUID>(threadCount, GenerateUUID(), howMany, verbose, "UUID");
219 runTest<string, GenerateRandomString>(threadCount, GenerateRandomString(), howMany, verbose, "string");
220 }
221
222 DEFINE_TEST(Client);
223