source: tests/PRNG.cfa @ df2e00f

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

reduce runtime testing duration of PRNG

  • Property mode set to 100644
File size: 7.1 KB
RevLine 
[4246869]1//
[5910fc0]2// Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo
[4246869]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//
[5910fc0]9// Author           : Peter A. Buhr
10// Created On       : Wed Dec 29 09:38:12 2021
11// Last Modified By : Peter A. Buhr
[3267041]12// Last Modified On : Tue Dec  5 08:14:57 2023
13// Update Count     : 428
[5910fc0]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
[8a2f7f1]23#include <thread.hfa>
[470618c0]24#include <mutex_stmt.hfa>
[5910fc0]25
[8a2f7f1]26#define xstr(s) str(s)
27#define str(s) #s
28
29//#define TIME
30
[5910fc0]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"
[3267041]34enum { BUCKETS = 100_000, TRIALS = 100_000_000 };
[5910fc0]35#else
36#define STARTTIME
37#define ENDTIME( extra )
[3267041]38enum { BUCKETS = 100_000, TRIALS = 10_000_000 };
[5910fc0]39#endif // TIME
40
[8a2f7f1]41static void avgstd( size_t trials, size_t buckets[] ) {
42        size_t min = MAX, max = 0;
[5910fc0]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 );
[8a2f7f1]57        mutex( sout ) sout | "trials"  | trials | "buckets" | BUCKETS
[470618c0]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)) | "%";
[5910fc0]60} // avgstd
61
62
[ae7a085c]63size_t seed = 1009;
[5910fc0]64
65thread T1 {};
66void main( T1 & ) {
[8a2f7f1]67        size_t * buckets = calloc( BUCKETS );                           // too big for task stack
68        for ( TRIALS / 50 ) {
[5910fc0]69                buckets[rand() % BUCKETS] += 1;                                 // concurrent
70        } // for
[8a2f7f1]71        avgstd( TRIALS / 50, buckets );
[5910fc0]72        free( buckets );
73} // main
74
75thread T2 {};
76void main( T2 & ) {
77        PRNG prng;
78        if ( seed != 0 ) set_seed( prng, seed );
[8a2f7f1]79        size_t * buckets = calloc( BUCKETS );                           // too big for task stack
[5910fc0]80        for ( TRIALS ) {
81                buckets[prng( prng ) % BUCKETS] += 1;                   // concurrent
82        } // for
[8a2f7f1]83        avgstd( TRIALS, buckets );
[5910fc0]84        free( buckets );
85} // main
86
87thread T3 {};
88void main( T3 & th ) {
[8a2f7f1]89        size_t * buckets = calloc( BUCKETS );                           // too big for task stack
90        for ( TRIALS / 5 ) {
[5910fc0]91                buckets[prng() % BUCKETS] += 1;                                 // concurrent
92        } // for
[8a2f7f1]93        avgstd( TRIALS / 5, buckets );
[5910fc0]94        free( buckets );
95} // main
96
97thread T4 {};
98void main( T4 & th ) {
[8a2f7f1]99        size_t * buckets = calloc( BUCKETS );                           // too big for task stack
[5910fc0]100        for ( TRIALS ) {
[8a2f7f1]101                buckets[prng( th ) % BUCKETS] += 1;                             // concurrent
[5910fc0]102        } // for
[8a2f7f1]103        avgstd( TRIALS, buckets );
[5910fc0]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 ) {
[8a2f7f1]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 ) {
[5910fc0]113                buckets[prng( th ) % BUCKETS] += 1;                             // sequential
114        } // for
[8a2f7f1]115        avgstd( TRIALS, buckets );
[5910fc0]116        free( buckets );
117} // dummy
118
[ae7a085c]119
[5910fc0]120int main() {
[e6d8d11]121        // setlocale( LC_NUMERIC, getenv( "LANG" ) );           // causes leaked storage message
122
123        // only works on the current pthread thread
[ae7a085c]124        // locale_t loc = newlocale( LC_NUMERIC_MASK, getenv( "LANG" ), (locale_t)0p );
125        // if ( loc == (locale_t)0p ) abort( "newlocale" );
126        // uselocale( loc );
[5910fc0]127
128        enum { TASKS = 4 };
129        Time start;
[8a2f7f1]130
[5910fc0]131#ifdef TIME                                                                                             // too slow for test and generates non-repeatable results
132#if 1
[8a2f7f1]133        sout | "glib rand" | nl | nl;
134
135        size_t rseed;
[5910fc0]136        if ( seed != 0 ) rseed = seed;
137        else rseed = rdtscl();
138        srand( rseed );
139
[7d25f44]140        sout | sepOff;
[8a2f7f1]141        sout | nl | wd(26, "rand()" ) | wd(12, "rand(5)") | wd(12, "rand(0,5)" );
[5910fc0]142        for ( 20 ) {
[ae7a085c]143                sout | wd(26, rand()) | nonl;
144                sout | wd(12, rand() % 5) | nonl;
145                sout | wd(12, rand() % (5 - 0 + 1) + 0);
[5910fc0]146        } // for
[7d25f44]147        sout | sepOn;
[5910fc0]148        sout | "seed" | rseed;
149
150        sout | nl | "Sequential";
151        STARTTIME;
152        {
[8a2f7f1]153                size_t * buckets = calloc( BUCKETS );                   // too big for task stack
154                for ( i; TRIALS / 5 ) {
[5910fc0]155                        buckets[rand() % BUCKETS] += 1;                         // sequential
156                } // for
[8a2f7f1]157                avgstd( TRIALS / 5, buckets );
[5910fc0]158                free( buckets );
159        }
[8a2f7f1]160        ENDTIME( " x 5 " );
[5910fc0]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        }
[8a2f7f1]170        ENDTIME( " x 50 " );
[5910fc0]171#endif // 0
172#endif // TIME
[8a2f7f1]173
174        sout | nl | "CFA " xstr(PRNG_NAME);
175
[5910fc0]176#if 1
177        PRNG prng;
[d2ad151]178
[5910fc0]179        if ( seed != 0 ) set_seed( prng, seed );
180
[7d25f44]181        sout | sepOff;
[ae7a085c]182        sout | nl | wd(26, "PRNG()" ) | wd(12, "PRNG(5)") | wd(12, "PRNG(0,5)" );
[5910fc0]183        for ( 20 ) {
[ae7a085c]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 ));
[5910fc0]187        } // for
[7d25f44]188        sout | sepOn;
[5910fc0]189        sout | "seed" | get_seed( prng );
190
191        sout | nl | "Sequential";
192        STARTTIME;
193        {
[8a2f7f1]194                size_t * buckets = calloc( BUCKETS );                   // too big for task stack
[5910fc0]195                for ( TRIALS ) {
196                        buckets[prng( prng ) % BUCKETS] += 1;           // sequential
197                } // for
[8a2f7f1]198                avgstd( TRIALS, buckets );
[5910fc0]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
[7d25f44]216        sout | sepOff;
[ae7a085c]217        sout | nl | wd(26, "prng()" ) | wd(12, "prng(5)") | wd(12, "prng(0,5)" );
[5910fc0]218        for ( 20 ) {
[ae7a085c]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 ));
[5910fc0]222        } // for
[7d25f44]223        sout | sepOn;
[5910fc0]224        sout | "seed" | get_seed( prng );
225
226        sout | nl | "Sequential";
227        STARTTIME;
228        {
[8a2f7f1]229                size_t * buckets = calloc( BUCKETS );                   // too big for task stack
230                for ( TRIALS / 5 ) {
[5910fc0]231                        buckets[prng() % BUCKETS] += 1;
232                } // for
[8a2f7f1]233                avgstd( TRIALS / 5, buckets );
[5910fc0]234                free( buckets );
235        }
[8a2f7f1]236        ENDTIME( " x 5 " );
[5910fc0]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        }
[8a2f7f1]246        ENDTIME( " x 5 " );
[5910fc0]247#endif // 0
248#if 1
249        if ( seed != 0 ) set_seed( seed );
250        thread$ & th = *active_thread();
251
[7d25f44]252        sout | sepOff;
[ae7a085c]253        sout | nl | wd(26, "prng(t)" ) | wd(12, "prng(t,5)") | wd(12, "prng(t,0,5)" );
[5910fc0]254        for ( 20 ) {
[ae7a085c]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 ));
[5910fc0]258        } // for
[7d25f44]259        sout | sepOn;
[5910fc0]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();
[ae7a085c]280        // freelocale( loc );
[5910fc0]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.