1+ target C
2+
3+ /**
4+ * Reactor that starts the kernel of a benchmark, measures its runtime and outputs the results for a
5+ * given number of iterations.
6+ *
7+ * This reactor is instantiated by the main reactor of a benchmark and the startup reaction of this
8+ * reactor is the starting point for that benchmark. The reactor runs a given number of iterations
9+ * of the benchmark, measures the runtime of each iteration and outputs them. The benchmark itself
10+ * is responsible to reset its state between the iterations. A benchmark can have an optional
11+ * initialization phase that is run once before the first iteration and is not measured. A benchmark
12+ * can have an optional cleanup phase after each iteration before the next iteration start which is
13+ * not considered in the runtime measurement.
14+ *
15+ * How to use:
16+ * - Instantiate this reactor in the main reactor of the benchmark.
17+ * - Connect the ports start, finish with the appropriate reactors of the benchmark.
18+ * - Create a startup reaction in the main reactor that calls printBenchmarkInfo(),
19+ *
20+ * Prototype startup reaction in the main reactor of a benchmark: runner = new
21+ * BenchmarkRunner(num_iterations=num_iterations); reaction(startup) {=
22+ * printBenchmarkInfo("ThreadRingReactorLFCppBenchmark"); printSystemInfo();
23+ * =}
24+ *
25+ * @param num_iterations How many times to execute the kernel of the benchmark to measure.
26+ *
27+ * @author Hannes Klein
28+ * @author Shaokai Lin
29+ * @author Matt Chorlian
30+ * @author Arthur Deng
31+ */
32+ preamble {=
33+ #include <stdio.h>
34+ =}
35+
36+ reactor BenchmarkRunner(num_iterations: size_t = 12) {
37+ /** Signal to start execution. Set this input from a startup reaction in the main reactor. */
38+ input inStart: bool
39+
40+ /** Signals for starting and finishing the kernel and runtime measurement. */
41+ output start: bool
42+ input finish: bool
43+
44+ /** Events to switch between the phases of running the iterations. */
45+ logical action nextIteration
46+ logical action done
47+
48+ /** Number of iterations already executed. */
49+ state count: unsigned = 0
50+
51+ /** Start time for runtime measurement. */
52+ state startTime: instant_t
53+
54+ /** Runtime measurements. */
55+ state measuredTimes: interval_t*
56+
57+ preamble {=
58+ static double toMS(interval_t t) {
59+ return t / 1000000.0;
60+ }
61+
62+ int comp (const void * elem1, const void * elem2) {
63+ int f = *((double*)elem1);
64+ int s = *((double*)elem2);
65+ if (f > s) return 1;
66+ if (f < s) return -1;
67+ return 0;
68+ }
69+
70+ static double median(double* execTimes, int size) {
71+ if (size == 0) {
72+ return 0.0;
73+ }
74+
75+ int middle = size / 2;
76+ if(size % 2 == 1) {
77+ return execTimes[middle];
78+ } else {
79+ return (execTimes[middle-1] + execTimes[middle]) / 2;
80+ }
81+ }
82+
83+ static double* getMSMeasurements(interval_t* measured_times, int num_iterations) {
84+
85+ double* msMeasurements = (double *) calloc(num_iterations, sizeof(double));
86+ for (int i = 0; i < num_iterations; i++) {
87+ msMeasurements[i] = toMS(measured_times[i]);
88+ }
89+
90+ return msMeasurements;
91+ }
92+ =}
93+
94+ preamble {=
95+ void printBenchmarkInfo(char* benchmarkId) {
96+ printf("Benchmark: %s\n", benchmarkId);
97+ }
98+
99+ void printSystemInfo() {
100+
101+ printf("System information\n");
102+ printf("O/S Name: ");
103+
104+ #ifdef _WIN32
105+ printf("Windows 32-bit");
106+ #elif _WIN64
107+ printf("Windows 64-bit");
108+ #elif __APPLE__ || __MACH__
109+ printf("Mac OSX");
110+ #elif __linux__
111+ printf("Linux");
112+ #elif __FreeBSD__
113+ printf("FreeBSD");
114+ #elif __unix || __unix__
115+ printf("Unix");
116+ #else
117+ printf("Other");
118+ #endif
119+
120+ printf("\n");
121+ }
122+ =}
123+
124+ reaction(startup) -> nextIteration {=
125+ // Initialize an array of interval_t
126+ self->measuredTimes = (interval_t *) calloc(self->num_iterations, sizeof(interval_t));
127+ lf_schedule(nextIteration, 0);
128+ =}
129+
130+ reaction(nextIteration) -> start, done {=
131+ if (self->count < self->num_iterations) {
132+ self->startTime = lf_time_physical();
133+ lf_set(start, true);
134+ } else {
135+ lf_schedule(done, 0);
136+ }
137+ =}
138+
139+ reaction(finish) -> nextIteration {=
140+ interval_t end_time = lf_time_physical();
141+ interval_t duration = end_time - self->startTime;
142+ self->measuredTimes[self->count] = duration;
143+ self->count += 1;
144+
145+ printf("Iteration %d - %.3f ms\n", self->count, toMS(duration));
146+
147+ lf_schedule(nextIteration, 0);
148+ =}
149+
150+ reaction(done) {=
151+ double* measuredMSTimes = getMSMeasurements(self->measuredTimes, self->num_iterations);
152+ qsort(measuredMSTimes, self->num_iterations, sizeof(double), comp);
153+
154+ printf("Execution - Summary:\n");
155+ printf("Best Time:\t %.3f msec\n", measuredMSTimes[0]);
156+ printf("Worst Time:\t %.3f msec\n", measuredMSTimes[self->num_iterations - 1]);
157+ printf("Median Time:\t %.3f msec\n", median(measuredMSTimes, self->num_iterations));
158+ lf_request_stop();
159+ =}
160+ }
0 commit comments