Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
c0d7073fc4464f600cff6a8614445868863e8f9e
[simgrid.git] / examples / smpi / NAS / nas_common.c
1 /* Copyright (c) 2016. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6 #include "nas_common.h"
7
8 static double start[64], elapsed[64];
9
10 /* integer log base two. Return error is argument isn't a power of two or is less than or equal to zero */
11 int ilog2(int i)
12 {
13   int log2;
14   int exp2 = 1;
15   if (i <= 0) return(-1);
16
17   for (log2 = 0; log2 < 20; log2++) {
18     if (exp2 == i) return(log2);
19     exp2 *= 2;
20   }
21   return(-1);
22 }
23
24 /*  get_info(): Get parameters from command line */
25 void get_info(int argc, char *argv[], int *nprocsp, char *classp)
26 {
27   if (argc < 3) {
28     printf("Usage: %s (%d) nprocs class\n", argv[0], argc);
29     exit(1);
30   }
31
32   *nprocsp = atoi(argv[1]);
33   *classp = *argv[2];
34 }
35
36 /*  check_info(): Make sure command line data is ok for this benchmark */
37 void check_info(int type, int nprocs, char class)
38 {
39   int logprocs;
40
41   /* check number of processors */
42   if (nprocs <= 0) {
43     printf("setparams: Number of processors must be greater than zero\n");
44     exit(1);
45   }
46   switch(type) {
47   case IS:
48     logprocs = ilog2(nprocs);
49     if (logprocs < 0) {
50       printf("setparams: Number of processors must be a power of two (1,2,4,...) for this benchmark\n");
51       exit(1);
52     }
53     break;
54   case EP:
55   case DT:
56     break;
57   default:
58     /* never should have gotten this far with a bad name */
59     printf("setparams: (Internal Error) Benchmark type %d unknown to this program\n", type);
60     exit(1);
61   }
62
63   /* check class */
64   if (class != 'S' && class != 'W' && class != 'A' && class != 'B' && class != 'C' && class != 'D' && class != 'E') {
65     printf("setparams: Unknown benchmark class %c\n", class);
66     printf("setparams: Allowed classes are \"S\", \"W\", and \"A\" through \"E\"\n");
67     exit(1);
68   }
69
70   if (class == 'E' && (type == IS || type == DT)) {
71     printf("setparams: Benchmark class %c not defined for IS or DT\n", class);
72     exit(1);
73   }
74
75   if (class == 'D' && type == IS && nprocs < 4) {
76     printf("setparams: IS class D size cannot be run on less than 4 processors\n");
77     exit(1);
78   }
79 }
80
81 void timer_clear(int n)
82 {
83   elapsed[n] = 0.0;
84 }
85
86 void timer_start(int n)
87 {
88   start[n] = MPI_Wtime();
89 }
90
91 void timer_stop(int n)
92 {
93   elapsed[n] += MPI_Wtime() - start[n];
94 }
95
96 double timer_read(int n)
97 {
98   return elapsed[n];
99 }
100
101 double vranlc(int n, double x, double a, double *y)
102 {
103   int i;
104   uint64_t  i246m1=0x00003FFFFFFFFFFF;
105   uint64_t  LLx, Lx, La;
106   double d2m46;
107
108 // This doesn't work, because the compiler does the calculation in 32 bits and overflows. No standard way (without
109 // f90 stuff) to specifythat the rhs should be done in 64 bit arithmetic.
110 // parameter(i246m1=2**46-1)
111
112   d2m46=pow(0.5,46);
113
114   Lx = (uint64_t)x;
115   La = (uint64_t)a;
116   //fprintf(stdout,("================== Vranlc ================");
117   //fprintf(stdout,("Before Loop: Lx = " + Lx + ", La = " + La);
118   LLx = Lx;
119   for (i=0; i< n; i++) {
120     Lx   = Lx*La & i246m1 ;
121     LLx = Lx;
122     y[i] = d2m46 * (double)LLx;
123     /*
124      if(i == 0) {
125        fprintf(stdout,("After loop 0:");
126        fprintf(stdout,("Lx = " + Lx + ", La = " + La);
127        fprintf(stdout,("d2m46 = " + d2m46);
128        fprintf(stdout,("LLX(Lx) = " + LLX.doubleValue());
129        fprintf(stdout,("Y[0]" + y[0]);
130      }
131      */
132   }
133
134   x = (double)LLx;
135   /*
136   fprintf(stdout,("Change: Lx = " + Lx);
137   fprintf(stdout,("=============End   Vranlc ================");
138    */
139   return x;
140 }
141
142 /*
143  *    FUNCTION RANDLC (X, A)
144  *
145  *  This routine returns a uniform pseudorandom double precision number in the
146  *  range (0, 1) by using the linear congruential generator
147  *
148  *  x_{k+1} = a x_k  (mod 2^46)
149  *
150  *  where 0 < x_k < 2^46 and 0 < a < 2^46.  This scheme generates 2^44 numbers
151  *  before repeating.  The argument A is the same as 'a' in the above formula,
152  *  and X is the same as x_0.  A and X must be odd double precision integers
153  *  in the range (1, 2^46).  The returned value RANDLC is normalized to be
154  *  between 0 and 1, i.e. RANDLC = 2^(-46) * x_1.  X is updated to contain
155  *  the new seed x_1, so that subsequent calls to RANDLC using the same
156  *  arguments will generate a continuous sequence.
157  *
158  *  This routine should produce the same results on any computer with at least
159  *  48 mantissa bits in double precision floating point data.  On Cray systems,
160  *  double precision should be disabled.
161  *
162  *  David H. Bailey     October 26, 1990
163  *
164  *     IMPLICIT DOUBLE PRECISION (A-H, O-Z)
165  *     SAVE KS, R23, R46, T23, T46
166  *     DATA KS/0/
167  *
168  *  If this is the first call to RANDLC, compute R23 = 2 ^ -23, R46 = 2 ^ -46,
169  *  T23 = 2 ^ 23, and T46 = 2 ^ 46.  These are computed in loops, rather than
170  *  by merely using the ** operator, in order to insure that the results are
171  *  exact on all systems.  This code assumes that 0.5D0 is represented exactly.
172  */
173 double randlc(double *X, double*A)
174 {
175   static int        KS=0;
176   static double  R23, R46, T23, T46;
177   double    T1, T2, T3, T4;
178   double    A1, A2;
179   double    X1, X2;
180   double    Z;
181   int       i, j;
182
183   if (KS == 0) {
184     R23 = 1.0;
185     R46 = 1.0;
186     T23 = 1.0;
187     T46 = 1.0;
188
189     for (i=1; i<=23; i++) {
190       R23 = 0.50 * R23;
191       T23 = 2.0 * T23;
192     }
193     for (i=1; i<=46; i++) {
194       R46 = 0.50 * R46;
195       T46 = 2.0 * T46;
196     }
197     KS = 1;
198   }
199
200 /*  Break A into two parts such that A = 2^23 * A1 + A2 and set X = N.  */
201   T1 = R23 * *A;
202   j  = T1;
203   A1 = j;
204   A2 = *A - T23 * A1;
205
206 /*  Break X into two parts such that X = 2^23 * X1 + X2, compute
207     Z = A1 * X2 + A2 * X1  (mod 2^23), and then X = 2^23 * Z + A2 * X2  (mod 2^46). */
208   T1 = R23 * *X;
209   j  = T1;
210   X1 = j;
211   X2 = *X - T23 * X1;
212   T1 = A1 * X2 + A2 * X1;
213
214   j  = R23 * T1;
215   T2 = j;
216   Z = T1 - T23 * T2;
217   T3 = T23 * Z + A2 * X2;
218   j  = R46 * T3;
219   T4 = j;
220   *X = T3 - T46 * T4;
221   return(R46 * *X);
222 }
223
224 void c_print_results(const char *name, char class, int n1, int n2, int n3, int niter, int nprocs_compiled,
225                      int nprocs_total, double t, double mops, const char *optype, int passed_verification)
226 {
227   printf( "\n\n %s Benchmark Completed\n", name );
228   printf( " Class           =                        %c\n", class );
229
230   if( n3 == 0 ) {
231     long nn = n1;
232     if ( n2 != 0 ) nn *= n2;
233     printf( " Size            =             %12ld\n", nn );   /* as in IS */
234   } else
235     printf( " Size            =              %3dx %3dx %3d\n", n1,n2,n3 );
236
237   printf( " Iterations      =             %12d\n", niter );
238   printf( " Time in seconds =             %12.2f\n", t );
239   printf( " Total processes =             %12d\n", nprocs_total );
240
241   if ( nprocs_compiled != 0 )
242     printf( " Compiled procs  =             %12d\n", nprocs_compiled );
243
244   printf( " Mop/s total     =             %12.2f\n", mops );
245   printf( " Mop/s/process   =             %12.2f\n", mops/((float) nprocs_total) );
246   printf( " Operation type  = %24s\n", optype);
247
248   if( passed_verification )
249     printf( " Verification    =               SUCCESSFUL\n" );
250   else
251     printf( " Verification    =             UNSUCCESSFUL\n" );
252 }