-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbenchit.c
1892 lines (1760 loc) · 58.4 KB
/
benchit.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/********************************************************************
* BenchIT - Performance Measurement for Scientific Applications
* Contact: developer@benchit.org
*
* $Id: benchit.c 1 2009-09-11 12:26:19Z william $
* $URL: svn+ssh://william@rupert.zih.tu-dresden.de/svn-base/benchit-root/BenchITv6/benchit.c $
* For license details see COPYING in the package base directory
*******************************************************************/
/* Main program of the BenchIT-project
*******************************************************************/
#ifdef USE_MPI
#include <mpi.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <errno.h>
/* This is for `size_t'. */
#include <stddef.h>
/* This is for different calculations. E.g for logarithmic axis */
#include <math.h>
/* This is for a lot of String work concat and so on... */
#include <string.h>
/* used for typeconversion e.g. atoi string to integer */
#include <stdlib.h>
/* main posix header */
#include <unistd.h>
/* This is for catching SIG_INT and SIG_TERM*/
#include <signal.h>
#include <ctype.h>
#include <math.h>
/* if this is compiled for a MPI-kernel,
* somewhere you got to set -DUSE_MPI as compiler flag
* to include mpi-header
*/
/* if this is compiled for a OpenMP-kernel,
* somewhere you got to set -DUSE_OMP as compiler flag
* to include OpenMP-header
*/
#ifdef USE_OMP
#include <omp.h>
#endif
/* if PAPI should be used,
* somewhere you got to set -DUSE_PAPI as compiler flag
*/
#ifdef USE_PAPI
#include <papi.h>
#endif
/* used for timers */
#include <time.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>
/* used for BenchIT */
#include "interface.h"
#include "tools/bienvhash.h"
#include "tools/stringlib.h"
#include "tools/output.h"
#include "tools/bitWriter.h"
/* used for BenchIT version number (year) */
#ifndef BENCHIT_MAJOR
#define BENCHIT_MAJOR 2013 /**< Major version number used by fileinfo.c */
#endif
/* used for BenchIT version number (month) */
#ifndef BENCHIT_MINOR
#define BENCHIT_MINOR 00 /**< Minor version number used by fileinfo.c */
#endif
/* used for BenchIT version number (day) */
#ifndef BENCHIT_SUBMINOR
#define BENCHIT_SUBMINOR 00 /**< Subminor version number used by fileinfo.c */
#endif
/* Every kernel on every problemsize will be run (Accuracy+1) times */
#undef DEFAULT_ACCURACY
#define DEFAULT_ACCURACY 2 /**< If the LOCALDEF does not define an accuracy number -
2 will be used which will result in 2 repetitions
of each measurementstep */
/* the time-limit in seconds. when more time has passed, the measurement is interrupted */
#undef DEFAULT_TIMELIMIT
#define DEFAULT_TIMELIMIT 600 /**< Number of seconds after which a measurment is stoped
(should be set in PARAMETERS) */
/*name of the file where progress information is stored to*/
static char* progf = NULL;
/*file descriptor to the file where progress information is stored to */
static FILE* prog_file = NULL;
/*
* boolean for standalone-applictation
*/
int bi_standalone = 0; /**< is this a standalone binary to be used without benchit-environment*/
/* For more detailed output of what's going on. */
int verbose = 0; /**< be more communicative */
static double bi_gettimeofday(void);
static double bi_gettimeofday_improved(void);
double (*bi_gettime)() = bi_gettimeofday_improved;
double dTimerGranularity;
double dTimerOverhead;
double dStartTimerOverhead;
double d_bi_start_sec; /**< start time */
double biStartTime;
// Times relative to programm start (improved precision)
double biStartTimeAbs;
double biStopTimeAbs;
static void safe_exit(int code);
static void selectTimer(void);
static void createDirStructureOrExit(const char *dirstr) {
int err = createDirStructure(dirstr);
if (err != 0)
safe_exit(err);
}
void allocYAxis(bi_info *theInfo) {
theInfo->yaxistexts = (char**) calloc((size_t)theInfo->numfunctions, sizeof(char*));
if (theInfo->yaxistexts == 0) {
fprintf(stderr, "Allocation of yaxistexts failed.\n");
fflush(stderr);
exit(127);
}
theInfo->selected_result = (int*) calloc((size_t)theInfo->numfunctions, sizeof(int));
if (theInfo->selected_result == 0) {
fprintf(stderr, "Allocation of outlier direction failed.\n");
fflush(stderr);
exit(127);
}
theInfo->legendtexts = (char**) calloc((size_t)theInfo->numfunctions, sizeof(char*));
if (theInfo->legendtexts == 0) {
fprintf(stderr, "Allocation of legendtexts failed.\n");
fflush(stderr);
exit(127);
}
theInfo->base_yaxis = (int*) calloc((size_t)theInfo->numfunctions, sizeof(int));
if (theInfo->base_yaxis == 0) {
fprintf(stderr, "Allocation of base yaxis failed.\n");
fflush(stderr);
exit(127);
}
}
/*!@brief Print list and explanation of command line args on stdout
* and exit the program.
*/
static void printHelpAndExit() {
printf("Usage: <executable> [option]...\n\n");
printf("Where option can be:\n");
printf(" -h, --help\t\t\t");
printf("show this help screen\n");
printf(" -d, --dumpTable\t\t");
printf("print the environment variables stored in the internal"
"\n\t\t\t\tHashTable to stdout\n");
printf(" -o, --output-dir=DIR\t\t");
printf("write result files into DIR (requires absolute path)\n");
printf(" -S, --standalone\t\t");
printf("don't read _input_*\n");
printf(" -p, --parameter-file=PAR_FILE\t");
printf("read parameters from PAR_FILE at runtime\n");
printf(" -q, --quiet\t\t\t");
printf("suppress all messages to stdout and stderr\n");
printf(" -v, --verbose\t\t\t");
printf("print more messages about what the program is doing\n");
printf(" -V, --version\t\t\t");
printf("print version information\n");
fflush(stdout);
safe_exit(0);
}
/*!@brief Extract values for recognized options.
*
* Checks if at position pos in argv is an option in whether
* short or long version. If hasValue is greater than 0 the
* pointer value will be set to the start of the value string
* and the varibale pos will be increased.
* If argv[i] is a short option the value is expected in argv[i+1].
* If argv[i] is a long option, the value is that part of argv[i]
* that follows the first occuring = sign.
* @param[in] argv the argv array.
* @param[in] pos the postion in argv to look at.
* @param[in] argc the number of elements in argv.
* @param[in] sOpt the short version of the option.
* @param[in] lOpt the long version of the option.
* @param[in] hasValue 0 if option without value, 1 or greater if with value.
* @param[in,out] value pointer to the value char array.
* @return 1 if successful match and retrieval of value, 0 else.
*/
static int isOption(char** argv, int *pos, int argc, char sOpt, const char *lOpt, int hasValue, char **value) {
/*
retval is the return value for this function
len is the length of the poss entry in argv.
*/
int retval = 0, len = -1;
/* reset value */
*value = 0;
/* if there is no argument number pos return 0 */
if (argv[*pos] == 0)
return retval;
/* else get the length of the argument */
len = lengthc(argv[*pos]) + 1;
/* if the pos' arguments first char is not a '-' return 0 */
if (argv[*pos][0] != '-')
return retval;
/* now try to match option
* ! short Options MUST have length 2 ('-' plus a single character)
*/
if (len == 2) {
/* short option */
/* if there was some strange stuff used as short Option return 0 */
if (sOpt == 0)
return retval;
/* if there is no Value needed for this option, but a value is passed return 0 */
if (hasValue > 0 && *pos + 1 >= argc)
return retval;
/* if it is found */
if (argv[*pos][1] == sOpt) {
/* short option hit */
/* if it needs a value, set it */
if (hasValue == 1)
*value = argv[++*pos];
/* but always return 1 */
retval = 1;
}
/* if it is not found return 0 */
else
return retval;
}
/*
* ! long options MUST have length >2 (- plus at least 2 chars)
*/
else if (len > 2 && lOpt != 0) {
char * lOptNonConst = strdup(lOpt);
/* long option */
/* STR_LEN is passed from a header (string.h?) */
char sub[STR_LEN];
/* position */
int eqPos = -1;
/* fill the string sub with 0s (NOT with '0's) */
memset(sub, 0, STR_LEN);
/* if there is no lOpt passed */
if (lOpt == 0)
return retval;
/* if the argument doesn't start with a dash '-' */
if (argv[*pos][1] != '-')
return retval;
/* if it needs a value, they must be separated by a = : -option=value */
/* always point separation between arguments: */
if (hasValue == 1) {
eqPos = indexOf(argv[*pos], '=', 1);
} else {
eqPos = len + 1;
}
/* if it is too short (only a single char) return 0 */
if (eqPos < 3)
return retval;
/* extract option name */
/* if the option name cannot be found in the option
* (sub=argv[*pos].substring(2,eqPos))
* subString sub is a substring of argv[*pos] beginning with the 2nd char to the eqPos' char
* if the creation of this substring fails retun 0 */
if (substring(argv[*pos], sub, 2, eqPos) != 1)
return retval;
/* if the subString is to short return false */
if (strlen(sub) == 0)
return retval;
/* compare the strings 0 means no differences */
if (comparec(sub, lOptNonConst) == 0) {
/* long option hit */
/* if it needs a value (-option=value), set it */
if (hasValue == 1)
*value = &argv[*pos][eqPos + 1];
/* but always return 0 */
retval = 1;
}
freeCheckedC(&lOptNonConst);
}
/* if nothing is found return 0; */
else
return retval;
return retval;
}
/*!@brief Parse commandline arguments.
*
* Checks the arguments for recognizable input. Does not use
* getopt for compatibility reasons. See documentation of
* printUsage() for detailed info about recognized options.
* @param argc argc from main()
* @param argv argv from main()
*/
static void checkCommandLine(int argc, char **argv) {
/* for incrementing over arguments */
int i;
/* increment over arguments:
* (all possible arguments should be checked here)
* check: is this an available option? */
for (i = 1; i < argc; i++) {
/* value of the option (if it needs one) */
char *value = 0;
/* shall the help be printed? */
if (isOption(argv, &i, argc, 'h', "help", 0, &value) == 1) {
printHelpAndExit();
continue;
}
/* shall the environment be dumped? */
if (isOption(argv, &i, argc, 'd', "dumpTable", 0, &value) == 1) {
bi_dumpTable();
fflush(stdout);
safe_exit(0);
continue;
}
/* shall the output-dir be setted? */
if (isOption(argv, &i, argc, 'o', "output-dir", 1, &value) == 1) {
bi_put(bi_strdup("BENCHIT_RUN_OUTPUT_DIR"), value);
continue;
}
/* shall another parameter file be used? */
if (isOption(argv, &i, argc, 'p', "parameter-file", 1, &value) == 1) {
bi_put(bi_strdup("BENCHIT_PARAMETER_FILE"), value);
bi_readParameterFile(value);
continue;
}
/* shall there be no printing? */
if (isOption(argv, &i, argc, 'q', "quiet", 0, &value) == 1) {
if (freopen("/dev/null", "w", stdout) == NULL ) {
printf("BenchIT: Error: could not remap stdout to /dev/null.\n");
fflush(stdout);
safe_exit(1);
}
if (freopen("/dev/null", "w", stderr) == NULL ) {
printf("BenchIT: Error: could not remap stderr to /dev/null.\n");
fflush(stdout);
safe_exit(1);
}
continue;
}
/* shall we use verbose mode? */
if (isOption(argv, &i, argc, 'v', "verbose", 0, &value) == 1) {
verbose = 1;
continue;
}
/* or print the version? */
if (isOption(argv, &i, argc, 'V', "version", 0, &value) == 1) {
printf("BenchIT version %d.%d.%d\n", BENCHIT_MAJOR, BENCHIT_MINOR, BENCHIT_SUBMINOR);
fflush(stdout);
safe_exit(0);
}
/* or shall we run this as standalone? */
if (isOption(argv, &i, argc, 'S', "standalone", 0, &value) == 1) {
bi_standalone = 1;
if (isOption(argv, &i, argc, 'o', "output-dir", 1, &value) == 0) {
value = (char*) malloc(300 * sizeof(char));
if (getcwd(value, 290) == NULL ) {
printf(" [FAILED]\nBenchIT: Couldn't create output directory: ./output.\n");
safe_exit(127);
}
if (value[strlen(value) - 1] == '/')
strcat(value, "output");
else
strcat(value, "/output");
bi_put(bi_strdup("BENCHIT_RUN_OUTPUT_DIR"), value);
freeCheckedC(&value);
}
continue;
}
/* if this point of the loop is reached, the argument
is not a recognized option */
printf("BenchIT: Unknown argument: %s\n", argv[i]);
safe_exit(1);
}
}
/*!@brief Safely exit BenchIT.
*
* Cleans up MPI, Vampir and progress file before exit is called.
* COMMENTS: set -DVAMPIR_TRACE while compiling to clean vampir-trace to!
* @param code The exitcode to use with exit().
*/
static void safe_exit(int code) {
#ifdef USE_MPI
if (code == 0)
MPI_Finalize();
else
MPI_Abort(MPI_COMM_WORLD, code);
#endif
#ifdef VAMPIR_TRACE
(void) _vptleave(300);
(void) _vptflush();
#endif
if (prog_file != NULL ) {
fclose(prog_file);
unlink(progf);
}
exit(code);
}
/*!@brief Generate a new todoList with problemsizes for computation by the
* kernel.
*
* PRE: in the first call todo and done are arrays with all values=0
* max = maximumproblemsize = length of the arrays
* todo[0] and done[0] remain unchanged by the calling party
* done[i] indicates, that the problemsize i has already been calculated
* POST:
* Short: todo is a new array of problemsizes to be calculated
* the array is terminated with a 0
* Long:
* after calling this function todo[i] (i!=0) will contain the problemsize(s),
* which shall be computed in the next step(s). It is NOT said how many todo-problemsizes are returned!
* todos after the last valid todo[i] will contain a problemsize of 0
* functions returns true if new problems could be generated, false if not
* COMMENTS: todo[0] is used to store the number of calls of the function get_new_problems
* done[0] iw used to store whether we are done or not, done[0]=1 means, that get_new_problems
* will return true with the next call
* @return 1 if new todoList could be generated\n
* 0 if there are no problemsizes left.
*/
static int get_new_problems(int *todo, int *done, int max) {
/* todo[0] contains the number of calls of this function. */
/* heres another call, so increment it */
/* though we are filling first the middle problemsize, then the ones at quarters */
/* and so on, we check for the half/quarter/eighth, which is computed by max/(2^num_ofCall) */
int stepsize = (int) (max / (int) pow(2, (++todo[0])));
/* those are used for for loops, explained later */
int i = 0, k = 1, inc = 0;
/* when in the last call of this function done[0] was NOT set, there is still sth. to do */
int ret = !done[0];
/* but if it was set in the last call, we're done */
if (ret == 0)
return ret;
IDL(1, printf("Entering get_new_problems for %d. time\n", todo[0]));
/* if the difference is small enough (dont compute for 1/(2^1024)-parts) */
/* go to linear stepping */
if (stepsize < (0.05 * max))
stepsize = 1;
/* if linear measurement is used, do linear stepping too :P */
#ifdef LINEAR_MEASUREMENT
stepsize = 1;
#endif
/* if we take every following problemsize... */
if (stepsize == 1)
/* ... we should also set inc(rement) to 1, to reach all problemsizes */
inc = 1;
/* if we are still in the pattern which computes first the half problemsize, then the quarter and three-quarter, ... */
else
/* if e.g. it is the 2nd call of the function, the middle problemsize has been solved. */
/* BUT now we have to solve those at the quarter and three-quarter */
/* so stepsize is (1/4)*problemsizemax, but inc is (1/2)*problemsizemax */
/* to reach (1/4)*problemsizemax AND (3/4)*problemsizemax :) */
inc = 2 * stepsize;
/* now compute the problemsizes, which shall be generated */
/* the first will be k[1], the 2nd k[2] and so on */
for (i = stepsize; i <= max; i += inc) {
if (done[i] != 1)
todo[k++] = i;
}
/* the first item after all todo-problemsizes is set to 0 */
/* maybe in the last step we had to compute more then in this step */
todo[k] = 0;
/* if stepsize is 1, means, that all remaining problemsizes were written */
/* into the todo field */
if (stepsize == 1)
done[0] = 1;
/* if we have a larger stepsize: don't do the measurement for largest problemsize */
/* this time */
else if (todo[k - 1] == max)
todo[k - 1] = 0; /*remove max from todo unless stepsize=1*/
IDL(2, printf("todoList="));
for (i = 1; i <= max; i++)
IDL(2, printf(" %d", todo[i]));
IDL(2, printf("\n"));
IDL(1, printf("Leaving get_new_problems.\n"));
return ret;
}
/**
* variables used by main(), analyse_results() and write_results()
* defined static to not be visible in other source-files (avoid multiple declarations)
*/
/*
*
*/
static void *mcb;
/*
* variables:
* rank: used for MPI, will be the rank of the MPI-process or 0 if no MPI is used
* offset: how many functions are measured by bi_entry
* timelimit: timelimit for running the benchmark, if exceeding this limit, it will be stopped
* accuracy: how often every kernel is measured
* dataPointCt: number of data points per function including x value(=numMeasurements*(accuracy+1)+1)
*/
static int rank, offset = 0, curTodoIndex = 1, w = 1, flag = 0, i, j, n = 0, timelimit, accuracy, dataPointCt, numDataPointsPerX;
/*
* info about the kernel, will be filled by kernel
*/
static bi_info theInfo;
/*
* will contain all results of all bi_entry_call
* x|func1_1|func1_2...func1_n|func2_1|func2_2... with n=accuracy+1
*/
static double *allResults = NULL;
static void cleanUp(int err){
bi_cleanup(mcb);
freeCheckedD(&allResults);
safe_exit(err);
}
/**
* Finishes Benchit: Write results (checked), bi_cleanup kernel, free allResults,
*/
static void finish(int err){
if(rank==0){
write_results(theInfo, allResults, accuracy + 1, bi_standalone);
printf("BenchIT: Finishing...\n");
fflush(stdout);
}
cleanUp(err);
}
/**
* Signal handler for SIGINT
*/
static void sigint_handler(int signum) {
char c = '\0', *p = NULL;
int interactive = 0, exitcode = 0;
/* ignore further signals while handling */
signal(signum, SIG_IGN );
if (rank == 0) {
p = bi_getenv("BENCHIT_INTERACTIVE", 0);
interactive = atoi(p);
if (interactive) {
printf("\nBenchIT: Received SIGINT (Ctrl-C). Do you really want to quit? [y/n]: ");
fflush(stdout);
c = (char) fgetc(stdin);
fflush(stdin);
} else {
printf("\nBenchIT: Received SIGINT (Ctrl-C).\n");
c = 'y';
exitcode = 1;
}
}
#ifdef USE_MPI
MPI_Bcast(&c, 1, MPI_CHAR, 0,MPI_COMM_WORLD);
#endif
if (c == 'y' || c == 'Y') {
if (rank == 0) {
printf("BenchIT: Aborting...\n");
fflush(stdout);
}
finish(exitcode);
} else {
/* read remaining input */
if (rank == 0)
while (fgetc(stdin) != '\n')
;
/* reinstall handler */
signal(SIGINT, sigint_handler);
}
}
/**
* Signal handler for SIGTERM,
*/
static void sigterm_handler(int signum) {
/* ignore further signals as we are going to quit anyway */
signal(signum, SIG_IGN );
if (rank == 0) {
fflush(stdout);
printf("\nBenchIT: Received SIGTERM, Aborting...\n");
fflush(stdout);
}
finish(1);
}
/**
* Abort function that should be used by the kernels instead of doing an exit(err)
*/
void bi_abort(int err) {
if (rank == 0) {
fflush(stdout);
printf("\nBenchIT: Received Abort, Aborting...\n");
fflush(stdout);
}
finish(err);
}
/*!@brief Monstrous main function doing everything BenchIT consists of.
*
* This function initializes the kernel, runs the measurements and writes
* the result-file.
* @param argc Standard main argument.
* @param argv Standard main argument.
* @return 0 on success, >0 on failure.
*/
int main(int argc, char** argv) {
#ifdef USE_MPI
/*
* will contain the number of MPI processes
*/
int size;
#endif
#ifdef USE_PAPI
int papi_ver;
#endif
/*
* todoList: what problemsizes have to be calculated
* doneList: what problemsizes have been calculated
*/
int *todoList = NULL, *doneList = NULL;
/*
* will contain results temporarily of one bi_entry_call for one problemsize
*/
double *tmpResults = NULL;
/*
* variables are used for check, how long this process is running
*/
double totalstart = 0, time2 = 0;
/*
* is the timelimit reached?
*/
int timelimit_reached = 0;
/* iterator vor the progress output */
int percent;
/*
* errno.h dosn't set errno to 0, so a check !=0 would fail
*/errno = 0;
/*****************************************************************************
* Initialization
*/
/* start VAMPIR */
#ifdef VAMPIR_TRACE
(void) _vptsetup();
(void) _vptenter(300);
#endif
/* start MPI */
#ifdef USE_MPI
IDL(2,printf("MPI_Init()..."));
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&size);
IDL(2,printf(" [OK]\n"));
#else
/* set rank to 0 becaues only one process exists */
rank = 0;
/* size=1; */
#endif
#ifdef USE_PAPI
IDL(2,printf("PAPI_library_init()..."));
papi_ver = PAPI_library_init(PAPI_VER_CURRENT);
if (papi_ver != PAPI_VER_CURRENT) safe_exit(1);
IDL(2,printf(" [OK]\n"));
#endif
/* initialize hashtable for environment variables */
bi_initTable();
/* and fill it */
bi_fillTable();
/* check the command line arguments for flags */
checkCommandLine(argc, argv);
d_bi_start_sec = (double) ((long long) bi_gettimeofday());
/* getting timer granularity and overhead */
/* these variables can also be accessed by the kernel */
dTimerOverhead = 0.0;
dTimerGranularity = 1.0;
/* select MPI-timer or standard timer or... */
selectTimer();
/* only first process shall write this */
if (rank == 0) {
printf("BenchIT: Timer granularity: %.9g ns\n", dTimerGranularity * 1e9);
printf("BenchIT: Timer overhead: %.9g ns\n", dTimerOverhead * 1e9);
}
/* get the time limit */
char* p = bi_getenv("BENCHIT_RUN_TIMELIMIT", 0);
/* if the environment variable is set use it */
if (p != 0){
timelimit = atoi(p);
freeCheckedC(&p);
/* if not, use standard */
}else
timelimit = DEFAULT_TIMELIMIT;
/* the same for this environment variable */
p = bi_getenv("BENCHIT_RUN_ACCURACY", 0);
if (p != 0){
accuracy = atoi(p);
freeCheckedC(&p);
}else
accuracy = DEFAULT_ACCURACY;
/* prompt info */
if (rank == 0) {
printf("BenchIT: Getting info about kernel...");
fflush(stdout);
}
/* fill theInfo with 0s (NOT '0's) */
(void) memset(&theInfo, 0, sizeof(theInfo));
/* get info from kernel */
bi_getinfo(&theInfo);
/* offset: number of functions from kernel +1 */
offset = theInfo.numfunctions + 1;
dataPointCt = theInfo.num_measurements * (accuracy + 1);
numDataPointsPerX = (accuracy + 1) * theInfo.numfunctions + 1;
/* print info */
if (rank == 0) {
printf(" [OK]\nBenchIT: Getting starting time...");
fflush(stdout);
}
/* starting time used for timelimit */
totalstart = bi_gettimeofday();
/* print info */
if (rank == 0) {
char *kernelString = bi_getenv("BENCHIT_KERNELNAME", 1);
printf(" [OK]\nBenchIT: Selected kernel: \"%s\"\n", kernelString != 0 ? kernelString : "NULL");
fflush(stdout);
printf("BenchIT: Initializing kernel...");
fflush(stdout);
}
/* initialize kernel */
#ifdef BENCHIT_ECOLAB_DEBUG
BENCHIT_ECOLAB_PRINT("Initializing Kernel");
#endif
mcb = bi_init(theInfo.num_measurements);
/* print info */
if (rank == 0) {
printf(" [OK]\n");
fflush(stdout);
printf("BenchIT: Allocating memory for results...");
fflush(stdout);
/* all results, which will be measured for one problemsize */
allResults = (double*) malloc((size_t) theInfo.num_measurements * (size_t) numDataPointsPerX * sizeof(double));
//Reset all values to x=0 (not measured) and y=invalid to detect aborts
for (i = 0; i < theInfo.num_measurements; i++) {
//x
allResults[i * numDataPointsPerX] = INVALID_MEASUREMENT;
//y
for (j = 1; j < numDataPointsPerX; j++)
allResults[i * numDataPointsPerX + j] = INVALID_MEASUREMENT;
}
/* results, which will be measured with a single call of bi_entry */
tmpResults = (double*) calloc((size_t) offset, sizeof(double));
//Init results
int error = initResults(theInfo);
/* if a malloc didnt work */
if (allResults == 0 || tmpResults == 0 || error != 0) {
printf(" [FAILED]\n");
printf(" allResults: %lx, tmpResults: %lx, initError: %lx \n", (unsigned long) allResults, (unsigned long) tmpResults,
(unsigned long) error);
cleanUp(1);
} else {
printf(" [OK]\n");
fflush(stdout);
}
}
/* build list for done problemsizes and todo problemsizes */
todoList = (int*) calloc((size_t) theInfo.num_measurements + 2, sizeof(int));
doneList = (int*) calloc((size_t) theInfo.num_measurements + 1, sizeof(int));
/* did malloc work? */
if (todoList == 0 || doneList == 0) {
printf(" [FAILED]\n");
cleanUp(1);
}
/* setup signalhandlers */
signal(SIGINT, sigint_handler);
signal(SIGTERM, sigterm_handler);
/*****************************************************************************
* Measurement
*/
/* print info */
if (rank == 0) {
printf("BenchIT: Measuring...\n");
fflush(stdout);
}
if (rank == 0 && DEBUGLEVEL == 0) {
if (bi_getenv("BENCHIT_PROGRESS_DIR", 0) != NULL && strcmp(bi_getenv("BENCHIT_PROGRESS_DIR", 0), "") && !bi_standalone) {
size_t size = strlen(bi_getenv("BENCHITROOT", 0)) + strlen(bi_getenv("BENCHIT_PROGRESS_DIR", 0))
+ strlen(bi_getenv("BENCHIT_KERNELNAME", 0)) + 25;
char* tmp;
progf = (char*) calloc(size, 1);
sprintf(progf, "%s", bi_getenv("BENCHIT_PROGRESS_DIR", 0));
if (progf[0] != '/') {
memset(progf, 0, size);
sprintf(progf, "%s/%s", bi_getenv("BENCHITROOT", 0), bi_getenv("BENCHIT_PROGRESS_DIR", 0));
}
createDirStructureOrExit(progf);
memset(progf, 0, size);
progf += strlen(bi_getenv("BENCHITROOT", 0)) + 1;
tmp = progf;
if (progf[0] == '\"')
tmp++;
sprintf(progf, "%s", bi_getenv("BENCHIT_PROGRESS_DIR", 0));
if (progf[strlen(progf) - 1] == '\"')
progf[strlen(progf) - 1] = '\0';
if (progf[strlen(progf) - 1] != '/')
progf[strlen(progf)] = '/';
progf += strlen(progf);
sprintf(progf, "%s_", bi_getenv("BENCHIT_KERNELNAME", 0));
progf += strlen(bi_getenv("BENCHIT_KERNELNAME", 0)) + 1;
sprintf(progf, "%018.6f", bi_gettimeofday());
if (tmp[0] != '/') {
tmp--;
tmp[0] = '/';
tmp -= strlen(bi_getenv("BENCHITROOT", 0));
strncpy(tmp, bi_getenv("BENCHITROOT", 0), strlen(bi_getenv("BENCHITROOT", 0)));
}
progf = tmp;
prog_file = fopen(progf, "w");
if (prog_file != NULL ) {
printf("BenchIT: writing progress information to file: %s\n", progf);
fprintf(prog_file, "progress: 0%%\n");
fflush(prog_file);
} else
printf("could not create file for writing progress information\n");
}
printf("progress scale (percent):\n");
printf("0--------20--------40--------60--------80-------100\n");
printf("progress:\n");
fflush(stdout);
}
/* as long as there are still some problems (todo-/done-lists can be created) to measure */
/* and we didnt exceed the timelimit do */
while (get_new_problems(todoList, doneList, theInfo.num_measurements) && !timelimit_reached) {
/* do accuracy+1 measurement */
for (w = 0; w <= accuracy; w++) {
/* as long as ther is something in the todoList and the time limit isn't reached do measure */
curTodoIndex = 0;
while ((todoList[++curTodoIndex] != 0) && !timelimit_reached) {
int curProblemSize = todoList[curTodoIndex];
IDL(2, printf("Testing with problem size %d\n", curProblemSize));
/* if MPI is used, set a barrier to synchronize */
#ifdef USE_MPI
if (theInfo.kernel_execs_mpi1 != 0) MPI_Barrier(MPI_COMM_WORLD);
#endif
IDL(2, printf(" entering(%d)...\n", rank));
/* do measurement for non-MPI or first MPI-process */
if (rank == 0)
flag = bi_entry(mcb, curProblemSize, tmpResults);
else {
if ((theInfo.kernel_execs_mpi1 != 0) || (theInfo.kernel_execs_mpi2 != 0))
flag = bi_entry(mcb, curProblemSize, 0);
else {
printf("\nBenchIT: Warning: Maybe you should check the bi_getinfo funktion\n");
printf("\nBenchIT: infostruct->kernel_execs_mpi1 = 0 AND\n");
printf("\nBenchIT: infostruct->kernel_execs_mpi2 = 0 ???\n");
}
}
/* for timelimit check */
time2 = bi_gettimeofday();
IDL(2, printf(" leaving(%d)...\n", rank));
/* was sth else then 0 returned? */
if (flag != 0) {
/* finalize ;) */
if (rank == 0)
printf(" [FAILED]\nBenchIT: Internal kernel error. \n");
cleanUp(1);
} else {
/* if everything is fine: */
/* say: this problemsize is done */
doneList[curProblemSize] = 1;
}
/* only the first one needs to do this */
if (rank == 0) {
IDL(3, printf("tmpResults="));
for (i = 0; i < offset; i++) {
IDL(3, printf(" %g", tmpResults[i]))
}
IDL(3, printf("\n"));
//holds index of current x
int curRow = numDataPointsPerX * (curProblemSize - 1);
if (w == 0)
allResults[curRow] = tmpResults[0];
for (i = 0; i < theInfo.numfunctions; i++) {
//accuracy+1: values per function; w: current run; +1: skip over x
allResults[curRow + i * (accuracy + 1) + w + 1] = tmpResults[i + 1];
}
}
/* another barrier for synchronization */
#ifdef USE_MPI
if (theInfo.kernel_execs_mpi1 != 0) MPI_Barrier(MPI_COMM_WORLD);
#endif
/* timelimit reached? */
if ((timelimit > 0) && ((time2 - totalstart) > timelimit)) {
if (rank == 0)
printf("[BREAK]\nBenchIT: Total time limit reached. Stopping measurement.");
timelimit_reached = 1;
break;
}
/* write progress information to file if available */
if ((rank == 0) && (DEBUGLEVEL == 0)) {
n++;
for (percent = 100; percent >= 0; percent -= 2) {
if (100 * n / dataPointCt >= percent && 100 * (n - 1) / dataPointCt < percent)
printf(".");
}
fflush(stdout);
if ((100 * n / dataPointCt != 100 * (n - 1) / dataPointCt) && prog_file != NULL ) {
if (truncate(progf, 0) == 0)
fprintf(prog_file, "progress: %i%%\n", 100 * n / (theInfo.num_measurements * (accuracy + 1)));
fflush(prog_file);
}
}
} /* while (todoList...)*/
} /* for(w=-1;w<accuracy;w++) */
IDL(2, printf("...OK\n"));
} /* while (get_new_pr...)*/
IDL(0,printf("\n"));
finish(0);
return 0;
}
/*!@brief Starts the measurement timer
*
* This function is basicly a wrapper for bi_gettime() but also allows for using bi_stopTimer()
*
* @return The current timestamp as returned by bi_gettime
*/
double bi_startTimer() {
biStartTimeAbs = bi_gettimeofday_improved();
biStartTime = bi_gettime();
return biStartTime;
}
/*!@brief Stops the measurement timer and returns the elapsed seconds
*
* Calculates the elapsed time since the start if bi_startTimer
* WARNING: Results are undefined without a previous call to bi_startTimer.
* Do NOT mix with calls of bi_gettime
*
* @return The elapsed time cleaned by overhead or INVALID_MEASUREMENT if below granularity
*/
double bi_stopTimer() {
double stopTime = bi_gettime();
double diff = stopTime - biStartTime - dStartTimerOverhead;
biStopTimeAbs = biStartTimeAbs + diff;
if (diff < dTimerGranularity) {
return INVALID_MEASUREMENT;
}
return diff;
}
/*!@brief Stops the measurement timer and returns the elapsed seconds.
* Additionally returns timestamps of start/stop in startStop[2]
*
* Calculates the elapsed time since the start if bi_startTimer and prepares the system to get the consumed energy
* WARNING: Results are undefined without a previous call to bi_startTimer.
* Do NOT mix with calls of bi_gettime
*
* @return The elapsed time cleaned by overhead or INVALID_MEASUREMENT if below granularity
*/
double bi_getStartStopTime(double *startStop) {
double diff = bi_stopTimer();
startStop[0] = biStartTimeAbs;
startStop[1] = biStopTimeAbs;
return 0;