Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 803 lines (669 sloc) 17.579 kB
4567d2c Initial revision
scschnei authored
1 #if defined(USE_HOARD) && defined(_WIN32)
2 #pragma comment(lib, "libhoard.lib")
3 #endif
4
5 #if defined(USE_RX) && defined(_WIN32)
6 #pragma comment(lib, "librx.lib")
7 #endif
8
9 #include <assert.h>
10 #include <stdio.h>
11
12 extern "C" {
13 #include <errno.h>
14 }
15
16 #if defined(_WIN32)
17 #define __WIN32__
18 #endif
19
20 #ifdef __WIN32__
21 #include <windows.h>
22 #include <conio.h>
23 #include <process.h>
24
25 #else
26 #include <unistd.h>
27 #include <sys/resource.h>
28 #include <sys/time.h>
29
30 #ifndef __SVR4
31 //extern "C" int pthread_setconcurrency (int) throw();
32 #include <pthread.h>
33 #endif
34
35 #if defined(__SVR4)
36 //#include <sys/types.h>
37 //#include <procfs.h>
38 #endif
39
40 #if defined(__cplusplus)
41 extern "C" {
42 #endif
43 extern void * hoardmalloc(size_t) __THROW __attribute_malloc__;
44 extern void hoardfree (void*) __THROW;
45 extern void * hoardcalloc(size_t, size_t) __THROW __attribute_malloc__;
46 extern void * hoardrealloc(void *,size_t) __THROW __attribute_malloc__;
47 #if defined(__cplusplus)
48 }
49 #endif
50
51 #if defined(USE_HOARD)
52 #define malloc(x) hoardmalloc(x)
53 #define free(p) hoardfree(p)
54 #define calloc(s,n) hoardcalloc(s,n)
55 #define realloc(p,s) hoardrealloc(p,s)
56
57 #endif
58
59 typedef void * LPVOID;
60 typedef long long LONGLONG;
61 typedef long DWORD;
62 typedef long LONG;
63 typedef unsigned long ULONG;
64 typedef union _LARGE_INTEGER {
65 struct {
66 DWORD LowPart;
67 LONG HighPart;
68 } foo;
69 LONGLONG QuadPart; // In Visual C++, a typedef to _ _int64} LARGE_INTEGER;
70 } LARGE_INTEGER;
71 typedef long long app_int64;
72 #ifndef TRUE
73 enum { TRUE = 1, FALSE = 0 };
74 #endif
75 #include <assert.h>
76 #define _ASSERTE(x) assert(x)
77 #define _inline inline
78 void Sleep (long x)
79 {
80 // printf ("sleeping for %ld seconds.\n", x/1000);
81 sleep(x/1000);
82 }
83
84 void QueryPerformanceCounter (long * x)
85 {
86 struct timezone tz;
87 struct timeval tv;
88 gettimeofday (&tv, &tz);
89 *x = tv.tv_sec * 1000000L + tv.tv_usec;
90 }
91
92 void QueryPerformanceFrequency(long * x)
93 {
94 *x = 1000000L;
95 }
96
97
98 #include <stdio.h>
99 #include <stdlib.h>
100 #include <stddef.h>
101 #include <string.h>
102 #include <ctype.h>
103 #include <time.h>
104 #include <assert.h>
105
106 #define _REENTRANT 1
107 #include <pthread.h>
108 #ifdef __sun
109 #include <thread.h>
110 #endif
111 typedef void * VoidFunction (void *);
112 void _beginthread (VoidFunction x, int, void * z)
113 {
114 pthread_t pt;
115 pthread_attr_t pa;
116 pthread_attr_init (&pa);
117 #if 1//defined(__SVR4)
118 pthread_attr_setscope (&pa, PTHREAD_SCOPE_SYSTEM); /* bound behavior */
119 #endif
120
121 // printf ("creating a thread.\n");
122 int v = pthread_create(&pt, &pa, x, z);
123
124 if (v != 0)
125 perror("Error creating thread:");
126 // printf ("v = %d\n", v);
127 }
128 #endif
129
130
131 #if 0
132 static char buf[65536];
133
134 #define malloc(v) &buf
135 #define free(p)
136 #endif
137
138 #undef CPP
139 //#define CPP
140 //#include "arch-specific.h"
141
142 #if USE_ROCKALL
143 //#include "FastHeap.hpp"
144 //FAST_HEAP theFastHeap (1024 * 1024, true, true, true);
145
146 typedef int SBIT32;
147
148 #include "SmpHeap.hpp"
149 SMP_HEAP theFastHeap (1024 * 1024, true, true, true);
150
151 void * operator new( unsigned int cb )
152 {
153 void *pRet = theFastHeap.New ((size_t)cb) ;
154 return pRet;
155 }
156
157 void operator delete(void *pUserData )
158 {
159 theFastHeap.Delete (pUserData) ;
160 }
161 #endif
162
163 #if 0
164 extern "C" void * hdmalloc (size_t sz) ;
165 extern "C" void hdfree (void * ptr) ;
166 extern "C" void hdmalloc_stats (void) ;
167 void * operator new( unsigned int cb )
168 {
169 void *pRet = hdmalloc((size_t)cb) ;
170 return pRet;
171 }
172
173 void operator delete(void *pUserData )
174 {
175 hdfree(pUserData) ;
176 }
177 #endif
178
179
180
181 /* Test driver for memory allocators */
182 /* Author: Paul Larson, palarson@microsoft.com */
183 #define MAX_THREADS 100
184 #define MAX_BLOCKS 1000000
185
186 int volatile stopflag=FALSE ;
187
188 struct lran2_st {
189 long x, y, v[97];
190 };
191
192 int TotalAllocs=0 ;
193
194 typedef struct thr_data {
195
196 int threadno ;
197 int NumBlocks ;
198 int seed ;
199
200 int min_size ;
201 int max_size ;
202
203 char * *array ;
204 int *blksize ;
205 int asize ;
206
207 int cAllocs ;
208 int cFrees ;
209 int cThreads ;
210 int cBytesAlloced ;
211
212 volatile int finished ;
213 struct lran2_st rgen ;
214
215 } thread_data;
216
217 void runthreads(long sleep_cnt, int min_threads, int max_threads,
218 int chperthread, int num_rounds) ;
219 void runloops(long sleep_cnt, int num_chunks ) ;
220 static void warmup(char **blkp, int num_chunks );
221 static void * exercise_heap( void *pinput) ;
222 static void lran2_init(struct lran2_st* d, long seed) ;
223 static long lran2(struct lran2_st* d) ;
224 ULONG CountReservedSpace() ;
225
226 char * blkp[MAX_BLOCKS] ;
227 int blksize[MAX_BLOCKS] ;
228 long seqlock=0 ;
229 struct lran2_st rgen ;
230 int min_size=10, max_size=500 ;
231 int num_threads ;
232 ULONG init_space ;
233
234 extern int cLockSleeps ;
235 extern int cAllocedChunks ;
236 extern int cAllocedSpace ;
237 extern int cUsedSpace ;
238 extern int cFreeChunks ;
239 extern int cFreeSpace ;
240
241 int cChecked=0 ;
242
243 #if defined(_WIN32)
244 extern "C" {
245 extern HANDLE crtheap;
246 };
247 #endif
248
249 int main (int argc, char *argv[])
250 {
251 #if defined(USE_LFH) && defined(_WIN32)
252 // Activate 'Low Fragmentation Heap'.
253 ULONG info = 2;
254 HeapSetInformation (GetProcessHeap(),
255 HeapCompatibilityInformation,
256 &info,
257 sizeof(info));
258 #endif
259 #if 0 // defined(__SVR4)
260 {
261 psinfo_t ps;
262 int pid = getpid();
263 char fname[255];
264 sprintf (fname, "/proc/%d/psinfo", pid);
265 // sprintf (fname, "/proc/self/ps");
266 FILE * f = fopen (fname, "rb");
267 printf ("opening %s\n", fname);
268 if (f) {
269 fread (&ps, sizeof(ps), 1, f);
270 printf ("resident set size = %dK\n", ps.pr_rssize);
271 fclose (f);
272 }
273 }
274 #endif
275
276 // char * dummy = new char[42];
277 //ReferenceLibHoard();
278 #if defined(_MT) || defined(_REENTRANT)
279 int min_threads, max_threads ;
280 int num_rounds ;
281 int chperthread ;
282 #endif
283 unsigned seed=12345 ;
284 int num_chunks=10000;
285 long sleep_cnt;
286
287 if (argc > 7) {
288 sleep_cnt = atol(argv[1]);
289 min_size = atoi(argv[2]);
290 max_size = atoi(argv[3]);
291 chperthread = atoi(argv[4]);
292 num_rounds = atoi(argv[5]);
293 seed = atoi(argv[6]);
294 max_threads = atoi(argv[7]);
295 min_threads = max_threads;
296 goto DoneWithInput;
297 }
298
299 #if defined(_MT) || defined(_REENTRANT)
300 //#ifdef _MT
301 //printf( "\nMulti-threaded test driver \n") ;
302 #else
303 //printf( "\nSingle-threaded test driver \n") ;
304 #endif
305 #ifdef CPP
306 //printf("C++ version (new and delete)\n") ;
307 #else
308 //printf("C version (malloc and free)\n") ;
309 #endif
310 //printf("runtime (sec): ") ;
311 scanf("%ld", &sleep_cnt);
312 //printf("chunk size (min,max): ") ;
313 scanf("%d %d", &min_size, &max_size ) ;
314 #if defined(_MT) || defined(_REENTRANT)
315 //#ifdef _MT
316 //printf("threads (min, max): ") ;
317 scanf("%d %d", &min_threads, &max_threads) ;
318 //printf("chunks/thread: ") ;
319 scanf("%d", &chperthread ) ;
320 //printf("no of rounds: ") ;
321 scanf("%d", &num_rounds ) ;
322 num_chunks = max_threads*chperthread ;
323 #else
324 //printf("no of chunks: ") ;
325 scanf("%d", &num_chunks ) ;
326 #endif
327 //printf("random seed: ") ;
328 scanf("%d", &seed) ;
329
330 DoneWithInput:
331
332 max_threads = atoi(argv[1]);
333 min_threads = max_threads;
334
335 if( num_chunks > MAX_BLOCKS ){
336 printf("Max %d chunks - exiting\n", MAX_BLOCKS ) ;
337 return(1) ;
338 }
339
340 #ifndef __WIN32__
341 #ifdef __SVR4
342 pthread_setconcurrency (max_threads);
343 #endif
344 #endif
345
346 lran2_init(&rgen, seed) ;
347 // init_space = CountReservedSpace() ;
348
349 #if defined(_MT) || defined(_REENTRANT)
350 //#ifdef _MT
351 runthreads(sleep_cnt, min_threads, max_threads, chperthread, num_rounds) ;
352 #else
353 runloops(sleep_cnt, num_chunks ) ;
354 #endif
355
356 #ifdef _DEBUG
357 _cputs("Hit any key to exit...") ; (void)_getch() ;
358 #endif
359
360 #if 0 // defined(__SVR4)
361 {
362 psinfo_t ps;
363 int pid = getpid();
364 char fname[255];
365 sprintf (fname, "/proc/%d/psinfo", pid);
366 // sprintf (fname, "/proc/self/ps");
367 FILE * f = fopen (fname, "rb");
368 printf ("opening %s\n", fname);
369 if (f) {
370 fread (&ps, sizeof(ps), 1, f);
371 printf ("resident set size = %dK\n", ps.pr_rssize);
372 fclose (f);
373 }
374 }
375 #endif
376
377 return(0) ;
378
379 } /* main */
380
381 void runloops(long sleep_cnt, int num_chunks )
382 {
383 int cblks ;
384 int victim ;
385 int blk_size ;
386 #ifdef __WIN32__
387 _LARGE_INTEGER ticks_per_sec, start_cnt, end_cnt;
388 #else
389 long ticks_per_sec ;
390 long start_cnt, end_cnt ;
391 #endif
392 app_int64 ticks ;
393 double duration ;
394 double reqd_space ;
395 //ULONG used_space ;
396 int sum_allocs=0 ;
397
398 QueryPerformanceFrequency( &ticks_per_sec ) ;
399 QueryPerformanceCounter( &start_cnt) ;
400
401 for( cblks=0; cblks<num_chunks; cblks++){
402 if (max_size == min_size) {
403 blk_size = min_size;
404 } else {
405 blk_size = min_size+lran2(&rgen)%(max_size - min_size) ;
406 }
407 #ifdef CPP
408 blkp[cblks] = new char[blk_size] ;
409 #else
410 blkp[cblks] = (char *) malloc(blk_size) ;
411 #endif
412 blksize[cblks] = blk_size ;
413 assert(blkp[cblks] != NULL) ;
414 }
415
416 while(TRUE){
417 for( cblks=0; cblks<num_chunks; cblks++){
418 victim = lran2(&rgen)%num_chunks ;
419 #ifdef CPP
420 delete blkp[victim] ;
421 #else
422 free(blkp[victim]) ;
423 #endif
424
425 if (max_size == min_size) {
426 blk_size = min_size;
427 } else {
428 blk_size = min_size+lran2(&rgen)%(max_size - min_size) ;
429 }
430 #ifdef CPP
431 blkp[victim] = new char[blk_size] ;
432 #else
433 blkp[victim] = (char *) malloc(blk_size) ;
434 #endif
435 blksize[victim] = blk_size ;
436 assert(blkp[victim] != NULL) ;
437 }
438 sum_allocs += num_chunks ;
439
440 QueryPerformanceCounter( &end_cnt) ;
441 #ifdef __WIN32__
442 ticks = end_cnt.QuadPart - start_cnt.QuadPart ;
443 duration = (double)ticks/ticks_per_sec.QuadPart ;
444 #else
445 ticks = end_cnt - start_cnt ;
446 duration = (double)ticks/ticks_per_sec ;
447 #endif
448
449 if( duration >= sleep_cnt) break ;
450 }
451 reqd_space = (0.5*(min_size+max_size)*num_chunks) ;
452 // used_space = CountReservedSpace() - init_space;
453
454 /*
455 printf("%6.3f", duration ) ;
456 printf("%8.0f", sum_allocs/duration ) ;
457 printf(" %6.3f %.3f", (double)used_space/(1024*1024), used_space/reqd_space) ;
458 printf("\n") ;
459 */
460
461 }
462
463
464 #if defined(_MT) || defined(_REENTRANT)
465 //#ifdef _MT
466 void runthreads(long sleep_cnt, int min_threads, int max_threads, int chperthread, int num_rounds)
467 {
468 thread_data de_area[MAX_THREADS] ;
469 thread_data *pdea;
470 int nperthread ;
471 int sum_threads ;
472 int sum_allocs ;
473 int sum_frees ;
474 double duration ;
475 #ifdef __WIN32__
476 _LARGE_INTEGER ticks_per_sec, start_cnt, end_cnt;
477 #else
478 long ticks_per_sec ;
479 long start_cnt, end_cnt ;
480 #endif
481 app_int64 ticks ;
482 double rate_1=0, rate_n ;
483 double reqd_space ;
484 ULONG used_space ;
485 int prevthreads ;
486 int i ;
487
488 QueryPerformanceFrequency( &ticks_per_sec ) ;
489
490 pdea = &de_area[0] ;
491 memset(&de_area[0], 0, sizeof(thread_data)) ;
492
493 prevthreads = 0 ;
494 for(num_threads=min_threads; num_threads <= max_threads; num_threads++ )
495 {
496
497 warmup(&blkp[prevthreads*chperthread], (num_threads-prevthreads)*chperthread );
498
499 nperthread = chperthread ;
500 stopflag = FALSE ;
501
502 for(i=0; i< num_threads; i++){
503 de_area[i].threadno = i+1 ;
504 de_area[i].NumBlocks = num_rounds*nperthread;
505 de_area[i].array = &blkp[i*nperthread] ;
506 de_area[i].blksize = &blksize[i*nperthread] ;
507 de_area[i].asize = nperthread ;
508 de_area[i].min_size = min_size ;
509 de_area[i].max_size = max_size ;
510 de_area[i].seed = lran2(&rgen) ; ;
511 de_area[i].finished = 0 ;
512 de_area[i].cAllocs = 0 ;
513 de_area[i].cFrees = 0 ;
514 de_area[i].cThreads = 0 ;
515 de_area[i].finished = FALSE ;
516 lran2_init(&de_area[i].rgen, de_area[i].seed) ;
517
518 #ifdef __WIN32__
519 _beginthread((void (__cdecl*)(void *)) exercise_heap, 0, &de_area[i]) ;
520 #else
521 _beginthread(exercise_heap, 0, &de_area[i]) ;
522 #endif
523
524 }
525
526 QueryPerformanceCounter( &start_cnt) ;
527
528 Sleep(sleep_cnt * 1000L) ;
529
530 stopflag = TRUE ;
531
532 for(i=0; i<num_threads; i++){
533 while( !de_area[i].finished ){
534 #ifdef __WIN32__
535 Sleep(1);
536 #elif defined(__SVR4)
537 thr_yield();
538 #else
539 sched_yield();
540 #endif
541 }
542 }
543
544
545 QueryPerformanceCounter( &end_cnt) ;
546
547 sum_frees = sum_allocs =0 ;
548 sum_threads = 0 ;
549 for(i=0;i< num_threads; i++){
550 sum_allocs += de_area[i].cAllocs ;
551 sum_frees += de_area[i].cFrees ;
552 sum_threads += de_area[i].cThreads ;
553 de_area[i].cAllocs = de_area[i].cFrees = 0;
554 }
555
556
557 #ifdef __WIN32__
558 ticks = end_cnt.QuadPart - start_cnt.QuadPart ;
559 duration = (double)ticks/ticks_per_sec.QuadPart ;
560 #else
561 ticks = end_cnt - start_cnt ;
562 duration = (double)ticks/ticks_per_sec ;
563 #endif
564
565 for( i=0; i<num_threads; i++){
566 if( !de_area[i].finished )
567 printf("Thread at %d not finished\n", i) ;
568 }
569
570
571 rate_n = sum_allocs/duration ;
572 if( rate_1 == 0){
573 rate_1 = rate_n ;
574 }
575
576 reqd_space = (0.5*(min_size+max_size)*num_threads*chperthread) ;
577 // used_space = CountReservedSpace() - init_space;
578 used_space = 0;
579
580 printf ("%8.0f operations per second, %2d threads.\n", sum_allocs / duration, sum_threads);
581
582 #if 0
583 printf("%2d ", num_threads ) ;
584 printf("%6.3f", duration ) ;
585 printf("%6.3f", rate_n/rate_1 ) ;
586 printf("%8.0f", sum_allocs/duration ) ;
587 printf(" %6.3f %.3f", (double)used_space/(1024*1024), used_space/reqd_space) ;
588 printf("\n") ;
589 #endif
590
591 Sleep(5000L) ; // wait 5 sec for old threads to die
592
593 prevthreads = num_threads ;
594
595 //printf ("Done sleeping...\n");
596
597 }
598 }
599
600
601 static void * exercise_heap( void *pinput)
602 {
603 thread_data *pdea;
604 int cblks=0 ;
605 int victim ;
606 long blk_size ;
607 int range ;
e5d8bae Cleaned up warnings for x86_64.
scschnei authored
608 volatile char ch = '0';
4567d2c Initial revision
scschnei authored
609
610 if( stopflag ) return 0;
611
612 pdea = (thread_data *)pinput ;
613 pdea->finished = FALSE ;
614 pdea->cThreads++ ;
615 range = pdea->max_size - pdea->min_size ;
616
617 /* allocate NumBlocks chunks of random size */
618 for( cblks=0; cblks<pdea->NumBlocks; cblks++){
619 victim = lran2(&pdea->rgen)%pdea->asize ;
c983b0a No idea.
scschnei authored
620 assert(victim >= 0 && victim < pdea->asize);
4567d2c Initial revision
scschnei authored
621 #ifdef CPP
622 delete pdea->array[victim] ;
623 #else
624 free(pdea->array[victim]) ;
625 #endif
626 pdea->cFrees++ ;
627
628 if (range == 0) {
629 blk_size = pdea->min_size;
630 } else {
631 blk_size = pdea->min_size+lran2(&pdea->rgen)%range ;
632 }
633 #ifdef CPP
634 pdea->array[victim] = new char[blk_size] ;
635 #else
636 pdea->array[victim] = (char *) malloc(blk_size) ;
637 #endif
638 pdea->blksize[victim] = blk_size ;
639 assert(pdea->array[victim] != NULL) ;
640
641 pdea->cAllocs++ ;
642
643 /* Write something! */
644 volatile char * chptr = ((char *) pdea->array[victim]);
645 *chptr++ = 'a';
646 volatile char ch = *((char *) pdea->array[victim]);
647 *chptr = 'b';
648
649 if( stopflag ) break ;
650 }
651
652 // printf("Thread %u terminating: %d allocs, %d frees\n",
653 // pdea->threadno, pdea->cAllocs, pdea->cFrees) ;
654 pdea->finished = TRUE ;
655
656 if( !stopflag ){
657 #ifdef __WIN32__
658 _beginthread((void (__cdecl*)(void *)) exercise_heap, 0, pdea) ;
659 #else
660 _beginthread(exercise_heap, 0, pdea) ;
661 #endif
662 } else {
663 //printf ("thread stopping.\n");
664 }
665 #ifndef _WIN32
666 pthread_exit (NULL);
667 #endif
668 return 0;
669 }
670
671 static void warmup(char **blkp, int num_chunks )
672 {
673 int cblks ;
674 int victim ;
675 int blk_size ;
676 LPVOID tmp ;
677
678
679 for( cblks=0; cblks<num_chunks; cblks++){
680 if (min_size == max_size) {
681 blk_size = min_size;
682 } else {
683 blk_size = min_size+lran2(&rgen)%(max_size-min_size) ;
684 }
685 #ifdef CPP
686 blkp[cblks] = new char[blk_size] ;
687 #else
688 blkp[cblks] = (char *) malloc(blk_size) ;
689 #endif
690
691 blksize[cblks] = blk_size ;
692 assert(blkp[cblks] != NULL) ;
693 }
694
695 /* generate a random permutation of the chunks */
696 for( cblks=num_chunks; cblks > 0 ; cblks--){
697 victim = lran2(&rgen)%cblks ;
698 tmp = blkp[victim] ;
699 blkp[victim] = blkp[cblks-1] ;
700 blkp[cblks-1] = (char *) tmp ;
701 }
702
703 for( cblks=0; cblks<4*num_chunks; cblks++){
704 victim = lran2(&rgen)%num_chunks ;
705 #ifdef CPP
706 delete blkp[victim] ;
707 #else
708 free(blkp[victim]) ;
709 #endif
710
711 if (max_size == min_size) {
712 blk_size = min_size;
713 } else {
714 blk_size = min_size+lran2(&rgen)%(max_size - min_size) ;
715 }
716 #ifdef CPP
717 blkp[victim] = new char[blk_size] ;
718 #else
719 blkp[victim] = (char *) malloc(blk_size) ;
720 #endif
721 blksize[victim] = blk_size ;
722 assert(blkp[victim] != NULL) ;
723 }
724 }
725 #endif // _MT
726
727 #ifdef __WIN32__
728 ULONG CountReservedSpace()
729 {
730 MEMORY_BASIC_INFORMATION info;
731 char *addr=NULL ;
732 ULONG size=0 ;
733
734 while( true){
735 VirtualQuery(addr, &info, sizeof(info));
736 switch( info.State){
737 case MEM_FREE:
738 case MEM_RESERVE:
739 break ;
740 case MEM_COMMIT:
741 size += info.RegionSize ;
742 break ;
743 }
744 addr += info.RegionSize ;
745 if( addr >= (char *)0x80000000UL ) break ;
746 }
747
748 return size ;
749
750 }
751 #endif
752
753 // =======================================================
754
755 /* lran2.h
756 * by Wolfram Gloger 1996.
757 *
758 * A small, portable pseudo-random number generator.
759 */
760
761 #ifndef _LRAN2_H
762 #define _LRAN2_H
763
764 #define LRAN2_MAX 714025l /* constants for portable */
765 #define IA 1366l /* random number generator */
766 #define IC 150889l /* (see e.g. `Numerical Recipes') */
767
768 //struct lran2_st {
769 // long x, y, v[97];
770 //};
771
772 static void
773 lran2_init(struct lran2_st* d, long seed)
774 {
775 long x;
776 int j;
777
778 x = (IC - seed) % LRAN2_MAX;
779 if(x < 0) x = -x;
780 for(j=0; j<97; j++) {
781 x = (IA*x + IC) % LRAN2_MAX;
782 d->v[j] = x;
783 }
784 d->x = (IA*x + IC) % LRAN2_MAX;
785 d->y = d->x;
786 }
787
788 static
789 long lran2(struct lran2_st* d)
790 {
791 int j = (d->y % 97);
792
793 d->y = d->v[j];
794 d->x = (IA*d->x + IC) % LRAN2_MAX;
795 d->v[j] = d->x;
796 return d->y;
797 }
798
799 #undef IA
800 #undef IC
801
802 #endif
Something went wrong with that request. Please try again.