2 ** testbench_long_jump.c
4 ** Made by (Miguel marciano)
5 ** Login <miguel@namir.ctr.unican.es>
7 ** Started on Fri Nov 23 11:42:09 2007 Miguel marciano
8 ** Last update Sun May 12 01:17:25 2002 Speed Blue
14 Objective: To get the following overhead:
16 - fixed_abort_ovhd: install handler (only for worst case)
19 fosa_long_jump_was_performed
21 - fixed_memory_copy_ovhd: Copying memory areas of 0 bytes
22 - memory_copy_per_byte_ovhd: Variable copying memory areas per byte.
24 NOTES: I don't take the mutex
32 #include <time.h> // For clock_nanosleep
37 #include "frsh_error.h"
39 #include "frsh_fosa.h"
40 #include "timespec_operations.h"
44 /*************************/
45 /* D E F I N I T I O N S */
46 /*************************/
47 #define NUMBER_OF_TESTS 1000
49 static struct timespec minimum_budget_for_timer = {0, 100000}; // 100 us
51 #define NUMBER_OF_BYTES_TO_SIMULATE 10000 // Stack limit 40k in
52 // current MaRTE configuration
54 #define CALIBRATE_THREAD_PRIORITY (fosa_get_priority_min() + 4)
55 #define MAIN_THREAD_PRIORITY (fosa_get_priority_min() + 3)
56 #define MUTEX_CEILING (fosa_get_priority_min() + 10)
58 #define MINIMUM_BUDGET_FOR_TIMER_USECS 100
60 #define SIGNAL_CALIBRATE_FINISHED (FRSH_SIGNAL_MIN + 6)
63 typedef struct _individual_results_t
65 int first_time_passed;
66 int second_time_passed;
68 struct timespec first_interval;
70 /* The rest of min, max and average are taken over the REST of the
72 struct timespec average_interval;
73 struct timespec min_interval;
74 int iteration_min_interval;
75 struct timespec max_interval;
76 int iteration_max_interval;
77 struct timespec total_interval;
78 long int number_of_tries;
80 } individual_results_t;
82 typedef struct _thread_data_t
84 individual_results_t *results;
85 frsh_thread_id_t parent_tid;
88 typedef struct _measurements
90 individual_results_t fixed_abort_ovhd;
91 individual_results_t fixed_memory_copy_ovhd;
92 individual_results_t memory_copy_per_byte_ovhd;
96 /*************************/
97 /* P R O T O T Y P E S */
98 /*************************/
99 static void work_under_a_interruptible_budget();
101 static int frsh_sharedobj_calibrate(individual_results_t *fixed_abort_ovhd,
102 individual_results_t *fixed_memory_copy_ovhd,
103 individual_results_t *memory_copy_per_byte_ovhd);
105 static void *fixed_abort_ovhd_thread_code(void *thread_arg);
106 static void process_result(individual_results_t *results, struct timespec interval);
107 static void print_results(individual_results_t results);
109 static struct timespec timespec_divide_by_int(struct timespec numerator, long int denominator);
116 measurements_t measurements;
118 memset(&measurements, 0, sizeof(measurements) );
120 /* We set the signal mask */
122 PRW( frsh_sharedobj_calibrate(&measurements.fixed_abort_ovhd,
123 &measurements.fixed_memory_copy_ovhd,
124 &measurements.memory_copy_per_byte_ovhd) );
126 /* Print info here */
127 printf("FIXED ABORT OVHD:\n");
128 print_results(measurements.fixed_abort_ovhd);
129 printf("\n\nFIXED MEMORY COPY OVHD: \n");
130 print_results(measurements.fixed_memory_copy_ovhd);
131 printf("\n\nMEMORY COPY PER BYTE OVHD: \n");
132 print_results(measurements.memory_copy_per_byte_ovhd);
135 printf("End of test\n");
139 // -----------------------------------------------------------------
141 static int frsh_sharedobj_calibrate(individual_results_t *fixed_abort_ovhd,
142 individual_results_t *fixed_memory_copy_ovhd,
143 individual_results_t *memory_copy_per_byte_ovhd)
147 frsh_signal_t signal_set[1];
148 thread_data_t thread_data;
150 frsh_thread_attr_t calibrate_thread_attr;
151 frsh_thread_id_t calibrate_tid;
153 frsh_signal_t signal_received;
154 frsh_signal_info_t signal_info_received;
156 fosa_clock_id_t cpu_clock;
157 struct timespec initial_time = {-1, -1};
158 struct timespec final_time = {-1, -1};
160 char memory_region_source[NUMBER_OF_BYTES_TO_SIMULATE];
161 char memory_region_destination[NUMBER_OF_BYTES_TO_SIMULATE];
164 memset(&signal_set, 0, sizeof(signal_set) );
165 memset(&thread_data, 0, sizeof(thread_data) );
167 memset(&calibrate_thread_attr, 0, sizeof(calibrate_thread_attr) );
168 memset(&calibrate_tid, 0, sizeof(calibrate_tid) );
170 memset(&signal_received, 0, sizeof(signal_received) );
171 memset(&signal_info_received, 0, sizeof(signal_info_received) );
172 memset(&cpu_clock, 0, sizeof(cpu_clock) );
175 /* We set the signal mask and adjust our priority */
176 /**************************************************/
177 signal_set[0] = SIGNAL_CALIBRATE_FINISHED;
178 PRW( fosa_set_accepted_signals(signal_set, 1) );
179 PRW( fosa_thread_set_prio(fosa_thread_self(), MAIN_THREAD_PRIORITY) );
181 /* We get our CPU clock */
182 PRW( fosa_thread_get_cputime_clock( fosa_thread_self(), &cpu_clock) );
184 /* We measure the fixed_abort_ovhd */
185 /***********************************/
186 thread_data.results = fixed_abort_ovhd;
187 thread_data.parent_tid = pthread_self();
189 PRW( frsh_thread_attr_init(&calibrate_thread_attr) );
190 PRW( fosa_thread_attr_set_prio(&calibrate_thread_attr, CALIBRATE_THREAD_PRIORITY) );
192 PRW( fosa_thread_create(&calibrate_tid, &calibrate_thread_attr, fixed_abort_ovhd_thread_code,
195 /* We wait for the signal to arrive */
196 PRW( fosa_signal_wait(signal_set, 1, &signal_received, &signal_info_received) );
199 /* We measure fixed_memory_copy_ovhd */
200 /*************************************/
201 for(i = 0 ; i < NUMBER_OF_TESTS ; i++)
203 fosa_clock_get_time(FOSA_CLOCK_REALTIME, &initial_time); // Start measurement
204 memcpy(memory_region_destination, memory_region_source, 0);
205 fosa_clock_get_time(FOSA_CLOCK_REALTIME, &final_time); // End measurement
207 decr_timespec(&final_time, &initial_time);
209 process_result(fixed_memory_copy_ovhd, final_time);
212 fixed_memory_copy_ovhd->average_interval =
213 timespec_divide_by_int(fixed_memory_copy_ovhd->total_interval,
214 fixed_memory_copy_ovhd->number_of_tries - 1);
216 /* We measure memory_copy_per_byte_ovhd */
217 /****************************************/
218 for(i = 0 ; i < NUMBER_OF_TESTS ; i++)
220 fosa_clock_get_time(cpu_clock, &initial_time); // Start measurement
221 memcpy(memory_region_destination, memory_region_source, NUMBER_OF_BYTES_TO_SIMULATE);
222 fosa_clock_get_time(cpu_clock, &final_time); // End measurement
224 decr_timespec(&final_time, &initial_time);
226 final_time = timespec_divide_by_int(final_time, NUMBER_OF_BYTES_TO_SIMULATE / 1024);
228 process_result(memory_copy_per_byte_ovhd, final_time);
231 memory_copy_per_byte_ovhd->average_interval =
232 timespec_divide_by_int(memory_copy_per_byte_ovhd->total_interval,
233 memory_copy_per_byte_ovhd->number_of_tries - 1);
239 // ------------------------------------------------------------------------
241 typedef struct _protection_parameters
244 fosa_clock_id_t cpu_clock;
245 frsh_thread_id_t jump_handler_thread;
246 frsh_signal_t jump_signal;
247 frsh_signal_info_t jump_signal_info;
248 fosa_timer_id_t jump_timer;
249 } protection_parameters_t;
251 // ------------------------------------------------------------------------
253 static void *fixed_abort_ovhd_thread_code(void *thread_arg)
257 thread_data_t *thread_data = NULL;
258 individual_results_t *results = NULL;
260 protection_parameters_t protection_parameters;
262 frsh_signal_info_t signal_info_to_send;
265 memset(&protection_parameters, 0, sizeof(protection_parameters) );
266 memset(&signal_info_to_send, 0, sizeof(signal_info_to_send) );
267 memset(&mutex, 0, sizeof(mutex) );
269 thread_data = (thread_data_t *) thread_arg;
270 results = thread_data->results;
272 PXW( fosa_mutex_init(&mutex, MUTEX_CEILING) );
277 protection_parameters.initialised = false;
279 results->number_of_tries = 0;
280 while (results->number_of_tries < NUMBER_OF_TESTS)
283 struct timespec budget = {-1, -1};
284 static fosa_long_jump_context_t context;
286 struct timespec before_timestamp = {-1, -1 };
287 struct timespec after_timestamp = {-1, -1 };
290 /* We initialise variables */
292 memset(&before_timestamp, 0, sizeof(before_timestamp) );
293 memset(&after_timestamp, 0, sizeof(after_timestamp) );
296 budget.tv_nsec = MINIMUM_BUDGET_FOR_TIMER_USECS * 1000;
299 /* S T A R T M E A S U R I N G H E R E */
300 /*********************************************/
301 fosa_clock_get_time(FOSA_CLOCK_REALTIME, &before_timestamp);
304 /* This is only executed once per thread */
305 if (protection_parameters.initialised == false)
307 PXW( fosa_long_jump_install_handler(&protection_parameters.jump_signal,
308 &protection_parameters.jump_handler_thread) );
310 PXW( fosa_thread_get_cputime_clock( fosa_thread_self(), &protection_parameters.cpu_clock) );
311 protection_parameters.jump_signal_info.sival_ptr = &context;
313 PXW( fosa_timer_create_with_receiver(protection_parameters.cpu_clock,
314 protection_parameters.jump_signal,
315 protection_parameters.jump_signal_info,
316 &protection_parameters.jump_timer,
317 protection_parameters.jump_handler_thread) );
319 protection_parameters.initialised = true;
322 PXW( fosa_mutex_lock(&mutex) );
324 /* We arm the jump_timer */
325 PXW( fosa_timer_arm(protection_parameters.jump_timer, false, &budget) );
327 /* This is the point where the jump returns */
328 fosa_long_jump_save_context(&context);
330 /* Query if we come from a jump */
331 fosa_long_jump_was_performed(&context, &jumped);
334 /* HERE COMES THE WORK THAT CAN BE INTERRUPTED */
335 work_under_a_interruptible_budget();
336 PXW( fosa_timer_disarm(protection_parameters.jump_timer, NULL) );
337 PXW( fosa_mutex_unlock(&mutex) );
338 PERROR_AND_EXIT(FRSH_ERR_INTERNAL_ERROR, "The jump should always prevent us from arriving here\n");
341 PXW( fosa_mutex_unlock(&mutex) );
344 /* E N D O F M E A S U R I N G H E R E */
345 /***************************************************/
346 fosa_clock_get_time(FOSA_CLOCK_REALTIME, &after_timestamp);
348 decr_timespec(&after_timestamp, &before_timestamp);
350 decr_timespec(&after_timestamp, &minimum_budget_for_timer);
352 process_result(results, after_timestamp);
356 results->average_interval = timespec_divide_by_int(results->total_interval, results->number_of_tries - 1);
358 PXW( fosa_signal_queue(SIGNAL_CALIBRATE_FINISHED, signal_info_to_send, thread_data->parent_tid) );
364 // ------------------------------------------------------------------------------
366 static void work_under_a_interruptible_budget()
368 struct timespec upper_execution_limit = {1, 0};
370 frsh_eat(&upper_execution_limit);
373 // ------------------------------------------------------------------------------
375 static void process_result(individual_results_t *results, struct timespec interval)
377 results->number_of_tries++;
379 if (results->first_time_passed == 0)
381 results->first_interval = interval;
382 results->first_time_passed = 1;
384 else if (results->second_time_passed == 0)
386 results->max_interval = interval;
387 results->iteration_max_interval = results->number_of_tries;
389 results->min_interval = interval;
390 results->iteration_min_interval = results->number_of_tries;
392 results->second_time_passed = 1;
394 incr_timespec(&results->total_interval, &interval);
398 if (smaller_timespec(&results->max_interval, &interval) )
400 results->max_interval = interval;
401 results->iteration_max_interval = results->number_of_tries;
404 if (smaller_timespec(&interval, &results->min_interval) )
406 results->min_interval = interval;
407 results->iteration_min_interval = results->number_of_tries;
410 incr_timespec(&results->total_interval, &interval);
415 // ------------------------------------------------------------------------------
417 static void print_results(individual_results_t results)
419 assert(results.first_interval.tv_sec == 0);
420 assert(results.max_interval.tv_sec == 0);
421 assert(results.min_interval.tv_sec == 0);
422 assert(results.average_interval.tv_sec == 0);
424 printf("FIRST interval time: %d ns. All other stats apply to other invocations\n",
425 results.first_interval.tv_nsec);
427 printf("MAX interval time: %d ns at %d try, MIN interval time: %d ns at %d try\n",
428 results.max_interval.tv_nsec, results.iteration_max_interval,
429 results.min_interval.tv_nsec, results.iteration_min_interval);
431 printf("AVERAGE interval time: %d ns, Number of tries %ld\n",
432 results.average_interval.tv_nsec, results.number_of_tries);
435 // ------------------------------------------------------------------------------
437 static struct timespec timespec_divide_by_int(struct timespec numerator, long int denominator)
439 struct timespec result = {-1, -1};
440 long int reminder = -1;
442 assert(denominator < 1000000000); // For simplicity
444 result.tv_sec = numerator.tv_sec/denominator;
446 reminder = numerator.tv_sec % denominator;
448 result.tv_nsec = (reminder * 1000000000 + numerator.tv_nsec)/denominator;