source: tests/PRNG.cfa@ 262a864

Last change on this file since 262a864 was 3267041, checked in by Peter A. Buhr <pabuhr@…>, 22 months ago

reduce runtime testing duration of PRNG

  • Property mode set to 100644
File size: 7.1 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo
3//
4// PRNG.c -- high-perforamnce pseudo-random numbers
5//
6// The contents of this file are covered under the licence agreement in the
7// file "LICENCE" distributed with Cforall.
8//
9// Author : Peter A. Buhr
10// Created On : Wed Dec 29 09:38:12 2021
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Tue Dec 5 08:14:57 2023
13// Update Count : 428
14//
15
16#include <fstream.hfa> // sout
17#include <stdlib.hfa> // PRNG
18#include <clock.hfa>
19#include <limits.hfa> // MAX
20#include <math.hfa> // sqrt
21#include <malloc.h> // malloc_stats
22#include <locale.h> // setlocale
23#include <thread.hfa>
24#include <mutex_stmt.hfa>
25
26#define xstr(s) str(s)
27#define str(s) #s
28
29//#define TIME
30
31#ifdef TIME // use -O2 -nodebug
32#define STARTTIME start = timeHiRes()
33#define ENDTIME( extra ) sout | wd(0,1, (timeHiRes() - start)`ms / 1000.) | extra "seconds"
34enum { BUCKETS = 100_000, TRIALS = 100_000_000 };
35#else
36#define STARTTIME
37#define ENDTIME( extra )
38enum { BUCKETS = 100_000, TRIALS = 10_000_000 };
39#endif // TIME
40
41static void avgstd( size_t trials, size_t buckets[] ) {
42 size_t min = MAX, max = 0;
43 double sum = 0.0, diff;
44 for ( i; BUCKETS ) {
45 if ( buckets[i] < min ) min = buckets[i];
46 if ( buckets[i] > max ) max = buckets[i];
47 sum += buckets[i];
48 } // for
49
50 double avg = sum / BUCKETS; // average
51 sum = 0.0;
52 for ( i; BUCKETS ) { // sum squared differences from average
53 diff = buckets[i] - avg;
54 sum += diff * diff;
55 } // for
56 double std = sqrt( sum / BUCKETS );
57 mutex( sout ) sout | "trials" | trials | "buckets" | BUCKETS
58 | "min" | min | "max" | max
59 | "avg" | wd(0,1, avg) | "std" | wd(0,1, std) | "rstd" | wd(0,1, (avg == 0 ? 0.0 : std / avg * 100)) | "%";
60} // avgstd
61
62
63size_t seed = 1009;
64
65thread T1 {};
66void main( T1 & ) {
67 size_t * buckets = calloc( BUCKETS ); // too big for task stack
68 for ( TRIALS / 50 ) {
69 buckets[rand() % BUCKETS] += 1; // concurrent
70 } // for
71 avgstd( TRIALS / 50, buckets );
72 free( buckets );
73} // main
74
75thread T2 {};
76void main( T2 & ) {
77 PRNG prng;
78 if ( seed != 0 ) set_seed( prng, seed );
79 size_t * buckets = calloc( BUCKETS ); // too big for task stack
80 for ( TRIALS ) {
81 buckets[prng( prng ) % BUCKETS] += 1; // concurrent
82 } // for
83 avgstd( TRIALS, buckets );
84 free( buckets );
85} // main
86
87thread T3 {};
88void main( T3 & th ) {
89 size_t * buckets = calloc( BUCKETS ); // too big for task stack
90 for ( TRIALS / 5 ) {
91 buckets[prng() % BUCKETS] += 1; // concurrent
92 } // for
93 avgstd( TRIALS / 5, buckets );
94 free( buckets );
95} // main
96
97thread T4 {};
98void main( T4 & th ) {
99 size_t * buckets = calloc( BUCKETS ); // too big for task stack
100 for ( TRIALS ) {
101 buckets[prng( th ) % BUCKETS] += 1; // concurrent
102 } // for
103 avgstd( TRIALS, buckets );
104 free( buckets );
105} // main
106
107// Compiler bug requires hiding declaration of th from the bucket access, otherwise the compiler thinks th is aliased
108// and continually reloads it from memory, which doubles the cost.
109static void dummy( thread$ & th ) __attribute__(( noinline ));
110static void dummy( thread$ & th ) {
111 size_t * buckets = (size_t *)calloc( BUCKETS, sizeof(size_t) ); // too big for task stack
112 for ( size_t i = 0; i < TRIALS; i += 1 ) {
113 buckets[prng( th ) % BUCKETS] += 1; // sequential
114 } // for
115 avgstd( TRIALS, buckets );
116 free( buckets );
117} // dummy
118
119
120int main() {
121 // setlocale( LC_NUMERIC, getenv( "LANG" ) ); // causes leaked storage message
122
123 // only works on the current pthread thread
124 // locale_t loc = newlocale( LC_NUMERIC_MASK, getenv( "LANG" ), (locale_t)0p );
125 // if ( loc == (locale_t)0p ) abort( "newlocale" );
126 // uselocale( loc );
127
128 enum { TASKS = 4 };
129 Time start;
130
131#ifdef TIME // too slow for test and generates non-repeatable results
132#if 1
133 sout | "glib rand" | nl | nl;
134
135 size_t rseed;
136 if ( seed != 0 ) rseed = seed;
137 else rseed = rdtscl();
138 srand( rseed );
139
140 sout | sepOff;
141 sout | nl | wd(26, "rand()" ) | wd(12, "rand(5)") | wd(12, "rand(0,5)" );
142 for ( 20 ) {
143 sout | wd(26, rand()) | nonl;
144 sout | wd(12, rand() % 5) | nonl;
145 sout | wd(12, rand() % (5 - 0 + 1) + 0);
146 } // for
147 sout | sepOn;
148 sout | "seed" | rseed;
149
150 sout | nl | "Sequential";
151 STARTTIME;
152 {
153 size_t * buckets = calloc( BUCKETS ); // too big for task stack
154 for ( i; TRIALS / 5 ) {
155 buckets[rand() % BUCKETS] += 1; // sequential
156 } // for
157 avgstd( TRIALS / 5, buckets );
158 free( buckets );
159 }
160 ENDTIME( " x 5 " );
161
162 sout | nl | "Concurrent";
163 STARTTIME;
164 {
165 processor p[TASKS - 1]; // already 1 processor
166 {
167 T1 t[TASKS];
168 } // wait for threads to complete
169 }
170 ENDTIME( " x 50 " );
171#endif // 0
172#endif // TIME
173
174 sout | nl | "CFA " xstr(PRNG_NAME);
175
176#if 1
177 PRNG prng;
178
179 if ( seed != 0 ) set_seed( prng, seed );
180
181 sout | sepOff;
182 sout | nl | wd(26, "PRNG()" ) | wd(12, "PRNG(5)") | wd(12, "PRNG(0,5)" );
183 for ( 20 ) {
184 sout | wd(26, prng( prng )) | nonl; // cascading => side-effect functions called in arbitary order
185 sout | wd(12, prng( prng, 5 )) | nonl;
186 sout | wd(12, prng( prng, 0, 5 ));
187 } // for
188 sout | sepOn;
189 sout | "seed" | get_seed( prng );
190
191 sout | nl | "Sequential";
192 STARTTIME;
193 {
194 size_t * buckets = calloc( BUCKETS ); // too big for task stack
195 for ( TRIALS ) {
196 buckets[prng( prng ) % BUCKETS] += 1; // sequential
197 } // for
198 avgstd( TRIALS, buckets );
199 free( buckets );
200 }
201 ENDTIME();
202
203 sout | nl | "Concurrent";
204 STARTTIME;
205 {
206 processor p[TASKS - 1]; // already 1 processor
207 {
208 T2 t[TASKS];
209 } // wait for threads to complete
210 }
211 ENDTIME();
212#endif // 0
213#if 1
214 if ( seed != 0 ) set_seed( seed );
215
216 sout | sepOff;
217 sout | nl | wd(26, "prng()" ) | wd(12, "prng(5)") | wd(12, "prng(0,5)" );
218 for ( 20 ) {
219 sout | wd(26, prng()) | nonl; // cascading => side-effect functions called in arbitary order
220 sout | wd(12, prng( 5 )) | nonl;
221 sout | wd(12, prng( 0, 5 ));
222 } // for
223 sout | sepOn;
224 sout | "seed" | get_seed( prng );
225
226 sout | nl | "Sequential";
227 STARTTIME;
228 {
229 size_t * buckets = calloc( BUCKETS ); // too big for task stack
230 for ( TRIALS / 5 ) {
231 buckets[prng() % BUCKETS] += 1;
232 } // for
233 avgstd( TRIALS / 5, buckets );
234 free( buckets );
235 }
236 ENDTIME( " x 5 " );
237
238 sout | nl | "Concurrent";
239 STARTTIME;
240 {
241 processor p[TASKS - 1]; // already 1 processor
242 {
243 T3 t[TASKS];
244 } // wait for threads to complete
245 }
246 ENDTIME( " x 5 " );
247#endif // 0
248#if 1
249 if ( seed != 0 ) set_seed( seed );
250 thread$ & th = *active_thread();
251
252 sout | sepOff;
253 sout | nl | wd(26, "prng(t)" ) | wd(12, "prng(t,5)") | wd(12, "prng(t,0,5)" );
254 for ( 20 ) {
255 sout | wd(26, prng( th )) | nonl; // cascading => side-effect functions called in arbitary order
256 sout | wd(12, prng( th, 5 )) | nonl;
257 sout | wd(12, prng( th, 0, 5 ));
258 } // for
259 sout | sepOn;
260 sout | "seed" | get_seed( prng );
261
262 sout | nl | "Sequential";
263 STARTTIME;
264 {
265 dummy( th );
266 }
267 ENDTIME();
268
269 sout | nl | "Concurrent";
270 STARTTIME;
271 {
272 processor p[TASKS - 1]; // already 1 processor
273 {
274 T4 t[TASKS];
275 } // wait for threads to complete
276 }
277 ENDTIME();
278#endif // 0
279// malloc_stats();
280 // freelocale( loc );
281} // main
282
283
284// Local Variables: //
285// compile-command: "cfa -DTIME -O2 -nodebug PRNG.cfa" //
286// End: //
Note: See TracBrowser for help on using the repository browser.