source: tests/PRNG.cfa @ 5910fc0

ADTast-experimentalenumforall-pointer-decaypthread-emulationqualifiedEnum
Last change on this file since 5910fc0 was 5910fc0, checked in by Peter A. Buhr <pabuhr@…>, 2 years ago

add PRNG test

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