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
|
/**
* Copyright 2019 Sims Hill Osborne and Joshua Bakita
*
* This header provides facilities by which to separably run and time TACLeBench
**/
#include <time.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <limits.h>
#include <fcntl.h>
// These constants correspond to the imx6q-sabredb platform
#define LINE_SIZE 32
#define L2_SIZE 16*2048*32
#if __arm__
#include <unistd.h>
#include <sys/syscall.h>
#endif
#define LITMUS 1
#define MC2 1
#define MMDC_PROF 1
#if LITMUS
#include <litmus.h>
#endif
#if MMDC_PROF
#include "/media/speedy/litmus/tools/mmdc/mmdc.h"
#endif
#if LITMUS
#define SET_UP LOAD_PARAMS SETUP_LITMUS
#else
#define SET_UP LOAD_PARAMS
#endif
#if MMDC_PROF
#define LOAD_PARAMS LOAD_PARAMS_ITRL SETUP_MMDC
#else
#define LOAD_PARAMS LOAD_PARAMS_ITRL
#endif
#define LOAD_PARAMS_ITRL \
if (argc < 6) { \
printf("Usage: %s <name> <loops> <my core> <runID> <save results?>\n", argv[0]);\
exit(1);\
}\
char *thisProgram=argv[1];\
int maxJobs=atoi(argv[2]);\
char *thisCore=argv[3];\
char *runID=argv[4];\
int output=atoi(argv[5]);\
pid_t killMe;\
struct timespec start, end;\
int jobsComplete;\
int jobs_complete = -1;\
float progTime[maxJobs*output];\
memset(progTime, 0, sizeof(float)*maxJobs*output);\
char fileName[50];\
char *bigArray;\
int wasteCount;\
float mmdc_read[maxJobs];\
float mmdc_write[maxJobs];\
memset(mmdc_read, 0, sizeof(float)*maxJobs);\
memset(mmdc_write, 0, sizeof(float)*maxJobs);\
strcpy(fileName, runID);\
strcat(fileName, ".txt");\
mlockall(MCL_CURRENT || MCL_FUTURE);
#define SETUP_MMDC \
MMDC_PROFILE_RES_t mmdc_res; \
memset(&mmdc_res, 0, sizeof(MMDC_PROFILE_RES_t));\
int fd = open("/dev/mem", O_RDWR, 0);\
if (fd < 0) {\
perror("Unable to open /dev/mem");\
exit(1);\
}\
pMMDC_t mmdc = mmap(NULL, 0x4000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, MMDC_P0_IPS_BASE_ADDR);\
if (mmdc == MAP_FAILED) {\
perror("Unable to map MMDC address space");\
exit(1);\
}\
mmdc->madpcr1 = axi_arm1;\
msync(&(mmdc->madpcr1),4,MS_SYNC);
#define SETUP_LITMUS \
unsigned int cpu = atoi(thisCore); \
unsigned int wait = 0; \
if (be_migrate_to_domain(cpu) < 0) { \
perror("Unable to migrate to specified CPU"); \
exit(1); \
} \
struct reservation_config res; \
res.id = gettid(); \
res.cpu = cpu; \
res.priority = LITMUS_HIGHEST_PRIORITY; \
/* we take over half the CPU time (these are ns) */ \
res.polling_params.budget = ms2ns(3000); \
res.polling_params.period = ms2ns(3000); \
res.polling_params.offset = 0; \
res.polling_params.relative_deadline = ms2ns(3000); \
/* Not 100% sure that we should use periodic polling */ \
if (reservation_create(PERIODIC_POLLING, &res) < 0) { \
perror("Unable to create reservation"); \
exit(1); \
} \
struct rt_task rt_param; \
init_rt_task_param(&rt_param); \
/* Supposedly the next two parameters are irrelevant when reservations are enabled, but I'm leaving them anyway... */ \
rt_param.exec_cost = ms2ns(999); \
rt_param.period = ms2ns(1000); \
rt_param.priority = LITMUS_HIGHEST_PRIORITY; \
rt_param.cls = RT_CLASS_HARD; \
rt_param.release_policy = TASK_PERIODIC; \
rt_param.budget_policy = NO_ENFORCEMENT; \
rt_param.cpu = cpu; \
if (set_rt_task_param(gettid(), &rt_param) < 0) { \
perror("Unable to set real-time parameters"); \
exit(1); \
} \
if (init_litmus() != 0) { \
perror("init_litmus failed"); \
exit(1); \
} \
MC2_SETUP \
if (task_mode(LITMUS_RT_TASK) != 0) { \
perror("Unable to become real-time task"); \
exit(1); \
} \
if (wait && wait_for_ts_release() != 0) { \
perror("Unable to wait for taskset release"); \
exit(1); \
}
#if MC2
#define MC2_SETUP \
struct mc2_task mc2_param; \
mc2_param.res_id = gettid(); \
mc2_param.crit = CRIT_LEVEL_A; \
if (set_mc2_task_param(gettid(), &mc2_param) < 0) { \
perror("Unable to set MC^2 task params"); \
exit(1); \
} \
set_page_color(rt_param.cpu);
#else
#define MC2_SETUP
#endif
#define CLEANUP_LITMUS \
if (task_mode(BACKGROUND_TASK) != 0) { \
perror("Unable to become a real-time task"); \
exit(1); \
} \
reservation_destroy(gettid(), rt_param.cpu);
#if MMDC_PROF
#define SAVE_RESULTS \
if(jobs_complete>-1) {\
progTime[jobs_complete] = end.tv_sec - start.tv_sec;\
progTime[jobs_complete] *= 1000000000;\
progTime[jobs_complete] += end.tv_nsec - start.tv_nsec;\
mmdc_read[jobs_complete] = mmdc_res.read_bytes;\
mmdc_write[jobs_complete] = mmdc_res.write_bytes;\
}
#else
#define SAVE_RESULTS \
if(jobs_complete>-1) {\
progTime[jobs_complete] = end.tv_sec - start.tv_sec;\
progTime[jobs_complete] *= 1000000000;\
progTime[jobs_complete] += end.tv_nsec - start.tv_nsec;\
}
#endif
#if LITMUS
#define WRITE_TO_FILE WRITE_TO_FILE_ITRNL CLEANUP_LITMUS
#else
#define WRITE_TO_FILE WRITE_TO_FILE_ITRNL
#endif
#define WRITE_TO_FILE_ITRNL if (output){\
munlockall();\
FILE *fp=fopen(fileName, "a");\
if (fp == NULL) {\
perror("Error opening file. \n");\
exit(1);\
}\
for(int i = 0; i <= jobs_complete; i++){\
fprintf(fp, "%s none %s none %d %.f %s %d %.f %.f \n",\
thisProgram, thisCore, maxJobs,\
progTime[i], runID, i, mmdc_read[i], mmdc_write[i]);\
}\
fclose(fp);\
}
#if __arm__
// On ARM, manually flush the cache
#define FLUSH_CACHES \
volatile uint8_t buffer[L2_SIZE * 4]; \
for (uint32_t j = 0; j < 4; j++) \
for (uint32_t i = 0; i < L2_SIZE * 4; i += LINE_SIZE) \
buffer[i]++;
#else
// On x86 call the wbinvld instruction (it's in a kernel module due to it being ring-0)
#define FLUSH_CACHES \
FILE *fp = fopen("/proc/wbinvd", "r");\
if (fp == NULL) {\
perror("Cache flush module interface cannot be opened");\
exit(1);\
}\
char dummy;\
if (fread(&dummy, 1, 1, fp) == 0) {\
perror("Unable to access cache flush module interface");\
exit(1);\
}\
fclose(fp);
#endif
#if MMDC_PROF
#define START_TIMER \
/* This disables profiling, resets the counters, clears the overflow bit, and enables profiling */ \
start_mmdc_profiling(mmdc); \
/*nanosleep(&(struct timespec){0, ms2ns(999)}, NULL);*/ \
clock_gettime(CLOCK_MONOTONIC, &start);
#else
#define START_TIMER clock_gettime(CLOCK_MONOTONIC, &start);
#endif
#if MMDC_PROF
#define STOP_TIMER \
clock_gettime(CLOCK_MONOTONIC, &end); \
/* This freezes the profiling and makes results available */ \
pause_mmdc_profiling(mmdc); \
get_mmdc_profiling_results(mmdc, &mmdc_res);
#else
#define STOP_TIMER clock_gettime(CLOCK_MONOTONIC, &end);
#endif
#define SLEEP nanosleep((const struct timespec[]){{0, 1000000}}, NULL);
#if LITMUS
#define START_LOOP \
if (sleep_next_period() != 0) { \
perror("Unable to sleep for next period"); \
} \
FLUSH_CACHES START_TIMER
#else
#define START_LOOP FLUSH_CACHES START_TIMER
#endif
#define STOP_LOOP STOP_TIMER jobs_complete++; SAVE_RESULTS
/*
Intended structure
main
SET_UP
notice that STOP LOOP negates the ++ if outout=0
for (jobsComplete=-1; jobsComplete<maxJobs; jobsComplete++){
START_LOOP
tacleInit();
tacleMain();
STOP_LOOP
}
WRITE_TO_FILE
tacleReturn
*/
|