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.
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.
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"
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.
36 #include <sys/types.h>
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.
50 /* controls verbose output from setparams */
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"
58 #define CONTINUE " > "
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);
77 enum benchmark_types {IS, DT, EP};
79 int main(int argc, char *argv[])
81 int nprocs, nprocs_old, type;
82 char class, class_old;
83 int subtype = -1, old_subtype = -1;
85 /* Get command line arguments. Make sure they're ok. */
86 get_info(argc, argv, &type, &nprocs, &class, &subtype);
89 printf("setparams: For benchmark %s: number of processors = %d class = %c\n",
90 argv[1], nprocs, class);
92 check_info(type, nprocs, class);
95 /* Get old information. */
96 read_info(type, &nprocs_old, &class_old, &old_subtype);
98 if (class_old != 'X') {
100 printf("setparams: old settings: number of processors = %d class = %c\n",
101 nprocs_old, class_old);
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");
112 if (class_old != 'X') {
114 printf("setparams: Previous settings were CLASS=%c NPROCS=%d\n",
115 class_old, nprocs_old);
118 exit(1); /* exit on class==U */
121 /* Write out new information if it's different. */
122 if (nprocs != nprocs_old || class != class_old || subtype != old_subtype) {
124 printf("setparams: Writing %s\n", FILENAME);
126 write_info(type, nprocs, class, subtype);
129 printf("setparams: Settings unchanged. %s unmodified\n", FILENAME);
136 /* get_info(): Get parameters from command line */
137 void get_info(int argc, char *argv[], int *typep, int *nprocsp, char *classp, int *subtypep)
140 printf("Usage: %s (%d) benchmark-name nprocs class\n", argv[0], argc);
144 *nprocsp = atoi(argv[2]);
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;
151 printf("setparams: Error: unknown benchmark type %s\n", argv[1]);
157 * check_info(): Make sure command line data is ok for this benchmark
160 void check_info(int type, int nprocs, char class)
162 int rootprocs, logprocs;
164 /* check number of processors */
166 printf("setparams: Number of processors must be greater than zero\n");
171 logprocs = ilog2(nprocs);
173 printf("setparams: Number of processors must be a power of two (1,2,4,...) for this benchmark\n");
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);
196 printf("setparams: Unknown benchmark class %c\n", class);
197 printf("setparams: Allowed classes are \"S\", \"W\", and \"A\" through \"E\"\n");
201 if (class == 'E' && (type == IS || type == DT)) {
202 printf("setparams: Benchmark class %c not defined for IS or DT\n", class);
206 if (class == 'D' && type == IS && nprocs < 4) {
207 printf("setparams: IS class D size cannot be run on less than 4 processors\n");
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).
218 void read_info(int type, int *nprocsp, char *classp, int *subtypep)
222 fp = fopen(FILENAME, "r");
225 printf("setparams: INFO: configuration file %s does not exist (yet)\n", FILENAME);
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);
234 printf("setparams: Error line %d parsing config file %s. Ignoring previous settings\n", __LINE__,FILENAME);
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.
255 void write_info(int type, int nprocs, char class, int subtype)
258 char *BT_TYPES[] = {"NONE", "FULL", "SIMPLE", "EPIO", "FORTRAN"};
260 fp = fopen(FILENAME, "w");
262 printf("setparams: Can't open file %s for writing\n", FILENAME);
266 fprintf(fp, DEF_CLASS_LINE, class);
267 fprintf(fp, DEF_NUM_PROCS_LINE, nprocs);
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\
275 /* Now do benchmark-specific stuff */
278 write_is_info(fp, nprocs, class);
281 write_dt_info(fp, nprocs, class);
284 write_ep_info_C(fp, nprocs, class);
287 printf("setparams: (Internal error): Unknown benchmark type %d\n", type);
290 write_compiler_info(type, fp);
295 /* write_dt_info(): Write DT specific info to config file */
297 void write_dt_info(FILE *fp, int nprocs, char class)
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; }
307 printf("setparams: Internal error: invalid class type %c\n", class);
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);
315 /* write_is_info(): Write IS specific info to config file */
316 void write_is_info(FILE *fp, int nprocs, char class)
318 if( class != 'S' && class != 'W' && class != 'A' && class != 'B' && class != 'C' && class != 'D' )
320 printf("setparams: Internal error: invalid class type %c\n", class);
325 /* write_ep_info_C(): Write EP specific info to config file */
326 void write_ep_info_C(FILE *fp, int nprocs, char class)
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
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; }
340 printf("setparams: Internal error: invalid class type %c\n", class);
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);
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!
361 #define DEFFILE "../config/make.def"
362 #define DEFAULT_MESSAGE "(none)"
364 void write_compiler_info(int type, FILE *fp)
367 char compiletime[LL], randfile[LL];
368 char mpicc[LL], cflags[LL], clink[LL], clinkflags[LL],
369 cmpi_lib[LL], cmpi_inc[LL];
372 deffile = fopen(DEFFILE, "r");
373 if (deffile == NULL) {
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);
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);
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);
403 (void) strftime(compiletime, (size_t)LL, "%d %b %Y", tmp);
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);
415 void check_line(char *line, char *label, char *val)
419 original_line = line;
420 /* compare beginning of line and label */
421 while (*label != '\0' && *line == *label) {
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 */
438 /* chop off the newline at the end */
440 if (n >= 0 && val[n] == '\n')
442 if (n >= 0 && val[n] == '\r')
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)
454 /* if (val[strlen(val) - 1] == '\\') {
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);
468 int check_include_line(char *line, char *filename)
470 char *include_string = "include";
471 /* compare beginning of line and "include" */
472 while (*include_string != '\0' && *line == *include_string) {
473 line++; include_string++;
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) {
487 if (*filename != '\0' ||
488 (*line != ' ' && *line != '\0' && *line !='\n')) return(0);
493 void put_string(FILE *fp, char *name, char *val)
504 fprintf(fp, "%scharacter*%d %s\n", FINDENT, len, name);
505 fprintf(fp, "%sparameter (%s=\'%s\')\n", FINDENT, name, val);
508 /* NOTE: is the ... stuff necessary in C? */
509 void put_def_string(FILE *fp, char *name, char *val)
520 fprintf(fp, "#define %s \"%s\"\n", name, val);
523 void put_def_variable(FILE *fp, char *name, char *val)
534 fprintf(fp, "#define %s %s\n", name, val);
538 /* this version allows arbitrarily long lines but some compilers don't like that and they're rarely useful */
541 void put_string(FILE *fp, char *name, char *val)
543 int len, nlines, pos, i;
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++) {
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");
563 /* integer square root. Return error if argument isn't a perfect square or is less than or equal to zero */
567 if (i <= 0) return(-1);
569 for (root = 1; square <= i; root++) {
571 if (square == i) return(root);
576 /* integer log base two. Return error is argument isn't a power of two or is less than or equal to zero */
581 if (i <= 0) return(-1);
583 for (log2 = 0; log2 < 20; log2++) {
584 if (exp2 == i) return(log2);
593 if (i < 0) return(-1);
594 if (i == 0) return(1);
595 while(i--) pow2 *= 2;