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