1 //========================================================================
2 // Multithreading benchmark program, based on the GLFW multi threading
3 // support.
4 //
5 // This program can be used to get an idea of what to expect in terms of
6 // multithreading granularity performance.
7 //
8 // As a "bonus", this program demonstrates how to create a signal
9 // primitive using the GLFW mutex and condition variable primitives.
10 //
11 // Here are some benchmark results:
12 // (Note: these are not exact measurments, since they are subject to
13 // varying CPU-loads etc. Some tested systems are multi-user systems
14 // which were running under anything but optimal conditions)
15 //
16 // +------------+-------+-------------+-------------------+------------+
17 // | Processor  |  CPUs |     OS      | Context switches  | Mean sleep |
18 // |            |       |             |    per second     | time (ms)  |
19 // +------------+-------+-------------+-------------------+------------+
20 // |Athlon      |   1   | Linux       |       161942      |   20.000   |
21 // |710 MHz     |       | 2.4.3       |                   |            |
22 // +------------+-------+-------------+-------------------+------------+
23 // |Athlon      |   1   | MS Win2k    |       525230      |   10.014   |
24 // |710 MHz     |       |             |                   |            |
25 // +------------+-------+-------------+-------------------+------------+
26 // |Athlon      |   1   | MS Win 98   |        23564      |    4.947   |
27 // |710 MHz     |       |             |                   |            |
28 // +------------+-------+-------------+-------------------+------------+
29 // |Pentium III |   1   | MS NT 4.0   |       304694      |   10.014   |
30 // |500 MHz     |       |             |                   |            |
31 // +------------+-------+-------------+-------------------+------------+
32 // |UltraSPARC2 |   6   | SunOS 5.6   |       120867      |   19.355   |
33 // |400 MHz     |       |             |                   |            |
34 // +------------+-------+-------------+-------------------+------------+
35 // |Alpha 21264 |   1   | OSF1        |       131993      |    3.097   |
36 // |500 MHz     |       |             |                   |            |
37 // +------------+-------+-------------+-------------------+------------+
38 // |Alpha 21264 |   2   | OSF1        |        40836      |    1.397   |
39 // |500 MHz     |       |             |                   |            |
40 // +------------+-------+-------------+-------------------+------------+
41 // |68020 (emu) |   1   | AmigaOS 3.1 |        50425      |   40.060   |
42 // |~200 MHz    |       | (WinUAE)    |                   |            |
43 // +------------+-------+-------------+-------------------+------------+
44 //
45 //========================================================================
46 
47 import glfw;
48 import std.c.stdio;
49 
50 struct signal_t {
51     GLFWcond  cond;
52     GLFWmutex mutex;
53     int       flag;
54 }
55 
56 signal_t gotoA, gotoB;
57 
58 GLFWcond threadDone;
59 GLFWmutex doneMutex;
60 int doneCount = 0;
61 int gotoACount = 0;
62 int gotoBCount = 0;
63 
64 const int MAX_COUNT = 10000;
65 
66 
67 //------------------------------------------------------------------------
68 // InitSignal()
69 //------------------------------------------------------------------------
70 
InitSignal(signal_t * s)71 void InitSignal( signal_t *s )
72 {
73     s.cond  = glfwCreateCond();
74     s.mutex = glfwCreateMutex();
75     s.flag  = 0;
76 }
77 
78 
79 //------------------------------------------------------------------------
80 // KillSignal()
81 //------------------------------------------------------------------------
82 
KillSignal(signal_t * s)83 void KillSignal( signal_t *s )
84 {
85     glfwDestroyCond( s.cond );
86     glfwDestroyMutex( s.mutex );
87     s.flag  = 0;
88 }
89 
90 
91 //------------------------------------------------------------------------
92 // WaitSignal()
93 //------------------------------------------------------------------------
94 
WaitSignal(signal_t * s)95 void WaitSignal( signal_t *s )
96 {
97     glfwLockMutex( s.mutex );
98     while( !s.flag )
99     {
100         glfwWaitCond( s.cond, s.mutex, GLFW_INFINITY );
101     }
102     s.flag = 0;
103     glfwUnlockMutex( s.mutex );
104 }
105 
106 
107 //------------------------------------------------------------------------
108 // SetSignal()
109 //------------------------------------------------------------------------
110 
SetSignal(signal_t * s)111 void SetSignal( signal_t *s )
112 {
113     glfwLockMutex( s.mutex );
114     s.flag = 1;
115     glfwUnlockMutex( s.mutex );
116     glfwSignalCond( s.cond );
117 }
118 
119 
120 //------------------------------------------------------------------------
121 // main()
122 //------------------------------------------------------------------------
123 
main()124 int main( )
125 {
126     GLFWthread threadA, threadB;
127     double     t1, t2, csps;
128     int        done, count, i;
129 
130     gotoACount = gotoBCount = doneCount = 0;
131 
132     // Initialize GLFW
133     if( !glfwInit() )
134     {
135         return 0;
136     }
137 
138     // Print some program information
139     printf( "\nMultithreading benchmarking program\n" );
140     printf( "-----------------------------------\n\n" );
141     printf( "This program consists of two tests. In the first test " );
142     printf( "two threads are created,\n" );
143     printf( "which continously signal/wait each other. This forces " );
144     printf( "the execution to\n" );
145     printf( "alternate between the two threads, and gives a measure " );
146     printf( "of the thread\n" );
147     printf( "synchronization granularity. In the second test, the " );
148     printf( "main thread is repeatedly\n" );
149     printf( "put to sleep for a very short interval using glfwSleep. " );
150     printf( "The average sleep time\n" );
151     printf( "is measured, which tells the minimum supported sleep " );
152     printf( "interval.\n\n" );
153     printf( "Results:\n" );
154     printf( "--------\n\n" );
155     printf( "Number of CPUs: %d\n\n", glfwGetNumberOfProcessors() );
156     fflush( stdout );
157 
158 
159 //------------------------------------------------------------------------
160 // 1) Benchmark thread synchronization granularity
161 //------------------------------------------------------------------------
162 
163     // Init mutexes and conditions
164     doneMutex  = glfwCreateMutex();
165     threadDone = glfwCreateCond();
166     InitSignal( &gotoA );
167     InitSignal( &gotoB );
168 
169     // Create threads A & B
170     threadA = glfwCreateThread( &threadAfun, null );
171     threadB = glfwCreateThread( &threadBfun, null );
172     if( threadA == -1 || threadB == -1 )
173     {
174         glfwLockMutex( doneMutex );
175         doneCount = 2;
176         glfwUnlockMutex( doneMutex );
177     }
178 
179     // Wait for both threads to be done
180     t1 = glfwGetTime();
181     glfwLockMutex( doneMutex );
182     do
183     {
184         done = (doneCount == 2);
185         if( !done )
186         {
187             glfwWaitCond( threadDone, doneMutex, GLFW_INFINITY );
188         }
189     }
190     while( !done );
191     glfwUnlockMutex( doneMutex );
192     t2 = glfwGetTime();
193 
194     // Display results
195     count = gotoACount + gotoBCount;
196     csps = cast(double)count / (t2-t1);
197     printf( "Test 1:  %.0f context switches / second (%.3f us/switch)\n",
198             csps, 1e6/csps );
199     fflush( stdout );
200 
201     // Wait for threads to die
202     glfwWaitThread( threadA, GLFW_WAIT );
203     glfwWaitThread( threadB, GLFW_WAIT );
204 
205     // Destroy mutexes and conditions
206     glfwDestroyMutex( doneMutex );
207     glfwDestroyCond( threadDone );
208     KillSignal( &gotoA );
209     KillSignal( &gotoB );
210 
211 
212 //------------------------------------------------------------------------
213 // 2) Benchmark thread sleep granularity
214 //------------------------------------------------------------------------
215 
216     // Find an initial estimate
217     t1 = glfwGetTime();
218     for( i = 0; i < 10; i ++ )
219     {
220         glfwSleep( 0.0001 );
221     }
222     t2 = glfwGetTime();
223 
224     // Sleep for roughly 1 s
225     count = cast(int)(1.0 / ((t2-t1)/10.0));
226     t1 = glfwGetTime();
227     for( i = 0; i < count; i ++ )
228     {
229         glfwSleep( 0.0001 );
230     }
231     t2 = glfwGetTime();
232 
233     // Display results
234     printf( "Test 2:  %.3f ms / sleep (mean)\n\n",
235             1000.0 * (t2-t1) / cast(double)count );
236 
237     // Terminate GLFW
238     glfwTerminate();
239 
240     return 0;
241 }
242 
243 
version(Windows)244 version(Windows) {
245 	extern(Windows):
246 } else {
247 	extern(C):
248 }
249 //------------------------------------------------------------------------
250 // threadAfun()
251 //------------------------------------------------------------------------
252 
threadAfun(void * arg)253 void threadAfun( void * arg )
254 {
255     int done;
256 
257     do
258     {
259         done = (gotoACount >= MAX_COUNT);
260         if( !done )
261         {
262             gotoACount ++;
263             SetSignal( &gotoB );
264             WaitSignal( &gotoA );
265         }
266     }
267     while( !done );
268 
269     SetSignal( &gotoB );
270 
271     glfwLockMutex( doneMutex );
272     doneCount ++;
273     glfwUnlockMutex( doneMutex );
274     glfwSignalCond( threadDone );
275 }
276 
277 
278 //------------------------------------------------------------------------
279 // threadBfun()
280 //------------------------------------------------------------------------
281 
threadBfun(void * arg)282 void threadBfun( void * arg )
283 {
284     int done;
285 
286     do
287     {
288         done = (gotoBCount >= MAX_COUNT);
289         if( !done )
290         {
291             gotoBCount ++;
292             SetSignal( &gotoA );
293             WaitSignal( &gotoB );
294         }
295     }
296     while( !done );
297 
298     SetSignal( &gotoA );
299 
300     glfwLockMutex( doneMutex );
301     doneCount ++;
302     glfwUnlockMutex( doneMutex );
303     glfwSignalCond( threadDone );
304 }
305