Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
more cleanups in NAS
[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 "ep", "dt", or "is"
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 NPB benchmarks. It is in an obscure place so people
45  * won't accidentally change it. 
46  */
47
48 #define VERSION "3.3"
49
50 /* controls verbose output from setparams */
51 /* #define VERBOSE */
52
53 #define FILENAME "npbparams.h"
54 #define DESC_LINE "c NPROCS = %d CLASS = %c\n"
55 #define DEF_CLASS_LINE     "#define CLASS '%c'\n"
56 #define DEF_NUM_PROCS_LINE "#define NUM_PROCS %d\n"
57 #define FINDENT  "        "
58 #define CONTINUE "     > "
59
60 void get_info(int argc, char *argv[], int *typep, int *nprocsp, char *classp, int* subtypep);
61 void check_info(int type, int nprocs, char class);
62 void read_info(int type, int *nprocsp, char *classp, int *subtypep);
63 void write_info(int type, int nprocs, char class, int subtype);
64 void write_ep_info_C(FILE *fp, int nprocs, char class);  /* after C translation */
65 void write_is_info(FILE *fp, int nprocs, char class);
66 void write_dt_info(FILE *fp, int nprocs, char class);
67 void write_compiler_info(int type, FILE *fp);
68 void check_line(char *line, char *label, char *val);
69 int  check_include_line(char *line, char *filename);
70 void put_string(FILE *fp, char *name, char *val);
71 void put_def_string(FILE *fp, char *name, char *val);
72 void put_def_variable(FILE *fp, char *name, char *val);
73 int isqrt(int i);
74 int ilog2(int i);
75 int ipow2(int i);
76
77 enum benchmark_types {IS, DT, EP};
78
79 int main(int argc, char *argv[])
80 {
81   int nprocs, nprocs_old, type;
82   char class, class_old;
83   int subtype = -1, old_subtype = -1;
84
85   /* Get command line arguments. Make sure they're ok. */
86   get_info(argc, argv, &type, &nprocs, &class, &subtype);
87   if (class != 'U') {
88 #ifdef VERBOSE
89     printf("setparams: For benchmark %s: number of processors = %d class = %c\n", 
90      argv[1], nprocs, class); 
91 #endif
92     check_info(type, nprocs, class);
93   }
94
95   /* Get old information. */
96   read_info(type, &nprocs_old, &class_old, &old_subtype);
97   if (class != 'U') {
98     if (class_old != 'X') {
99 #ifdef VERBOSE
100       printf("setparams:     old settings: number of processors = %d class = %c\n", 
101        nprocs_old, class_old); 
102 #endif
103     }
104   } else {
105     printf("setparams:\n\
106   *********************************************************************\n\
107   * You must specify NPROCS and CLASS to build this benchmark         *\n\
108   * For example, to build a class A benchmark for 4 processors, type  *\n\
109   *       make {benchmark-name} NPROCS=4 CLASS=A                      *\n\
110   *********************************************************************\n\n"); 
111
112     if (class_old != 'X') {
113 #ifdef VERBOSE
114       printf("setparams: Previous settings were CLASS=%c NPROCS=%d\n", 
115        class_old, nprocs_old); 
116 #endif
117     }
118     exit(1); /* exit on class==U */
119   }
120
121   /* Write out new information if it's different. */
122   if (nprocs != nprocs_old || class != class_old || subtype != old_subtype) {
123 #ifdef VERBOSE
124     printf("setparams: Writing %s\n", FILENAME); 
125 #endif
126     write_info(type, nprocs, class, subtype);
127   } else {
128 #ifdef VERBOSE
129     printf("setparams: Settings unchanged. %s unmodified\n", FILENAME); 
130 #endif
131   }
132
133   return 0;
134 }
135
136 /*  get_info(): Get parameters from command line */
137 void get_info(int argc, char *argv[], int *typep, int *nprocsp, char *classp, int *subtypep)
138 {
139   if (argc < 4) {
140     printf("Usage: %s (%d) benchmark-name nprocs class\n", argv[0], argc);
141     exit(1);
142   }
143
144   *nprocsp = atoi(argv[2]);
145   *classp = *argv[3];
146
147   if      (!strcmp(argv[1], "is") || !strcmp(argv[1], "IS")) *typep = IS;
148   else if (!strcmp(argv[1], "dt") || !strcmp(argv[1], "DT")) *typep = DT;
149   else if (!strcmp(argv[1], "ep") || !strcmp(argv[1], "EP")) *typep = EP;
150   else {
151     printf("setparams: Error: unknown benchmark type %s\n", argv[1]);
152     exit(1);
153   }
154 }
155
156 /*
157  *  check_info(): Make sure command line data is ok for this benchmark 
158  */
159
160 void check_info(int type, int nprocs, char class) 
161 {
162   int rootprocs, logprocs; 
163
164   /* check number of processors */
165   if (nprocs <= 0) {
166     printf("setparams: Number of processors must be greater than zero\n");
167     exit(1);
168   }
169   switch(type) {
170   case IS:
171     logprocs = ilog2(nprocs);
172     if (logprocs < 0) {
173       printf("setparams: Number of processors must be a power of two (1,2,4,...) for this benchmark\n");
174       exit(1);
175     }
176     break;
177
178   case EP:
179   case DT:
180     break;
181
182   default:
183     /* never should have gotten this far with a bad name */
184     printf("setparams: (Internal Error) Benchmark type %d unknown to this program\n", type); 
185     exit(1);
186   }
187
188   /* check class */
189   if (class != 'S' && 
190       class != 'W' && 
191       class != 'A' && 
192       class != 'B' && 
193       class != 'C' && 
194       class != 'D' && 
195       class != 'E') {
196     printf("setparams: Unknown benchmark class %c\n", class); 
197     printf("setparams: Allowed classes are \"S\", \"W\", and \"A\" through \"E\"\n");
198     exit(1);
199   }
200
201   if (class == 'E' && (type == IS || type == DT)) {
202     printf("setparams: Benchmark class %c not defined for IS or DT\n", class);
203     exit(1);
204   }
205
206   if (class == 'D' && type == IS && nprocs < 4) {
207     printf("setparams: IS class D size cannot be run on less than 4 processors\n");
208     exit(1);
209   }
210 }
211
212 /* 
213  * read_info(): Read previous information from file. 
214  *              Not an error if file doesn't exist, because this may be the first time we're running.
215  *              Assumes the first two lines of the file is in a special format that we understand (since we wrote it).
216  */
217
218 void read_info(int type, int *nprocsp, char *classp, int *subtypep)
219 {
220   int nread = 0;
221   FILE *fp;
222   fp = fopen(FILENAME, "r");
223   if (fp == NULL) {
224 #ifdef VERBOSE
225     printf("setparams: INFO: configuration file %s does not exist (yet)\n", FILENAME); 
226 #endif
227     goto abort;
228   }
229
230   /* first two lines of file contains info */
231   nread = fscanf(fp, DEF_CLASS_LINE, classp);
232   nread += fscanf(fp, DEF_NUM_PROCS_LINE, nprocsp);
233   if (nread != 2) {
234     printf("setparams: Error line %d parsing config file %s. Ignoring previous settings\n", __LINE__,FILENAME);
235     goto abort;
236   }
237
238   fclose(fp);
239   return;
240
241  abort:
242   *nprocsp = -1;
243   *classp = 'X';
244   *subtypep = -1;
245   return;
246 }
247
248 /* 
249  * write_info(): Write new information to config file. 
250  *               First line is in a special format so we can read
251  *               it in again. Then comes a warning. The rest is all
252  *               specific to a particular benchmark. 
253  */
254
255 void write_info(int type, int nprocs, char class, int subtype) 
256 {
257   FILE *fp;
258   char *BT_TYPES[] = {"NONE", "FULL", "SIMPLE", "EPIO", "FORTRAN"};
259
260   fp = fopen(FILENAME, "w");
261   if (fp == NULL) {
262     printf("setparams: Can't open file %s for writing\n", FILENAME);
263     exit(1);
264   }
265
266   fprintf(fp, DEF_CLASS_LINE, class);
267   fprintf(fp, DEF_NUM_PROCS_LINE, nprocs);
268   fprintf(fp, "\
269 /*\n\
270    This file is generated automatically by the setparams utility.\n\
271    It sets the number of processors and the class of the NPB\n\
272    in this directory. Do not modify it by hand.   */\n\
273    \n");
274
275   /* Now do benchmark-specific stuff */
276   switch(type) {
277   case IS:
278     write_is_info(fp, nprocs, class);  
279     break;
280   case DT:
281     write_dt_info(fp, nprocs, class);  
282     break;
283   case EP:
284     write_ep_info_C(fp, nprocs, class);
285     break;
286   default:
287     printf("setparams: (Internal error): Unknown benchmark type %d\n", type);
288     exit(1);
289   }
290   write_compiler_info(type, fp);
291   fclose(fp);
292   return;
293 }
294
295 /* write_dt_info(): Write DT specific info to config file */
296
297 void write_dt_info(FILE *fp, int nprocs, char class) 
298 {
299   int num_samples,deviation,num_sources;
300   if      (class == 'S') { num_samples=1728; deviation=128; num_sources=4; }
301   else if (class == 'W') { num_samples=1728*8; deviation=128*2; num_sources=4*2; }
302   else if (class == 'A') { num_samples=1728*64; deviation=128*4; num_sources=4*4; }
303   else if (class == 'B') { num_samples=1728*512; deviation=128*8; num_sources=4*8; }
304   else if (class == 'C') { num_samples=1728*4096; deviation=128*16; num_sources=4*16; }
305   else if (class == 'D') { num_samples=1728*4096*8; deviation=128*32; num_sources=4*32; }
306   else {
307     printf("setparams: Internal error: invalid class type %c\n", class);
308     exit(1);
309   }
310   fprintf(fp, "#define NUM_SAMPLES %d\n", num_samples);
311   fprintf(fp, "#define STD_DEVIATION %d\n", deviation);
312   fprintf(fp, "#define NUM_SOURCES %d\n", num_sources);
313 }
314
315 /* write_is_info(): Write IS specific info to config file */
316 void write_is_info(FILE *fp, int nprocs, char class)
317 {
318   if( class != 'S' && class != 'W' && class != 'A' && class != 'B' && class != 'C' && class != 'D' )
319   {
320     printf("setparams: Internal error: invalid class type %c\n", class);
321     exit(1);
322   }
323 }
324
325 /* write_ep_info_C(): Write EP specific info to config file */
326 void write_ep_info_C(FILE *fp, int nprocs, char class)
327 {
328   /* easiest way (given the way the benchmark is written) is to specify log of number of grid points in each
329    * direction m1, m2, m3. nt is the number of iterations
330    */
331   int m;
332   if      (class == 'S') { m = 24; }
333   else if (class == 'W') { m = 25; }
334   else if (class == 'A') { m = 28; }
335   else if (class == 'B') { m = 30; }
336   else if (class == 'C') { m = 32; }
337   else if (class == 'D') { m = 36; }
338   else if (class == 'E') { m = 40; }
339   else {
340     printf("setparams: Internal error: invalid class type %c\n", class);
341     exit(1);
342   }
343
344   /* number of processors given by "npm" */
345   fprintf(fp, "%schar *_class=\"%c\";\n",FINDENT,class);
346   fprintf(fp, "%sint m=%d;\n", FINDENT,m);
347   fprintf(fp, "%sint npm=%d;\n", FINDENT,nprocs);
348 }
349
350 /* 
351  * This is a gross hack to allow the benchmarks to  print out how they were compiled. Various other ways
352  * of doing this have been tried and they all fail on some machine - due to a broken "make" program, or
353  * F77 limitations, of whatever. Hopefully this will always work because it uses very portable C. Unfortunately
354  * it relies on parsing the make.def file - YUK. 
355  * If your machine doesn't have <string.h> or <ctype.h>, happy hacking!
356  */
357
358 #define VERBOSE
359 #define LL 400
360 #include <stdio.h>
361 #define DEFFILE "../config/make.def"
362 #define DEFAULT_MESSAGE "(none)"
363 FILE *deffile;
364 void write_compiler_info(int type, FILE *fp)
365 {
366   char line[LL];
367   char compiletime[LL], randfile[LL];
368   char mpicc[LL], cflags[LL], clink[LL], clinkflags[LL],
369        cmpi_lib[LL], cmpi_inc[LL];
370   struct tm *tmp;
371   time_t t;
372   deffile = fopen(DEFFILE, "r");
373   if (deffile == NULL) {
374     printf("\n\
375 setparams: File %s doesn't exist. To build the NAS benchmarks\n\
376            you need to create is according to the instructions\n\
377            in the README in the main directory and comments in \n\
378            the file config/make.def.template\n", DEFFILE);
379     exit(1);
380   }
381   strcpy(randfile, DEFAULT_MESSAGE);
382   strcpy(mpicc, DEFAULT_MESSAGE);
383   strcpy(cflags, DEFAULT_MESSAGE);
384   strcpy(clink, DEFAULT_MESSAGE);
385   strcpy(clinkflags, DEFAULT_MESSAGE);
386   strcpy(cmpi_lib, DEFAULT_MESSAGE);
387   strcpy(cmpi_inc, DEFAULT_MESSAGE);
388
389   while (fgets(line, LL, deffile) != NULL) {
390     if (*line == '#') continue;
391     /* yes, this is inefficient. but it's simple! */
392     check_line(line, "RAND", randfile);
393     check_line(line, "MPICC", mpicc);
394     check_line(line, "CFLAGS", cflags);
395     check_line(line, "CLINK", clink);
396     check_line(line, "CLINKFLAGS", clinkflags);
397     check_line(line, "CMPI_LIB", cmpi_lib);
398     check_line(line, "CMPI_INC", cmpi_inc);
399   }
400
401   (void) time(&t);
402   tmp = localtime(&t);
403   (void) strftime(compiletime, (size_t)LL, "%d %b %Y", tmp);
404
405   put_def_string(fp, "COMPILETIME", compiletime);
406   put_def_string(fp, "NPBVERSION", VERSION);
407   put_def_string(fp, "MPICC", mpicc);
408   put_def_string(fp, "CFLAGS", cflags);
409   put_def_string(fp, "CLINK", clink);
410   put_def_string(fp, "CLINKFLAGS", clinkflags);
411   put_def_string(fp, "CMPI_LIB", cmpi_lib);
412   put_def_string(fp, "CMPI_INC", cmpi_inc);
413 }
414
415 void check_line(char *line, char *label, char *val)
416 {
417   char *original_line;
418   int n;
419   original_line = line;
420   /* compare beginning of line and label */
421   while (*label != '\0' && *line == *label) {
422     line++; label++; 
423   }
424   /* if *label is not EOS, we must have had a mismatch */
425   if (*label != '\0') return;
426   /* if *line is not a space, actual label is longer than test label */
427   if (!isspace(*line) && *line != '=') return ; 
428   /* skip over white space */
429   while (isspace(*line)) line++;
430   /* next char should be '=' */
431   if (*line != '=') return;
432   /* skip over white space */
433   while (isspace(*++line));
434   /* if EOS, nothing was specified */
435   if (*line == '\0') return;
436   /* finally we've come to the value */
437   strcpy(val, line);
438   /* chop off the newline at the end */
439   n = strlen(val)-1;
440   if (n >= 0 && val[n] == '\n')
441     val[n--] = '\0';
442   if (n >= 0 && val[n] == '\r')
443     val[n--] = '\0';
444   /* treat continuation */
445   while (val[n] == '\\' && fgets(original_line, LL, deffile)) {
446      line = original_line;
447      while (isspace(*line)) line++;
448      if (isspace(*original_line)) val[n++] = ' ';
449      while (*line && *line != '\n' && *line != '\r' && n < LL-1)
450        val[n++] = *line++;
451      val[n] = '\0';
452      n--;
453   }
454 /*  if (val[strlen(val) - 1] == '\\') {
455     printf("\n\
456 setparams: Error in file make.def. Because of the way in which\n\
457            command line arguments are incorporated into the\n\
458            executable benchmark, you can't have any continued\n\
459            lines in the file make.def, that is, lines ending\n\
460            with the character \"\\\". Although it may be ugly, \n\
461            you should be able to reformat without continuation\n\
462            lines. The offending line is\n\
463   %s\n", original_line);
464     exit(1);
465   } */
466 }
467
468 int check_include_line(char *line, char *filename)
469 {
470   char *include_string = "include";
471   /* compare beginning of line and "include" */
472   while (*include_string != '\0' && *line == *include_string) {
473     line++; include_string++; 
474   }
475   /* if *include_string is not EOS, we must have had a mismatch */
476   if (*include_string != '\0') return(0);
477   /* if *line is not a space, first word is not "include" */
478   if (!isspace(*line)) return(0); 
479   /* skip over white space */
480   while (isspace(*++line));
481   /* if EOS, nothing was specified */
482   if (*line == '\0') return(0);
483   /* next keyword should be name of include file in *filename */
484   while (*filename != '\0' && *line == *filename) {
485     line++; filename++; 
486   }  
487   if (*filename != '\0' || 
488       (*line != ' ' && *line != '\0' && *line !='\n')) return(0);
489   else return(1);
490 }
491
492 #define MAXL 46
493 void put_string(FILE *fp, char *name, char *val)
494 {
495   int len;
496   len = strlen(val);
497   if (len > MAXL) {
498     val[MAXL] = '\0';
499     val[MAXL-1] = '.';
500     val[MAXL-2] = '.';
501     val[MAXL-3] = '.';
502     len = MAXL;
503   }
504   fprintf(fp, "%scharacter*%d %s\n", FINDENT, len, name);
505   fprintf(fp, "%sparameter (%s=\'%s\')\n", FINDENT, name, val);
506 }
507
508 /* NOTE: is the ... stuff necessary in C? */
509 void put_def_string(FILE *fp, char *name, char *val)
510 {
511   int len;
512   len = strlen(val);
513   if (len > MAXL) {
514     val[MAXL] = '\0';
515     val[MAXL-1] = '.';
516     val[MAXL-2] = '.';
517     val[MAXL-3] = '.';
518     len = MAXL;
519   }
520   fprintf(fp, "#define %s \"%s\"\n", name, val);
521 }
522
523 void put_def_variable(FILE *fp, char *name, char *val)
524 {
525   int len;
526   len = strlen(val);
527   if (len > MAXL) {
528     val[MAXL] = '\0';
529     val[MAXL-1] = '.';
530     val[MAXL-2] = '.';
531     val[MAXL-3] = '.';
532     len = MAXL;
533   }
534   fprintf(fp, "#define %s %s\n", name, val);
535 }
536
537 #if 0
538 /* this version allows arbitrarily long lines but some compilers don't like that and they're rarely useful */
539
540 #define LINELEN 65
541 void put_string(FILE *fp, char *name, char *val)
542 {
543   int len, nlines, pos, i;
544   char line[100];
545   len = strlen(val);
546   nlines = len/LINELEN;
547   if (nlines*LINELEN < len) nlines++;
548   fprintf(fp, "%scharacter*%d %s\n", FINDENT, nlines*LINELEN, name);
549   fprintf(fp, "%sparameter (%s = \n", FINDENT, name);
550   for (i = 0; i < nlines; i++) {
551     pos = i*LINELEN;
552     if (i == 0) fprintf(fp, "%s\'", CONTINUE);
553     else        fprintf(fp, "%s", CONTINUE);
554     /* number should be same as LINELEN */
555     fprintf(fp, "%.65s", val+pos);
556     if (i == nlines-1) fprintf(fp, "\')\n");
557     else             fprintf(fp, "\n");
558   }
559 }
560 #endif
561
562
563 /* integer square root. Return error if argument isn't a perfect square or is less than or equal to zero */
564 int isqrt(int i)
565 {
566   int root, square;
567   if (i <= 0) return(-1);
568   square = 0;
569   for (root = 1; square <= i; root++) {
570     square = root*root;
571     if (square == i) return(root);
572   }
573   return(-1);
574 }
575
576 /* integer log base two. Return error is argument isn't a power of two or is less than or equal to zero */
577 int ilog2(int i)
578 {
579   int log2;
580   int exp2 = 1;
581   if (i <= 0) return(-1);
582
583   for (log2 = 0; log2 < 20; log2++) {
584     if (exp2 == i) return(log2);
585     exp2 *= 2;
586   }
587   return(-1);
588 }
589
590 int ipow2(int i)
591 {
592   int pow2 = 1;
593   if (i < 0) return(-1);
594   if (i == 0) return(1);
595   while(i--) pow2 *= 2;
596   return(pow2);
597 }