summaryrefslogtreecommitdiffstats
path: root/baseline/source/extra.h
diff options
context:
space:
mode:
authorJoshua Bakita <jbakita@cs.unc.edu>2020-10-18 00:24:06 -0400
committerJoshua Bakita <jbakita@cs.unc.edu>2020-10-18 00:24:06 -0400
commit41358857592f1908d0c0f9898b6c9acabc1ad161 (patch)
tree3ca3bf4ce9c5a2b34eaa991dc73a2e055c67e3e4 /baseline/source/extra.h
parente5db76ee18640ce27df8756e573ef8b497af4750 (diff)
Rewrite extra.h for task baselines to be easier to use
New macro `for_each_job` simplifies instrumentation. Backwards-compatible.
Diffstat (limited to 'baseline/source/extra.h')
-rw-r--r--baseline/source/extra.h275
1 files changed, 163 insertions, 112 deletions
diff --git a/baseline/source/extra.h b/baseline/source/extra.h
index 02e97af..e8f3d18 100644
--- a/baseline/source/extra.h
+++ b/baseline/source/extra.h
@@ -53,45 +53,60 @@ extern int sched_getcpu();
53#define LOAD_PARAMS LOAD_PARAMS_ITRL 53#define LOAD_PARAMS LOAD_PARAMS_ITRL
54#endif 54#endif
55 55
56// Store state globally so that the job can be outside main()
57// Arrays use float as a comprimise between overflow and size
58float *_rt_exec_time;
59#if MMDC_PERF
60float *_rt_mmdc_read;
61float *_rt_mmdc_write;
62#endif
63long _rt_jobs_complete;
64long _rt_max_jobs;
65int _rt_core;
66int _rt_will_output;
67struct timespec _rt_start, _rt_end;
68
69char *_rt_run_id;
70char *_rt_our_prog_name;
71#define _RT_FILENAME_LEN 64
72
56#define LOAD_PARAMS_ITRL \ 73#define LOAD_PARAMS_ITRL \
57 if (argc != 6) { \ 74 if (argc != 6) { \
58 fprintf(stderr, "Usage: %s <name> <loops> <my core> <runID> <save results?>\n", argv[0]);\ 75 fprintf(stderr, "Usage: %s <name> <loops> <my core> <runID> <save results?>\n", argv[0]);\
59 fprintf(stderr, " <loops> integer number of iterations. -1 for infitite.\n");\ 76 fprintf(stderr, " <loops> integer number of iterations. -1 for infitite.\n");\
60 fprintf(stderr, " <save results?> 1 to save results, 0 to discard.\n");\ 77 fprintf(stderr, " <save results?> 1 to save results, 0 to discard.\n");\
78 fprintf(stderr, " <my core> UNUSED. Core is now auto-detected.\n");\
79 exit(1);\
80 }\
81 _rt_our_prog_name = argv[1];\
82 _rt_max_jobs = atol(argv[2]);\
83 _rt_core = sched_getcpu();\
84 _rt_run_id = argv[4];\
85 _rt_will_output = atoi(argv[5]);\
86 if (_rt_max_jobs < 0 && _rt_will_output != 0) {\
87 fprintf(stderr, "Infinite loops only supported when _rt_will_output is disabled!\n");\
61 exit(1);\ 88 exit(1);\
62 }\ 89 }\
63 char *thisProgram=argv[1];\ 90 if (strlen(_rt_run_id) + 5 > _RT_FILENAME_LEN) {\
64 int parsedMaxJobs=atoi(argv[2]);\ 91 fprintf(stderr, "Run ID is too large! Keep it to less than %d characters.\n", _RT_FILENAME_LEN);\
65 unsigned int thisCore=atoi(argv[3]);\
66 thisCore = sched_getcpu();\
67 char *runID=argv[4];\
68 int output=atoi(argv[5]);\
69 if (parsedMaxJobs < 0 && output != 0){\
70 fprintf(stderr, "Infinite loops only supported when output is disabled!\n");\
71 exit(1);\ 92 exit(1);\
72 }\ 93 }\
73 /* Cheat. -1 is larger than jobsComplete can ever reach. */\ 94 _rt_exec_time = calloc(_rt_max_jobs * _rt_will_output, sizeof(float));\
74 unsigned int maxJobs = parsedMaxJobs;\ 95 if (!_rt_exec_time) {\
75 struct timespec _start, _end;\ 96 perror("Unable to allocate buffer for execution times");\
76 int jobsComplete;\
77 int jobs_complete = -1;\
78 float *progTime = malloc(sizeof(float)*maxJobs*output);\
79 memset(progTime, 0, sizeof(float)*maxJobs*output);\
80 char fileName[64];\
81 float *mmdc_read = malloc(sizeof(float)*maxJobs*output);\
82 float *mmdc_write = malloc(sizeof(float)*maxJobs*output);\
83 memset(mmdc_read, 0, sizeof(float)*maxJobs*output);\
84 memset(mmdc_write, 0, sizeof(float)*maxJobs*output);\
85 if (strlen(runID) + 5 > sizeof(fileName)) {\
86 fprintf(stderr, "Run ID is too large! Keep it to less than 60 characters.\n");\
87 exit(1);\ 97 exit(1);\
88 }\ 98 }\
89 strcpy(fileName, runID);\ 99 _rt_jobs_complete = 0;\
90 strcat(fileName, ".txt");\
91 mlockall(MCL_CURRENT || MCL_FUTURE); 100 mlockall(MCL_CURRENT || MCL_FUTURE);
92 101
93#define SETUP_MMDC \ 102#define SETUP_MMDC \
94 MMDC_PROFILE_RES_t mmdc_res; \ 103 _rt_mmdc_read = calloc(_rt_max_jobs * _rt_will_output, sizeof(float));\
104 _rt_mmdc_write = calloc(_rt_max_jobs * _rt_will_output, sizeof(float));\
105 if (!_rt_mmdc_read || !_rt_mmdc_write) {\
106 perror("Unable to allocate buffer for MMDC data");\
107 exit(1);\
108 }\
109 MMDC_PROFILE_RES_t mmdc_res;\
95 memset(&mmdc_res, 0, sizeof(MMDC_PROFILE_RES_t));\ 110 memset(&mmdc_res, 0, sizeof(MMDC_PROFILE_RES_t));\
96 int fd = open("/dev/mem", O_RDWR, 0);\ 111 int fd = open("/dev/mem", O_RDWR, 0);\
97 if (fd < 0) {\ 112 if (fd < 0) {\
@@ -107,9 +122,8 @@ extern int sched_getcpu();
107 msync(&(mmdc->madpcr1),4,MS_SYNC); 122 msync(&(mmdc->madpcr1),4,MS_SYNC);
108 123
109#define SETUP_LITMUS \ 124#define SETUP_LITMUS \
110 unsigned int cpu = atoi(thisCore); \
111 unsigned int wait = 0; \ 125 unsigned int wait = 0; \
112 if (be_migrate_to_domain(cpu) < 0) { \ 126 if (be_migrate_to_domain(_rt_core) < 0) { \
113 perror("Unable to migrate to specified CPU"); \ 127 perror("Unable to migrate to specified CPU"); \
114 exit(1); \ 128 exit(1); \
115 } \ 129 } \
@@ -176,54 +190,6 @@ extern int sched_getcpu();
176 } \ 190 } \
177 reservation_destroy(gettid(), rt_param.cpu); 191 reservation_destroy(gettid(), rt_param.cpu);
178 192
179#if MMDC_PROF
180#define SAVE_RESULTS \
181 if(jobs_complete >= maxJobs) {\
182 fprintf(stderr, "Max jobs setting too small! Trying to record job #%d when we only have space for %d jobs. Exiting...\n", jobs_complete, maxJobs);\
183 exit(1);\
184 }\
185 if(jobs_complete > -1 && output) {\
186 progTime[jobs_complete] = _end.tv_sec - _start.tv_sec;\
187 progTime[jobs_complete] *= 1000000000;\
188 progTime[jobs_complete] += _end.tv_nsec - _start.tv_nsec;\
189 mmdc_read[jobs_complete] = mmdc_res.read_bytes;\
190 mmdc_write[jobs_complete] = mmdc_res.write_bytes;\
191 }
192#else
193#define SAVE_RESULTS \
194 if(jobs_complete >= maxJobs) {\
195 fprintf(stderr, "Max jobs setting too small! Trying to record job #%d when we only have space for %d jobs. Exiting...\n", jobs_complete, maxJobs);\
196 exit(1);\
197 }\
198 if(jobs_complete > -1 && output) {\
199 progTime[jobs_complete] = _end.tv_sec - _start.tv_sec;\
200 progTime[jobs_complete] *= 1000000000;\
201 progTime[jobs_complete] += _end.tv_nsec - _start.tv_nsec;\
202 }
203#endif
204
205
206#if LITMUS
207#define WRITE_TO_FILE WRITE_TO_FILE_ITRNL CLEANUP_LITMUS
208#else
209#define WRITE_TO_FILE WRITE_TO_FILE_ITRNL
210#endif
211
212#define WRITE_TO_FILE_ITRNL if (output){\
213 munlockall();\
214 FILE *fp=fopen(fileName, "a");\
215 if (fp == NULL) {\
216 perror("Unable to open output file");\
217 exit(1);\
218 }\
219 for (int i = 0; i <= jobs_complete; i++){\
220 fprintf(fp, "%s none %u none %d %.f %s %d %.f %.f \n",\
221 thisProgram, thisCore, maxJobs,\
222 progTime[i], runID, i, mmdc_read[i], mmdc_write[i]);\
223 }\
224 fclose(fp);\
225}
226
227#if __arm__ 193#if __arm__
228// On ARM, manually flush the cache 194// On ARM, manually flush the cache
229#define FLUSH_CACHES \ 195#define FLUSH_CACHES \
@@ -247,53 +213,138 @@ extern int sched_getcpu();
247 fclose(fp); 213 fclose(fp);
248#endif 214#endif
249 215
216// Buffer timing result from a single job
217static void _rt_save_job_result() {
218 if (_rt_jobs_complete >= _rt_max_jobs) {
219 fprintf(stderr, "Max jobs setting too small! Trying to record job #%ld when we only have space for %ld jobs. Exiting...\n", _rt_jobs_complete, _rt_max_jobs);
220 exit(1);
221 }
222 if (_rt_jobs_complete > -1 && _rt_will_output) {
223 _rt_exec_time[_rt_jobs_complete] = _rt_end.tv_sec - _rt_start.tv_sec;
224 _rt_exec_time[_rt_jobs_complete] *= 1e9;
225 _rt_exec_time[_rt_jobs_complete] += _rt_end.tv_nsec - _rt_start.tv_nsec;
250#if MMDC_PROF 226#if MMDC_PROF
251#define START_TIMER \ 227 _rt_mmdc_read[_rt_jobs_complete] = mmdc_res.read_bytes;
252 /* This disables profiling, resets the counters, clears the overflow bit, and enables profiling */ \ 228 _rt_mmdc_write[_rt_jobs_complete] = mmdc_res.write_bytes;
253 start_mmdc_profiling(mmdc); \
254 /*nanosleep(&(struct timespec){0, ms2ns(999)}, NULL);*/ \
255 clock_gettime(CLOCK_MONOTONIC, &_start);
256#else
257#define START_TIMER clock_gettime(CLOCK_MONOTONIC, &_start);
258#endif 229#endif
230 }
231}
259 232
233// Save all buffered timing results to disk
234static void _rt_write_to_file() {
235 char fileName[_RT_FILENAME_LEN];
236 FILE *fp;
237 if (!_rt_will_output)
238 return;
239 munlockall();
240 strcpy(fileName, _rt_run_id);
241 strcat(fileName, ".txt");
242 fp = fopen(fileName, "a");
243 if (fp == NULL) {
244 perror("Unable to open _rt_will_output file");
245 exit(1);
246 }
247 // Same format as the paired results with "none" for unused fields
248 for (int i = 0; i < _rt_jobs_complete; i++){
249 fprintf(fp, "%s none %u none %ld %.f %s %d %.f %.f \n",
250 _rt_our_prog_name, _rt_core, _rt_max_jobs,
251 _rt_exec_time[i], _rt_run_id, i,
260#if MMDC_PROF 252#if MMDC_PROF
261#define STOP_TIMER \ 253 _rt_mmdc_read[i], _rt_mmdc_write[i]);
262 clock_gettime(CLOCK_MONOTONIC, &_end); \
263 /* This freezes the profiling and makes results available */ \
264 pause_mmdc_profiling(mmdc); \
265 get_mmdc_profiling_results(mmdc, &mmdc_res);
266#else 254#else
267#define STOP_TIMER clock_gettime(CLOCK_MONOTONIC, &_end); 255 0.0, 0.0);
268#endif 256#endif
257 }
258 fclose(fp);
259#if LITMUS
260 CLEANUP_LITMUS
261#endif
262}
269 263
270#define SLEEP nanosleep((const struct timespec[]){{0, 1000000}}, NULL); 264// Start a job
271 265static void _rt_start_loop() {
272#if LITMUS 266#if LITMUS
273#define START_LOOP \ 267 if (sleep_next_period() != 0) {
274 if (sleep_next_period() != 0) { \ 268 perror("Unable to sleep for next period");
275 perror("Unable to sleep for next period"); \ 269 }
276 } \
277 FLUSH_CACHES START_TIMER
278#else 270#else
279#define START_LOOP sched_yield(); FLUSH_CACHES START_TIMER 271 sched_yield();
280#endif 272#endif
273 FLUSH_CACHES
274#if MMDC_PROF
275 /* This disables profiling, resets the counters, clears the overflow bit, and enables profiling */
276 start_mmdc_profiling(mmdc);
277#endif
278 clock_gettime(CLOCK_MONOTONIC, &_rt_start);
279}
281 280
282#define STOP_LOOP STOP_TIMER jobs_complete++; SAVE_RESULTS 281// Complete a job
283 282static void _rt_stop_loop() {
283 clock_gettime(CLOCK_MONOTONIC, &_rt_end);
284#if MMDC_PROF
285 /* This freezes the profiling and makes results available */
286 pause_mmdc_profiling(mmdc);
287 get_mmdc_profiling_results(mmdc, &mmdc_res);
288#endif
289 _rt_save_job_result();
290 _rt_jobs_complete++;
291}
284 292
285/* 293/****** New API ******
286Intended structure 294 * Intended structure:
295 *
296 * |int main(int argc, char **argv) {
297 * | SET_UP
298 * | ...
299 * | for_each_job {
300 * | tacleInit();
301 * | tacleMain();
302 * | }
303 * | WRITE_TO_FILE
304 * |}
305 *
306 * The main() function must call its parameters argc and argv for SET_UP to be
307 * able to read them.
308 * Only SET_UP necessarily has to be in main().
309 *
310 * We use some niche C features, here's a quick explaination:
311 * 1. The && operator doesn't evaluate the right-hand side of the expression
312 * unless the left side evaluated to true. We use this to only execute
313 * _rt_start_loop() when the loop will actually run.
314 * 2. The comma operator executes the first expression and then throws away the
315 * result. We use this to call our void function from inside a comparison.
316 */
317#define for_each_job \
318 for (; _rt_jobs_complete < _rt_max_jobs && (_rt_start_loop(),1); \
319 _rt_stop_loop())
287 320
288main 321/****** Legacy API ******
289SET_UP 322 * Intended structure:
290notice that STOP LOOP negates the ++ if outout=0 323 *
291for (jobsComplete=0; jobsComplete<maxJobs; jobsComplete++){ 324 * |int main(int argc, char **argv) {
292 START_LOOP 325 * | SET_UP
293 tacleInit(); 326 * | for (jobsComplete=0; jobsComplete<maxJobs; jobsComplete++){
294 tacleMain(); 327 * | START_LOOP
295 STOP_LOOP 328 * | tacleInit();
296} 329 * | tacleMain();
297WRITE_TO_FILE 330 * | STOP_LOOP
298tacleReturn 331 * | }
299*/ 332 * | WRITE_TO_FILE
333 * | tacleReturn
334 * |}
335 *
336 * The main() function must call its parameters argc and argv for SET_UP to be
337 * able to read them.
338 */
339static int jobsComplete = 0;
340#define START_LOOP _rt_start_loop();
341#define STOP_LOOP _rt_stop_loop();
342#define WRITE_TO_FILE _rt_write_to_file();
343#define maxJobs _rt_max_jobs
344// Has been part of STOP_LOOP for quite some time
345#define SAVE_RESULTS \
346 #warning "The SAVE_RESULTS macro is deprecated and will soon be removed!";
347// Unclear if SLEEP is used anywhere.
348#define SLEEP \
349 #warning "The SLEEP macro is deprecated and may be removed!" \
350 nanosleep((const struct timespec[]){{0, 1000000}}, NULL);