source: tests/PRNG.cfa @ 5d8cc96

Last change on this file since 5d8cc96 was 7d25f44, checked in by Peter A. Buhr <pabuhr@…>, 12 months ago

update files from old separator manipulator names to new names

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