Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
9a4fba590cc8c3f40150ba1393ccf44fb0234faf
[simgrid.git] / examples / smpi / NAS / sys / setparams.c
1 /* 
2  * This utility configures a NPB to be built for a specific number
3  * of nodes and a specific class. It creates a file "npbparams.h" 
4  * in the source directory. This file keeps state information about 
5  * which size of benchmark is currently being built (so that nothing
6  * if unnecessarily rebuilt) and defines (through PARAMETER statements)
7  * the number of nodes and class for which a benchmark is being built. 
8
9  * The utility takes 3 arguments: 
10  *       setparams benchmark-name nprocs class
11  *    benchmark-name is "sp", "bt", etc
12  *    nprocs is the number of processors to run on
13  *    class is the size of the benchmark
14  * These parameters are checked for the current benchmark. If they
15  * are invalid, this program prints a message and aborts. 
16  * If the parameters are ok, the current npbsize.h (actually just
17  * the first line) is read in. If the new parameters are the same as 
18  * the old, nothing is done, but an exit code is returned to force the
19  * user to specify (otherwise the make procedure succeeds but builds a
20  * binary of the wrong name).  Otherwise the file is rewritten. 
21  * Errors write a message (to stdout) and abort. 
22  * 
23  * This program makes use of two extra benchmark "classes"
24  * class "X" means an invalid specification. It is returned if
25  * there is an error parsing the config file. 
26  * class "U" is an external specification meaning "unknown class"
27  * 
28  * Unfortunately everything has to be case sensitive. This is
29  * because we can always convert lower to upper or v.v. but
30  * can't feed this information back to the makefile, so typing
31  * make CLASS=a and make CLASS=A will produce different binaries.
32  *
33  * 
34  */
35
36 #include <sys/types.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <ctype.h>
40 #include <string.h>
41 #include <time.h>
42
43 /*
44  * This is the master version number for this set of 
45  * NPB benchmarks. It is in an obscure place so people
46  * won't accidentally change it. 
47  */
48
49 #define VERSION "3.3"
50
51 /* controls verbose output from setparams */
52 /* #define VERBOSE */
53
54 #define FILENAME "npbparams.h"
55 #define DESC_LINE "c NPROCS = %d CLASS = %c\n"
56 #define BT_DESC_LINE "c NPROCS = %d CLASS = %c SUBTYPE = %s\n"
57 #define DEF_CLASS_LINE     "#define CLASS '%c'\n"
58 #define DEF_NUM_PROCS_LINE "#define NUM_PROCS %d\n"
59 #define FINDENT  "        "
60 #define CONTINUE "     > "
61
62 #ifdef FORTRAN_REC_SIZE
63 int fortran_rec_size = FORTRAN_REC_SIZE;
64 #else
65 int fortran_rec_size = 4;
66 #endif
67
68 void get_info(int argc, char *argv[], int *typep, int *nprocsp, char *classp,
69               int* subtypep);
70 void check_info(int type, int nprocs, char class);
71 void read_info(int type, int *nprocsp, char *classp, int *subtypep);
72 void write_info(int type, int nprocs, char class, int subtype);
73 void write_sp_info(FILE *fp, int nprocs, char class);
74 void write_bt_info(FILE *fp, int nprocs, char class, int io);
75 void write_lu_info(FILE *fp, int nprocs, char class);
76 void write_mg_info(FILE *fp, int nprocs, char class);
77 void write_cg_info(FILE *fp, int nprocs, char class);
78 void write_ft_info(FILE *fp, int nprocs, char class);
79 void write_ep_info(FILE *fp, int nprocs, char class);
80 void write_ep_info_C(FILE *fp, int nprocs, char class);  /* after C translation */
81 void write_is_info(FILE *fp, int nprocs, char class);
82 void write_dt_info(FILE *fp, int nprocs, char class);
83 void write_compiler_info(int type, FILE *fp);
84 void write_convertdouble_info(int type, FILE *fp);
85 void check_line(char *line, char *label, char *val);
86 int  check_include_line(char *line, char *filename);
87 void put_string(FILE *fp, char *name, char *val);
88 void put_def_string(FILE *fp, char *name, char *val);
89 void put_def_variable(FILE *fp, char *name, char *val);
90 int isqrt(int i);
91 int ilog2(int i);
92 int ipow2(int i);
93
94 enum benchmark_types {SP, BT, LU, MG, FT, IS, DT, EP, CG};
95 enum iotypes { NONE = 0, FULL, SIMPLE, EPIO, FORTRAN};
96
97 int main(int argc, char *argv[])
98 {
99   int nprocs, nprocs_old, type;
100   char class, class_old;
101   int subtype = -1, old_subtype = -1;
102   
103   /* Get command line arguments. Make sure they're ok. */
104   get_info(argc, argv, &type, &nprocs, &class, &subtype);
105   if (class != 'U') {
106 #ifdef VERBOSE
107     printf("setparams: For benchmark %s: number of processors = %d class = %c\n", 
108            argv[1], nprocs, class); 
109 #endif
110     check_info(type, nprocs, class);
111   }
112
113   /* Get old information. */
114   read_info(type, &nprocs_old, &class_old, &old_subtype);
115   if (class != 'U') {
116     if (class_old != 'X') {
117 #ifdef VERBOSE
118       printf("setparams:     old settings: number of processors = %d class = %c\n", 
119              nprocs_old, class_old); 
120 #endif
121     }
122   } else {
123     printf("setparams:\n\
124   *********************************************************************\n\
125   * You must specify NPROCS and CLASS to build this benchmark         *\n\
126   * For example, to build a class A benchmark for 4 processors, type  *\n\
127   *       make {benchmark-name} NPROCS=4 CLASS=A                      *\n\
128   *********************************************************************\n\n"); 
129
130     if (class_old != 'X') {
131 #ifdef VERBOSE
132       printf("setparams: Previous settings were CLASS=%c NPROCS=%d\n", 
133              class_old, nprocs_old); 
134 #endif
135     }
136     exit(1); /* exit on class==U */
137   }
138
139   /* Write out new information if it's different. */
140   if (nprocs != nprocs_old || class != class_old || subtype != old_subtype) {
141 #ifdef VERBOSE
142     printf("setparams: Writing %s\n", FILENAME); 
143 #endif
144     write_info(type, nprocs, class, subtype);
145   } else {
146 #ifdef VERBOSE
147     printf("setparams: Settings unchanged. %s unmodified\n", FILENAME); 
148 #endif
149   }
150
151   return 0;
152 }
153
154
155 /*
156  *  get_info(): Get parameters from command line 
157  */
158
159 void get_info(int argc, char *argv[], int *typep, int *nprocsp, char *classp,
160               int *subtypep) 
161 {
162
163   if (argc < 4) {
164     printf("Usage: %s (%d) benchmark-name nprocs class\n", argv[0], argc);
165     exit(1);
166   }
167
168   *nprocsp = atoi(argv[2]);
169
170   *classp = *argv[3];
171
172   if      (!strcmp(argv[1], "sp") || !strcmp(argv[1], "SP")) *typep = SP;
173   else if (!strcmp(argv[1], "ft") || !strcmp(argv[1], "FT")) *typep = FT;
174   else if (!strcmp(argv[1], "lu") || !strcmp(argv[1], "LU")) *typep = LU;
175   else if (!strcmp(argv[1], "mg") || !strcmp(argv[1], "MG")) *typep = MG;
176   else if (!strcmp(argv[1], "is") || !strcmp(argv[1], "IS")) *typep = IS;
177   else if (!strcmp(argv[1], "dt") || !strcmp(argv[1], "DT")) *typep = DT;
178   else if (!strcmp(argv[1], "ep") || !strcmp(argv[1], "EP")) *typep = EP;
179   else if (!strcmp(argv[1], "cg") || !strcmp(argv[1], "CG")) *typep = CG;
180   else if (!strcmp(argv[1], "bt") || !strcmp(argv[1], "BT")) {
181     *typep = BT;
182     if (argc != 5) {
183       /* printf("Usage: %s (%d) benchmark-name nprocs class\n", argv[0], argc); */
184       /* exit(1); */
185       *subtypep = NONE;
186     } else {
187       if (!strcmp(argv[4], "full") || !strcmp(argv[4], "FULL")) {
188         *subtypep = FULL;
189       } else if (!strcmp(argv[4], "simple") || !strcmp(argv[4], "SIMPLE")) {
190         *subtypep = SIMPLE;
191       } else if (!strcmp(argv[4], "epio") || !strcmp(argv[4], "EPIO")) {
192         *subtypep = EPIO;
193       } else if (!strcmp(argv[4], "fortran") || !strcmp(argv[4], "FORTRAN")) {
194         *subtypep = FORTRAN;
195       } else if (!strcmp(argv[4], "none") || !strcmp(argv[4], "NONE")) {
196         *subtypep = NONE;
197       } else {
198         printf("setparams: Error: unknown btio type %s\n", argv[4]);
199         exit(1);
200       }
201     }
202   } else {
203     printf("setparams: Error: unknown benchmark type %s\n", argv[1]);
204     exit(1);
205   }
206 }
207
208 /*
209  *  check_info(): Make sure command line data is ok for this benchmark 
210  */
211
212 void check_info(int type, int nprocs, char class) 
213 {
214   int rootprocs, logprocs; 
215
216   /* check number of processors */
217   if (nprocs <= 0) {
218     printf("setparams: Number of processors must be greater than zero\n");
219     exit(1);
220   }
221   switch(type) {
222
223   case SP:
224   case BT:
225     rootprocs = isqrt(nprocs);
226     if (rootprocs < 0) {
227       printf("setparams: Number of processors %d must be a square (1,4,9,...) for this benchmark", 
228               nprocs);
229       exit(1);
230     }
231     if (class == 'S' && nprocs > 16) {
232       printf("setparams: BT and SP sample sizes cannot be run on more\n");
233       printf("           than 16 processors because the cell size would be too small.\n");
234       exit(1);
235     }
236     break;
237
238   case CG:
239   case FT:
240   case MG:
241   case IS:
242   case LU:
243     logprocs = ilog2(nprocs);
244     if (logprocs < 0) {
245       printf("setparams: Number of processors must be a power of two (1,2,4,...) for this benchmark\n");
246       exit(1);
247     }
248
249     break;
250
251   case EP:
252   case DT:
253     break;
254
255   default:
256     /* never should have gotten this far with a bad name */
257     printf("setparams: (Internal Error) Benchmark type %d unknown to this program\n", type); 
258     exit(1);
259   }
260
261   /* check class */
262   if (class != 'S' && 
263       class != 'W' && 
264       class != 'A' && 
265       class != 'B' && 
266       class != 'C' && 
267       class != 'D' && 
268       class != 'E') {
269     printf("setparams: Unknown benchmark class %c\n", class); 
270     printf("setparams: Allowed classes are \"S\", \"W\", and \"A\" through \"E\"\n");
271     exit(1);
272   }
273
274   if (class == 'E' && (type == IS || type == DT)) {
275     printf("setparams: Benchmark class %c not defined for IS or DT\n", class);
276     exit(1);
277   }
278
279   if (class == 'D' && type == IS && nprocs < 4) {
280     printf("setparams: IS class D size cannot be run on less than 4 processors\n");
281     exit(1);
282   }
283 }
284
285
286 /* 
287  * read_info(): Read previous information from file. 
288  *              Not an error if file doesn't exist, because this
289  *              may be the first time we're running. 
290  *              Assumes the first line of the file is in a special
291  *              format that we understand (since we wrote it). 
292  */
293
294 void read_info(int type, int *nprocsp, char *classp, int *subtypep)
295 {
296   int nread = 0;
297   FILE *fp;
298   fp = fopen(FILENAME, "r");
299   if (fp == NULL) {
300 #ifdef VERBOSE
301     printf("setparams: INFO: configuration file %s does not exist (yet)\n", FILENAME); 
302 #endif
303     goto abort;
304   }
305   
306   /* first line of file contains info (fortran), first two lines (C) */
307
308   switch(type) {
309       case BT: {
310           char subtype_str[100];
311           nread = fscanf(fp, BT_DESC_LINE, nprocsp, classp, subtype_str);
312           if (nread != 3) {
313             if (nread != 2) {
314               printf("setparams: Error parsing config file %s. Ignoring previous settings\n", FILENAME);
315               goto abort;
316             }
317             *subtypep = 0;
318             break;
319           }
320           if (!strcmp(subtype_str, "full") || !strcmp(subtype_str, "FULL")) {
321                 *subtypep = FULL;
322           } else if (!strcmp(subtype_str, "simple") ||
323                      !strcmp(subtype_str, "SIMPLE")) {
324                 *subtypep = SIMPLE;
325           } else if (!strcmp(subtype_str, "epio") || !strcmp(subtype_str, "EPIO")) {
326                 *subtypep = EPIO;
327           } else if (!strcmp(subtype_str, "fortran") ||
328                      !strcmp(subtype_str, "FORTRAN")) {
329                 *subtypep = FORTRAN;
330           } else {
331                 *subtypep = -1;
332           }
333           break;
334       }
335
336       case SP:
337       case FT:
338       case MG:
339       case LU:
340       //case EP:
341       case CG:
342           nread = fscanf(fp, DESC_LINE, nprocsp, classp);
343           if (nread != 2) {
344             printf("setparams: Error line %d parsing config file %s. Ignoring previous settings\n", __LINE__,FILENAME);
345             goto abort;
346           }
347           break;
348       case IS:
349       case EP:
350       case DT:
351           nread = fscanf(fp, DEF_CLASS_LINE, classp);
352           nread += fscanf(fp, DEF_NUM_PROCS_LINE, nprocsp);
353           if (nread != 2) {
354             printf("setparams: Error line %d parsing config file %s. Ignoring previous settings\n", __LINE__,FILENAME);
355             goto abort;
356           }
357           break;
358       default:
359         /* never should have gotten this far with a bad name */
360         printf("setparams: (Internal Error) Benchmark type %d unknown to this program\n", type); 
361         exit(1);
362   }
363
364   fclose(fp);
365
366
367   return;
368
369  abort:
370   *nprocsp = -1;
371   *classp = 'X';
372   *subtypep = -1;
373   return;
374 }
375
376
377 /* 
378  * write_info(): Write new information to config file. 
379  *               First line is in a special format so we can read
380  *               it in again. Then comes a warning. The rest is all
381  *               specific to a particular benchmark. 
382  */
383
384 void write_info(int type, int nprocs, char class, int subtype) 
385 {
386   FILE *fp;
387   char *BT_TYPES[] = {"NONE", "FULL", "SIMPLE", "EPIO", "FORTRAN"};
388
389   fp = fopen(FILENAME, "w");
390   if (fp == NULL) {
391     printf("setparams: Can't open file %s for writing\n", FILENAME);
392     exit(1);
393   }
394
395   switch(type) {
396       case BT:
397           /* Write out the header */
398           if (subtype == -1 || subtype == 0) {
399             fprintf(fp, DESC_LINE, nprocs, class);
400           } else {
401             fprintf(fp, BT_DESC_LINE, nprocs, class, BT_TYPES[subtype]);
402           }
403           /* Print out a warning so bozos don't mess with the file */
404           fprintf(fp, "\
405 c  \n\
406 c  \n\
407 c  This file is generated automatically by the setparams utility.\n\
408 c  It sets the number of processors and the class of the NPB\n\
409 c  in this directory. Do not modify it by hand.\n\
410 c  \n");
411
412           break;
413         
414       case SP:
415       case FT:
416       case MG:
417       case LU:
418       //case EP:
419       case CG:
420           /* Write out the header */
421           fprintf(fp, DESC_LINE, nprocs, class);
422           /* Print out a warning so bozos don't mess with the file */
423           fprintf(fp, "\
424 c  \n\
425 c  \n\
426 c  This file is generated automatically by the setparams utility.\n\
427 c  It sets the number of processors and the class of the NPB\n\
428 c  in this directory. Do not modify it by hand.\n\
429 c  \n");
430
431           break;
432         case EP:
433       case IS:
434       case DT:
435           fprintf(fp, DEF_CLASS_LINE, class);
436           fprintf(fp, DEF_NUM_PROCS_LINE, nprocs);
437           fprintf(fp, "\
438 /*\n\
439    This file is generated automatically by the setparams utility.\n\
440    It sets the number of processors and the class of the NPB\n\
441    in this directory. Do not modify it by hand.   */\n\
442    \n");
443           break;
444       default:
445           printf("setparams: (Internal error): Unknown benchmark type %d\n", 
446                                                                          type);
447           exit(1);
448   }
449
450   /* Now do benchmark-specific stuff */
451   switch(type) {
452   case SP:
453     write_sp_info(fp, nprocs, class);
454     break;
455   case LU:
456     write_lu_info(fp, nprocs, class);
457     break;
458   case MG:
459     write_mg_info(fp, nprocs, class);
460     break;
461   case IS:
462     write_is_info(fp, nprocs, class);  
463     break;
464   case DT:
465     write_dt_info(fp, nprocs, class);  
466     break;
467   case FT:
468     write_ft_info(fp, nprocs, class);
469     break;
470   case EP:
471     //write_ep_info(fp, nprocs, class);
472     write_ep_info_C(fp, nprocs, class);
473     break;
474   case CG:
475     write_cg_info(fp, nprocs, class);
476     break;
477   case BT:
478     write_bt_info(fp, nprocs, class, subtype);
479     break;
480   default:
481     printf("setparams: (Internal error): Unknown benchmark type %d\n", type);
482     exit(1);
483   }
484   write_convertdouble_info(type, fp);
485   write_compiler_info(type, fp);
486   fclose(fp);
487   return;
488 }
489
490
491 /* 
492  * write_sp_info(): Write SP specific info to config file
493  */
494
495 void write_sp_info(FILE *fp, int nprocs, char class) 
496 {
497   int maxcells, problem_size, niter;
498   char *dt;
499   maxcells = isqrt(nprocs);
500   if      (class == 'S') { problem_size = 12;  dt = "0.015d0";   niter = 100; }
501   else if (class == 'W') { problem_size = 36;  dt = "0.0015d0";  niter = 400; }
502   else if (class == 'A') { problem_size = 64;  dt = "0.0015d0";  niter = 400; }
503   else if (class == 'B') { problem_size = 102; dt = "0.001d0";   niter = 400; }
504   else if (class == 'C') { problem_size = 162; dt = "0.00067d0"; niter = 400; }
505   else if (class == 'D') { problem_size = 408; dt = "0.00030d0"; niter = 500; }
506   else if (class == 'E') { problem_size = 1020; dt = "0.0001d0"; niter = 500; }
507   else {
508     printf("setparams: Internal error: invalid class %c\n", class);
509     exit(1);
510   }
511   fprintf(fp, "%sinteger maxcells, problem_size, niter_default\n", FINDENT);
512   fprintf(fp, "%sparameter (maxcells=%d, problem_size=%d, niter_default=%d)\n", 
513                FINDENT, maxcells, problem_size, niter);
514   fprintf(fp, "%sdouble precision dt_default\n", FINDENT);
515   fprintf(fp, "%sparameter (dt_default = %s)\n", FINDENT, dt);
516 }
517   
518 /* 
519  * write_bt_info(): Write BT specific info to config file
520  */
521
522 void write_bt_info(FILE *fp, int nprocs, char class, int io) 
523 {
524   int maxcells, problem_size, niter, wr_interval;
525   char *dt;
526   maxcells = isqrt(nprocs);
527   if      (class == 'S') { problem_size = 12;  dt = "0.010d0";    niter = 60;  }
528   else if (class == 'W') { problem_size = 24;  dt = "0.0008d0";   niter = 200; }
529   else if (class == 'A') { problem_size = 64;  dt = "0.0008d0";   niter = 200; }
530   else if (class == 'B') { problem_size = 102; dt = "0.0003d0";   niter = 200; }
531   else if (class == 'C') { problem_size = 162; dt = "0.0001d0";   niter = 200; }
532   else if (class == 'D') { problem_size = 408; dt = "0.00002d0";  niter = 250; }
533   else if (class == 'E') { problem_size = 1020; dt = "0.4d-5";    niter = 250; }
534   else {
535     printf("setparams: Internal error: invalid class %c\n", class);
536     exit(1);
537   }
538   wr_interval = 5;
539   fprintf(fp, "%sinteger maxcells, problem_size, niter_default\n", FINDENT);
540   fprintf(fp, "%sparameter (maxcells=%d, problem_size=%d, niter_default=%d)\n", 
541                FINDENT, maxcells, problem_size, niter);
542   fprintf(fp, "%sdouble precision dt_default\n", FINDENT);
543   fprintf(fp, "%sparameter (dt_default = %s)\n", FINDENT, dt);
544   fprintf(fp, "%sinteger wr_default\n", FINDENT);
545   fprintf(fp, "%sparameter (wr_default = %d)\n", FINDENT, wr_interval);
546   fprintf(fp, "%sinteger iotype\n", FINDENT);
547   fprintf(fp, "%sparameter (iotype = %d)\n", FINDENT, io);
548   if (io) {
549     fprintf(fp, "%scharacter*(*) filenm\n", FINDENT);
550     switch (io) {
551         case FULL:
552             fprintf(fp, "%sparameter (filenm = 'btio.full.out')\n", FINDENT);
553             break;
554         case SIMPLE:
555             fprintf(fp, "%sparameter (filenm = 'btio.simple.out')\n", FINDENT);
556             break;
557         case EPIO:
558             fprintf(fp, "%sparameter (filenm = 'btio.epio.out')\n", FINDENT);
559             break;
560         case FORTRAN:
561             fprintf(fp, "%sparameter (filenm = 'btio.fortran.out')\n", FINDENT);
562             fprintf(fp, "%sinteger fortran_rec_sz\n", FINDENT);
563             fprintf(fp, "%sparameter (fortran_rec_sz = %d)\n",
564                     FINDENT, fortran_rec_size);
565             break;
566         default:
567             break;
568     }
569   }
570 }
571   
572
573
574 /* 
575  * write_lu_info(): Write SP specific info to config file
576  */
577
578 void write_lu_info(FILE *fp, int nprocs, char class) 
579 {
580   int isiz1, isiz2, itmax, inorm, problem_size;
581   int xdiv, ydiv; /* number of cells in x and y direction */
582   char *dt_default;
583
584   if      (class == 'S') { problem_size = 12;  dt_default = "0.5d0";  itmax = 50; }
585   else if (class == 'W') { problem_size = 33;  dt_default = "1.5d-3"; itmax = 300; }
586   else if (class == 'A') { problem_size = 64;  dt_default = "2.0d0";  itmax = 250; }
587   else if (class == 'B') { problem_size = 102; dt_default = "2.0d0";  itmax = 250; }
588   else if (class == 'C') { problem_size = 162; dt_default = "2.0d0";  itmax = 250; }
589   else if (class == 'D') { problem_size = 408; dt_default = "1.0d0";  itmax = 300; }
590   else if (class == 'E') { problem_size = 1020; dt_default = "0.5d0"; itmax = 300; }
591   else {
592     printf("setparams: Internal error: invalid class %c\n", class);
593     exit(1);
594   }
595   inorm = itmax;
596   xdiv = ydiv = ilog2(nprocs)/2;
597   if (xdiv+ydiv != ilog2(nprocs)) xdiv += 1;
598   xdiv = ipow2(xdiv); ydiv = ipow2(ydiv);
599   isiz1 = problem_size/xdiv; if (isiz1*xdiv < problem_size) isiz1++;
600   isiz2 = problem_size/ydiv; if (isiz2*ydiv < problem_size) isiz2++;
601   
602
603   fprintf(fp, "\nc number of nodes for which this version is compiled\n");
604   fprintf(fp, "%sinteger nnodes_compiled\n", FINDENT);
605   fprintf(fp, "%sparameter (nnodes_compiled = %d)\n", FINDENT, nprocs);
606
607   fprintf(fp, "\nc full problem size\n");
608   fprintf(fp, "%sinteger isiz01, isiz02, isiz03\n", FINDENT);
609   fprintf(fp, "%sparameter (isiz01=%d, isiz02=%d, isiz03=%d)\n", 
610           FINDENT, problem_size, problem_size, problem_size);
611
612   fprintf(fp, "\nc sub-domain array size\n");
613   fprintf(fp, "%sinteger isiz1, isiz2, isiz3\n", FINDENT);
614   fprintf(fp, "%sparameter (isiz1=%d, isiz2=%d, isiz3=isiz03)\n", 
615                FINDENT, isiz1, isiz2);
616
617   fprintf(fp, "\nc number of iterations and how often to print the norm\n");
618   fprintf(fp, "%sinteger itmax_default, inorm_default\n", FINDENT);
619   fprintf(fp, "%sparameter (itmax_default=%d, inorm_default=%d)\n", 
620           FINDENT, itmax, inorm);
621
622   fprintf(fp, "%sdouble precision dt_default\n", FINDENT);
623   fprintf(fp, "%sparameter (dt_default = %s)\n", FINDENT, dt_default);
624   
625 }
626
627 /* 
628  * write_mg_info(): Write MG specific info to config file
629  */
630
631 void write_mg_info(FILE *fp, int nprocs, char class) 
632 {
633   int problem_size, nit, log2_size, log2_nprocs, lt_default, lm;
634   int ndim1, ndim2, ndim3;
635   if      (class == 'S') { problem_size = 32;   nit = 4; }
636   else if (class == 'W') { problem_size = 128;  nit = 4; }
637   else if (class == 'A') { problem_size = 256;  nit = 4; }
638   else if (class == 'B') { problem_size = 256;  nit = 20; }
639   else if (class == 'C') { problem_size = 512;  nit = 20; }
640   else if (class == 'D') { problem_size = 1024; nit = 50; }
641   else if (class == 'E') { problem_size = 2048; nit = 50; }
642   else {
643     printf("setparams: Internal error: invalid class type %c\n", class);
644     exit(1);
645   }
646   log2_size = ilog2(problem_size);
647   log2_nprocs = ilog2(nprocs);
648   /* lt is log of largest total dimension */
649   lt_default = log2_size;
650   /* log of log of maximum dimension on a node */
651   lm = log2_size - log2_nprocs/3;
652   ndim1 = lm;
653   ndim3 = log2_size - (log2_nprocs+2)/3;
654   ndim2 = log2_size - (log2_nprocs+1)/3;
655
656   fprintf(fp, "%sinteger nprocs_compiled\n", FINDENT);
657   fprintf(fp, "%sparameter (nprocs_compiled = %d)\n", FINDENT, nprocs);
658   fprintf(fp, "%sinteger nx_default, ny_default, nz_default\n", FINDENT);
659   fprintf(fp, "%sparameter (nx_default=%d, ny_default=%d, nz_default=%d)\n", 
660           FINDENT, problem_size, problem_size, problem_size);
661   fprintf(fp, "%sinteger nit_default, lm, lt_default\n", FINDENT);
662   fprintf(fp, "%sparameter (nit_default=%d, lm = %d, lt_default=%d)\n", 
663           FINDENT, nit, lm, lt_default);
664   fprintf(fp, "%sinteger debug_default\n", FINDENT);
665   fprintf(fp, "%sparameter (debug_default=%d)\n", FINDENT, 0);
666   fprintf(fp, "%sinteger ndim1, ndim2, ndim3\n", FINDENT);
667   fprintf(fp, "%sparameter (ndim1 = %d, ndim2 = %d, ndim3 = %d)\n", 
668           FINDENT, ndim1, ndim2, ndim3);
669 }
670
671
672 /* 
673  * write_dt_info(): Write DT specific info to config file
674  */
675
676 void write_dt_info(FILE *fp, int nprocs, char class) 
677 {
678   int num_samples,deviation,num_sources;
679   if      (class == 'S') { num_samples=1728; deviation=128; num_sources=4; }
680   else if (class == 'W') { num_samples=1728*8; deviation=128*2; num_sources=4*2; }
681   else if (class == 'A') { num_samples=1728*64; deviation=128*4; num_sources=4*4; }
682   else if (class == 'B') { num_samples=1728*512; deviation=128*8; num_sources=4*8; }
683   else if (class == 'C') { num_samples=1728*4096; deviation=128*16; num_sources=4*16; }
684   else if (class == 'D') { num_samples=1728*4096*8; deviation=128*32; num_sources=4*32; }
685   else {
686     printf("setparams: Internal error: invalid class type %c\n", class);
687     exit(1);
688   }
689   fprintf(fp, "#define NUM_SAMPLES %d\n", num_samples);
690   fprintf(fp, "#define STD_DEVIATION %d\n", deviation);
691   fprintf(fp, "#define NUM_SOURCES %d\n", num_sources);
692 }
693
694 /* 
695  * write_is_info(): Write IS specific info to config file
696  */
697
698 void write_is_info(FILE *fp, int nprocs, char class) 
699 {
700   if( class != 'S' &&
701       class != 'W' &&
702       class != 'A' &&
703       class != 'B' &&
704       class != 'C' &&
705       class != 'D' )
706   {
707     printf("setparams: Internal error: invalid class type %c\n", class);
708     exit(1);
709   }
710 }
711
712 /* 
713  * write_cg_info(): Write CG specific info to config file
714  */
715
716 void write_cg_info(FILE *fp, int nprocs, char class) 
717 {
718   int na,nonzer,niter;
719   char *shift,*rcond="1.0d-1";
720   char *shiftS="10.",
721        *shiftW="12.",
722        *shiftA="20.",
723        *shiftB="60.",
724        *shiftC="110.",
725        *shiftD="500.",
726        *shiftE="1.5d3";
727
728   int num_proc_cols, num_proc_rows;
729
730
731   if( class == 'S' )
732   { na=1400;    nonzer=7;  niter=15;  shift=shiftS; }
733   else if( class == 'W' )
734   { na=7000;    nonzer=8;  niter=15;  shift=shiftW; }
735   else if( class == 'A' )
736   { na=14000;   nonzer=11; niter=15;  shift=shiftA; }
737   else if( class == 'B' )
738   { na=75000;   nonzer=13; niter=75;  shift=shiftB; }
739   else if( class == 'C' )
740   { na=150000;  nonzer=15; niter=75;  shift=shiftC; }
741   else if( class == 'D' )
742   { na=1500000; nonzer=21; niter=100; shift=shiftD; }
743   else if( class == 'E' )
744   { na=9000000; nonzer=26; niter=100; shift=shiftE; }
745   else
746   {
747     printf("setparams: Internal error: invalid class type %c\n", class);
748     exit(1);
749   }
750   fprintf( fp, "%sinteger            na, nonzer, niter\n", FINDENT );
751   fprintf( fp, "%sdouble precision   shift, rcond\n", FINDENT );
752   fprintf( fp, "%sparameter(  na=%d,\n", FINDENT, na );
753   fprintf( fp, "%s             nonzer=%d,\n", CONTINUE, nonzer );
754   fprintf( fp, "%s             niter=%d,\n", CONTINUE, niter );
755   fprintf( fp, "%s             shift=%s,\n", CONTINUE, shift );
756   fprintf( fp, "%s             rcond=%s )\n", CONTINUE, rcond );
757
758
759   num_proc_cols = num_proc_rows = ilog2(nprocs)/2;
760   if (num_proc_cols+num_proc_rows != ilog2(nprocs)) num_proc_cols += 1;
761   num_proc_cols = ipow2(num_proc_cols); num_proc_rows = ipow2(num_proc_rows);
762   
763   fprintf( fp, "\nc number of nodes for which this version is compiled\n" );
764   fprintf( fp, "%sinteger    nnodes_compiled\n", FINDENT );
765   fprintf( fp, "%sparameter( nnodes_compiled = %d)\n", FINDENT, nprocs );
766   fprintf( fp, "%sinteger    num_proc_cols, num_proc_rows\n", FINDENT );
767   fprintf( fp, "%sparameter( num_proc_cols=%d, num_proc_rows=%d )\n", 
768                                                           FINDENT,
769                                                           num_proc_cols,
770                                                           num_proc_rows );
771 }
772
773
774 /* 
775  * write_ft_info(): Write FT specific info to config file
776  */
777
778 void write_ft_info(FILE *fp, int nprocs, char class) 
779 {
780   /* easiest way (given the way the benchmark is written)
781    * is to specify log of number of grid points in each
782    * direction m1, m2, m3. nt is the number of iterations
783    */
784   int nx, ny, nz, maxdim, niter;
785   if      (class == 'S') { nx = 64;   ny = 64;   nz = 64;   niter = 6;}
786   else if (class == 'W') { nx = 128;  ny = 128;  nz = 32;   niter = 6;}
787   else if (class == 'A') { nx = 256;  ny = 256;  nz = 128;  niter = 6;}
788   else if (class == 'B') { nx = 512;  ny = 256;  nz = 256;  niter =20;}
789   else if (class == 'C') { nx = 512;  ny = 512;  nz = 512;  niter =20;}
790   else if (class == 'D') { nx = 2048; ny = 1024; nz = 1024; niter =25;}
791   else if (class == 'E') { nx = 4096; ny = 2048; nz = 2048; niter =25;}
792   else {
793     printf("setparams: Internal error: invalid class type %c\n", class);
794     exit(1);
795   }
796   maxdim = nx;
797   if (ny > maxdim) maxdim = ny;
798   if (nz > maxdim) maxdim = nz;
799   fprintf(fp, "%sinteger nx, ny, nz, maxdim, niter_default, ntdivnp, np_min\n", FINDENT);
800   fprintf(fp, "%sparameter (nx=%d, ny=%d, nz=%d, maxdim=%d)\n", 
801           FINDENT, nx, ny, nz, maxdim);
802   fprintf(fp, "%sparameter (niter_default=%d)\n", FINDENT, niter);
803   fprintf(fp, "%sparameter (np_min = %d)\n", FINDENT, nprocs);
804   fprintf(fp, "%sparameter (ntdivnp=((nx*ny)/np_min)*nz)\n", FINDENT);
805   fprintf(fp, "%sdouble precision ntotal_f\n", FINDENT);
806   fprintf(fp, "%sparameter (ntotal_f=1.d0*nx*ny*nz)\n", FINDENT);
807 }
808
809 /*
810  * write_ep_info(): Write EP specific info to config file
811  */
812
813 void write_ep_info(FILE *fp, int nprocs, char class)
814 {
815   /* easiest way (given the way the benchmark is written)
816    * is to specify log of number of grid points in each
817    * direction m1, m2, m3. nt is the number of iterations
818    */
819   int m;
820   if      (class == 'S') { m = 24; }
821   else if (class == 'W') { m = 25; }
822   else if (class == 'A') { m = 28; }
823   else if (class == 'B') { m = 30; }
824   else if (class == 'C') { m = 32; }
825   else if (class == 'D') { m = 36; }
826   else if (class == 'E') { m = 40; }
827   else {
828     printf("setparams: Internal error: invalid class type %c\n", class);
829     exit(1);
830   }
831   /* number of processors given by "npm" */
832
833
834   fprintf(fp, "%scharacter class\n",FINDENT);
835   fprintf(fp, "%sparameter (class =\'%c\')\n",
836                   FINDENT, class);
837   fprintf(fp, "%sinteger m, npm\n", FINDENT);
838   fprintf(fp, "%sparameter (m=%d, npm=%d)\n",
839           FINDENT, m, nprocs);
840 }
841 /*
842  * write_ep_info_C(): Write EP specific info to config file
843  */
844
845
846 void write_ep_info_C(FILE *fp, int nprocs, char class)
847 {
848   /* easiest way (given the way the benchmark is written)
849    * is to specify log of number of grid points in each
850    * direction m1, m2, m3. nt is the number of iterations
851    */
852   int m;
853   if      (class == 'S') { m = 24; }
854   else if (class == 'W') { m = 25; }
855   else if (class == 'A') { m = 28; }
856   else if (class == 'B') { m = 30; }
857   else if (class == 'C') { m = 32; }
858   else if (class == 'D') { m = 36; }
859   else if (class == 'E') { m = 40; }
860   else {
861     printf("setparams: Internal error: invalid class type %c\n", class);
862     exit(1);
863   }
864   /* number of processors given by "npm" */
865
866
867   fprintf(fp, "%schar *_class=\"%c\";\n",FINDENT,class);
868   fprintf(fp, "%sint m=%d;\n", FINDENT,m);
869   fprintf(fp, "%sint npm=%d;\n", FINDENT,nprocs);
870 }
871 /* 
872  * This is a gross hack to allow the benchmarks to 
873  * print out how they were compiled. Various other ways
874  * of doing this have been tried and they all fail on
875  * some machine - due to a broken "make" program, or
876  * F77 limitations, of whatever. Hopefully this will
877  * always work because it uses very portable C. Unfortunately
878  * it relies on parsing the make.def file - YUK. 
879  * If your machine doesn't have <string.h> or <ctype.h>, happy hacking!
880  * 
881  */
882
883 #define VERBOSE
884 #define LL 400
885 #include <stdio.h>
886 #define DEFFILE "../config/make.def"
887 #define DEFAULT_MESSAGE "(none)"
888 FILE *deffile;
889 void write_compiler_info(int type, FILE *fp)
890 {
891   char line[LL];
892   char mpif77[LL], flink[LL], fmpi_lib[LL], fmpi_inc[LL], fflags[LL], flinkflags[LL];
893   char compiletime[LL], randfile[LL];
894   char mpicc[LL], cflags[LL], clink[LL], clinkflags[LL],
895        cmpi_lib[LL], cmpi_inc[LL];
896   struct tm *tmp;
897   time_t t;
898   deffile = fopen(DEFFILE, "r");
899   if (deffile == NULL) {
900     printf("\n\
901 setparams: File %s doesn't exist. To build the NAS benchmarks\n\
902            you need to create is according to the instructions\n\
903            in the README in the main directory and comments in \n\
904            the file config/make.def.template\n", DEFFILE);
905     exit(1);
906   }
907   strcpy(mpif77, DEFAULT_MESSAGE);
908   strcpy(flink, DEFAULT_MESSAGE);
909   strcpy(fmpi_lib, DEFAULT_MESSAGE);
910   strcpy(fmpi_inc, DEFAULT_MESSAGE);
911   strcpy(fflags, DEFAULT_MESSAGE);
912   strcpy(flinkflags, DEFAULT_MESSAGE);
913   strcpy(randfile, DEFAULT_MESSAGE);
914   strcpy(mpicc, DEFAULT_MESSAGE);
915   strcpy(cflags, DEFAULT_MESSAGE);
916   strcpy(clink, DEFAULT_MESSAGE);
917   strcpy(clinkflags, DEFAULT_MESSAGE);
918   strcpy(cmpi_lib, DEFAULT_MESSAGE);
919   strcpy(cmpi_inc, DEFAULT_MESSAGE);
920
921   while (fgets(line, LL, deffile) != NULL) {
922     if (*line == '#') continue;
923     /* yes, this is inefficient. but it's simple! */
924     check_line(line, "MPIF77", mpif77);
925     check_line(line, "FLINK", flink);
926     check_line(line, "FMPI_LIB", fmpi_lib);
927     check_line(line, "FMPI_INC", fmpi_inc);
928     check_line(line, "FFLAGS", fflags);
929     check_line(line, "FLINKFLAGS", flinkflags);
930     check_line(line, "RAND", randfile);
931     check_line(line, "MPICC", mpicc);
932     check_line(line, "CFLAGS", cflags);
933     check_line(line, "CLINK", clink);
934     check_line(line, "CLINKFLAGS", clinkflags);
935     check_line(line, "CMPI_LIB", cmpi_lib);
936     check_line(line, "CMPI_INC", cmpi_inc);
937     /* if the dummy library is used by including make.dummy, we set the
938        Fortran and C paths to libraries and headers accordingly     */
939     if(check_include_line(line, "../config/make.dummy")) {
940        strcpy(fmpi_lib, "-L../MPI_dummy -lmpi");
941        strcpy(fmpi_inc, "-I../MPI_dummy");
942        strcpy(cmpi_lib, "-L../MPI_dummy -lmpi");
943        strcpy(cmpi_inc, "-I../MPI_dummy");
944     }
945   }
946
947   
948   (void) time(&t);
949   tmp = localtime(&t);
950   (void) strftime(compiletime, (size_t)LL, "%d %b %Y", tmp);
951
952
953   switch(type) {
954       case FT:
955       case SP:
956       case BT:
957       case MG:
958       case LU:
959       //case EP:
960       case CG:
961           put_string(fp, "compiletime", compiletime);
962           put_string(fp, "npbversion", VERSION);
963           put_string(fp, "cs1", mpif77);
964           put_string(fp, "cs2", flink);
965           put_string(fp, "cs3", fmpi_lib);
966           put_string(fp, "cs4", fmpi_inc);
967           put_string(fp, "cs5", fflags);
968           put_string(fp, "cs6", flinkflags);
969           put_string(fp, "cs7", randfile);
970           break;
971       case IS:
972       case EP:
973       case DT:
974           put_def_string(fp, "COMPILETIME", compiletime);
975           put_def_string(fp, "NPBVERSION", VERSION);
976           put_def_string(fp, "MPICC", mpicc);
977           put_def_string(fp, "CFLAGS", cflags);
978           put_def_string(fp, "CLINK", clink);
979           put_def_string(fp, "CLINKFLAGS", clinkflags);
980           put_def_string(fp, "CMPI_LIB", cmpi_lib);
981           put_def_string(fp, "CMPI_INC", cmpi_inc);
982           break;
983       default:
984           printf("setparams: (Internal error): Unknown benchmark type %d\n", 
985                                                                          type);
986           exit(1);
987   }
988
989 }
990
991 void check_line(char *line, char *label, char *val)
992 {
993   char *original_line;
994   int n;
995   original_line = line;
996   /* compare beginning of line and label */
997   while (*label != '\0' && *line == *label) {
998     line++; label++; 
999   }
1000   /* if *label is not EOS, we must have had a mismatch */
1001   if (*label != '\0') return;
1002   /* if *line is not a space, actual label is longer than test label */
1003   if (!isspace(*line) && *line != '=') return ; 
1004   /* skip over white space */
1005   while (isspace(*line)) line++;
1006   /* next char should be '=' */
1007   if (*line != '=') return;
1008   /* skip over white space */
1009   while (isspace(*++line));
1010   /* if EOS, nothing was specified */
1011   if (*line == '\0') return;
1012   /* finally we've come to the value */
1013   strcpy(val, line);
1014   /* chop off the newline at the end */
1015   n = strlen(val)-1;
1016   if (n >= 0 && val[n] == '\n')
1017     val[n--] = '\0';
1018   if (n >= 0 && val[n] == '\r')
1019     val[n--] = '\0';
1020   /* treat continuation */
1021   while (val[n] == '\\' && fgets(original_line, LL, deffile)) {
1022      line = original_line;
1023      while (isspace(*line)) line++;
1024      if (isspace(*original_line)) val[n++] = ' ';
1025      while (*line && *line != '\n' && *line != '\r' && n < LL-1)
1026        val[n++] = *line++;
1027      val[n] = '\0';
1028      n--;
1029   }
1030 /*  if (val[strlen(val) - 1] == '\\') {
1031     printf("\n\
1032 setparams: Error in file make.def. Because of the way in which\n\
1033            command line arguments are incorporated into the\n\
1034            executable benchmark, you can't have any continued\n\
1035            lines in the file make.def, that is, lines ending\n\
1036            with the character \"\\\". Although it may be ugly, \n\
1037            you should be able to reformat without continuation\n\
1038            lines. The offending line is\n\
1039   %s\n", original_line);
1040     exit(1);
1041   } */
1042 }
1043
1044 int check_include_line(char *line, char *filename)
1045 {
1046   char *include_string = "include";
1047   /* compare beginning of line and "include" */
1048   while (*include_string != '\0' && *line == *include_string) {
1049     line++; include_string++; 
1050   }
1051   /* if *include_string is not EOS, we must have had a mismatch */
1052   if (*include_string != '\0') return(0);
1053   /* if *line is not a space, first word is not "include" */
1054   if (!isspace(*line)) return(0); 
1055   /* skip over white space */
1056   while (isspace(*++line));
1057   /* if EOS, nothing was specified */
1058   if (*line == '\0') return(0);
1059   /* next keyword should be name of include file in *filename */
1060   while (*filename != '\0' && *line == *filename) {
1061     line++; filename++; 
1062   }  
1063   if (*filename != '\0' || 
1064       (*line != ' ' && *line != '\0' && *line !='\n')) return(0);
1065   else return(1);
1066 }
1067
1068
1069 #define MAXL 46
1070 void put_string(FILE *fp, char *name, char *val)
1071 {
1072   int len;
1073   len = strlen(val);
1074   if (len > MAXL) {
1075     val[MAXL] = '\0';
1076     val[MAXL-1] = '.';
1077     val[MAXL-2] = '.';
1078     val[MAXL-3] = '.';
1079     len = MAXL;
1080   }
1081   fprintf(fp, "%scharacter*%d %s\n", FINDENT, len, name);
1082   fprintf(fp, "%sparameter (%s=\'%s\')\n", FINDENT, name, val);
1083 }
1084
1085 /* NOTE: is the ... stuff necessary in C? */
1086 void put_def_string(FILE *fp, char *name, char *val)
1087 {
1088   int len;
1089   len = strlen(val);
1090   if (len > MAXL) {
1091     val[MAXL] = '\0';
1092     val[MAXL-1] = '.';
1093     val[MAXL-2] = '.';
1094     val[MAXL-3] = '.';
1095     len = MAXL;
1096   }
1097   fprintf(fp, "#define %s \"%s\"\n", name, val);
1098 }
1099
1100 void put_def_variable(FILE *fp, char *name, char *val)
1101 {
1102   int len;
1103   len = strlen(val);
1104   if (len > MAXL) {
1105     val[MAXL] = '\0';
1106     val[MAXL-1] = '.';
1107     val[MAXL-2] = '.';
1108     val[MAXL-3] = '.';
1109     len = MAXL;
1110   }
1111   fprintf(fp, "#define %s %s\n", name, val);
1112 }
1113
1114
1115
1116 #if 0
1117
1118 /* this version allows arbitrarily long lines but 
1119  * some compilers don't like that and they're rarely
1120  * useful 
1121  */
1122
1123 #define LINELEN 65
1124 void put_string(FILE *fp, char *name, char *val)
1125 {
1126   int len, nlines, pos, i;
1127   char line[100];
1128   len = strlen(val);
1129   nlines = len/LINELEN;
1130   if (nlines*LINELEN < len) nlines++;
1131   fprintf(fp, "%scharacter*%d %s\n", FINDENT, nlines*LINELEN, name);
1132   fprintf(fp, "%sparameter (%s = \n", FINDENT, name);
1133   for (i = 0; i < nlines; i++) {
1134     pos = i*LINELEN;
1135     if (i == 0) fprintf(fp, "%s\'", CONTINUE);
1136     else        fprintf(fp, "%s", CONTINUE);
1137     /* number should be same as LINELEN */
1138     fprintf(fp, "%.65s", val+pos);
1139     if (i == nlines-1) fprintf(fp, "\')\n");
1140     else             fprintf(fp, "\n");
1141   }
1142 }
1143
1144 #endif
1145
1146
1147 /* integer square root. Return error if argument isn't
1148  * a perfect square or is less than or equal to zero 
1149  */
1150
1151 int isqrt(int i)
1152 {
1153   int root, square;
1154   if (i <= 0) return(-1);
1155   square = 0;
1156   for (root = 1; square <= i; root++) {
1157     square = root*root;
1158     if (square == i) return(root);
1159   }
1160   return(-1);
1161 }
1162   
1163
1164 /* integer log base two. Return error is argument isn't
1165  * a power of two or is less than or equal to zero 
1166  */
1167
1168 int ilog2(int i)
1169 {
1170   int log2;
1171   int exp2 = 1;
1172   if (i <= 0) return(-1);
1173
1174   for (log2 = 0; log2 < 20; log2++) {
1175     if (exp2 == i) return(log2);
1176     exp2 *= 2;
1177   }
1178   return(-1);
1179 }
1180
1181 int ipow2(int i)
1182 {
1183   int pow2 = 1;
1184   if (i < 0) return(-1);
1185   if (i == 0) return(1);
1186   while(i--) pow2 *= 2;
1187   return(pow2);
1188 }
1189  
1190
1191
1192 void write_convertdouble_info(int type, FILE *fp)
1193 {
1194   switch(type) {
1195   case SP:
1196   case BT:
1197   case LU:
1198   case FT:
1199   case MG:
1200   //case EP:
1201   case CG:
1202     fprintf(fp, "%slogical  convertdouble\n", FINDENT);
1203 #ifdef CONVERTDOUBLE
1204     fprintf(fp, "%sparameter (convertdouble = .true.)\n", FINDENT);
1205 #else
1206     fprintf(fp, "%sparameter (convertdouble = .false.)\n", FINDENT);
1207 #endif
1208     break;
1209   }
1210 }