|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "nspr.h" |
|
7 #include "prinrval.h" |
|
8 #include "plgetopt.h" |
|
9 #include "pprthred.h" |
|
10 #include <stdio.h> |
|
11 #include <stdlib.h> |
|
12 #include <string.h> |
|
13 |
|
14 PRMonitor *mon; |
|
15 PRInt32 count, iterations, alive; |
|
16 |
|
17 PRBool debug_mode = PR_FALSE, passed = PR_TRUE; |
|
18 |
|
19 void |
|
20 PR_CALLBACK |
|
21 ReallyDumbThread(void *arg) |
|
22 { |
|
23 return; |
|
24 } |
|
25 |
|
26 void |
|
27 PR_CALLBACK |
|
28 DumbThread(void *arg) |
|
29 { |
|
30 PRInt32 tmp = (PRInt32)arg; |
|
31 PRThreadScope scope = (PRThreadScope)tmp; |
|
32 PRThread *thr; |
|
33 |
|
34 thr = PR_CreateThread(PR_USER_THREAD, |
|
35 ReallyDumbThread, |
|
36 NULL, |
|
37 PR_PRIORITY_NORMAL, |
|
38 scope, |
|
39 PR_JOINABLE_THREAD, |
|
40 0); |
|
41 |
|
42 if (!thr) { |
|
43 if (debug_mode) { |
|
44 printf("Could not create really dumb thread (%d, %d)!\n", |
|
45 PR_GetError(), PR_GetOSError()); |
|
46 } |
|
47 passed = PR_FALSE; |
|
48 } else { |
|
49 PR_JoinThread(thr); |
|
50 } |
|
51 PR_EnterMonitor(mon); |
|
52 alive--; |
|
53 PR_Notify(mon); |
|
54 PR_ExitMonitor(mon); |
|
55 } |
|
56 |
|
57 static void CreateThreads(PRThreadScope scope1, PRThreadScope scope2) |
|
58 { |
|
59 PRThread *thr; |
|
60 int n; |
|
61 |
|
62 alive = 0; |
|
63 mon = PR_NewMonitor(); |
|
64 |
|
65 alive = count; |
|
66 for (n=0; n<count; n++) { |
|
67 thr = PR_CreateThread(PR_USER_THREAD, |
|
68 DumbThread, |
|
69 (void *)scope2, |
|
70 PR_PRIORITY_NORMAL, |
|
71 scope1, |
|
72 PR_UNJOINABLE_THREAD, |
|
73 0); |
|
74 if (!thr) { |
|
75 if (debug_mode) { |
|
76 printf("Could not create dumb thread (%d, %d)!\n", |
|
77 PR_GetError(), PR_GetOSError()); |
|
78 } |
|
79 passed = PR_FALSE; |
|
80 alive--; |
|
81 } |
|
82 |
|
83 PR_Sleep(0); |
|
84 } |
|
85 |
|
86 /* Wait for all threads to exit */ |
|
87 PR_EnterMonitor(mon); |
|
88 while (alive) { |
|
89 PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); |
|
90 } |
|
91 |
|
92 PR_ExitMonitor(mon); |
|
93 PR_DestroyMonitor(mon); |
|
94 } |
|
95 |
|
96 static void CreateThreadsUU(void) |
|
97 { |
|
98 CreateThreads(PR_LOCAL_THREAD, PR_LOCAL_THREAD); |
|
99 } |
|
100 |
|
101 static void CreateThreadsUK(void) |
|
102 { |
|
103 CreateThreads(PR_LOCAL_THREAD, PR_GLOBAL_THREAD); |
|
104 } |
|
105 |
|
106 static void CreateThreadsKU(void) |
|
107 { |
|
108 CreateThreads(PR_GLOBAL_THREAD, PR_LOCAL_THREAD); |
|
109 } |
|
110 |
|
111 static void CreateThreadsKK(void) |
|
112 { |
|
113 CreateThreads(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD); |
|
114 } |
|
115 |
|
116 /************************************************************************/ |
|
117 |
|
118 static void Measure(void (*func)(void), const char *msg) |
|
119 { |
|
120 PRIntervalTime start, stop; |
|
121 double d; |
|
122 |
|
123 start = PR_IntervalNow(); |
|
124 (*func)(); |
|
125 stop = PR_IntervalNow(); |
|
126 |
|
127 if (debug_mode) |
|
128 { |
|
129 d = (double)PR_IntervalToMicroseconds(stop - start); |
|
130 printf("%40s: %6.2f usec\n", msg, d / count); |
|
131 } |
|
132 } |
|
133 |
|
134 int main(int argc, char **argv) |
|
135 { |
|
136 int index; |
|
137 |
|
138 PR_STDIO_INIT(); |
|
139 PR_Init(PR_USER_THREAD, PR_PRIORITY_HIGH, 0); |
|
140 |
|
141 { |
|
142 PLOptStatus os; |
|
143 PLOptState *opt = PL_CreateOptState(argc, argv, "dc:i:"); |
|
144 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) |
|
145 { |
|
146 if (PL_OPT_BAD == os) continue; |
|
147 switch (opt->option) |
|
148 { |
|
149 case 'd': /* debug mode */ |
|
150 debug_mode = PR_TRUE; |
|
151 break; |
|
152 case 'c': /* loop counter */ |
|
153 count = atoi(opt->value); |
|
154 break; |
|
155 case 'i': /* loop counter */ |
|
156 iterations = atoi(opt->value); |
|
157 break; |
|
158 default: |
|
159 break; |
|
160 } |
|
161 } |
|
162 PL_DestroyOptState(opt); |
|
163 } |
|
164 |
|
165 if (0 == count) count = 50; |
|
166 if (0 == iterations) iterations = 10; |
|
167 |
|
168 if (debug_mode) |
|
169 { |
|
170 printf("\ |
|
171 ** Tests lots of thread creations. \n\ |
|
172 ** Create %ld native threads %ld times. \n\ |
|
173 ** Create %ld user threads %ld times \n", iterations,count,iterations,count); |
|
174 } |
|
175 |
|
176 for (index=0; index<iterations; index++) { |
|
177 Measure(CreateThreadsUU, "Create user/user threads"); |
|
178 Measure(CreateThreadsUK, "Create user/native threads"); |
|
179 Measure(CreateThreadsKU, "Create native/user threads"); |
|
180 Measure(CreateThreadsKK, "Create native/native threads"); |
|
181 } |
|
182 |
|
183 if (debug_mode) printf("\nNow switch to recycling threads \n\n"); |
|
184 PR_SetThreadRecycleMode(1); |
|
185 |
|
186 for (index=0; index<iterations; index++) { |
|
187 Measure(CreateThreadsUU, "Create user/user threads"); |
|
188 Measure(CreateThreadsUK, "Create user/native threads"); |
|
189 Measure(CreateThreadsKU, "Create native/user threads"); |
|
190 Measure(CreateThreadsKK, "Create native/native threads"); |
|
191 } |
|
192 |
|
193 |
|
194 printf("%s\n", ((passed) ? "PASS" : "FAIL")); |
|
195 |
|
196 PR_Cleanup(); |
|
197 |
|
198 if (passed) { |
|
199 return 0; |
|
200 } else { |
|
201 return 1; |
|
202 } |
|
203 } |