source: tests/PRNG.cfa @ 960665c

Last change on this file since 960665c was 3267041, checked in by Peter A. Buhr <pabuhr@…>, 12 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.