]> rtime.felk.cvut.cz Git - frescor/fosa.git/blob - src_marte/tests/test_non_local_jump/fosa_long_jump_calibrate.c
Adding mutex_lock and unlock to calibration example
[frescor/fosa.git] / src_marte / tests / test_non_local_jump / fosa_long_jump_calibrate.c
1 /*
2 ** testbench_long_jump.c
3 ** 
4 ** Made by (Miguel marciano)
5 ** Login   <miguel@namir.ctr.unican.es>
6 ** 
7 ** Started on  Fri Nov 23 11:42:09 2007 Miguel marciano
8 ** Last update Sun May 12 01:17:25 2002 Speed Blue
9 */
10
11 /*
12   TO DO:
13
14   Objective:  To get the following overhead:
15
16   -  fixed_abort_ovhd:  install handler (only for worst case)
17                         save context
18                         jumped return
19                         fosa_long_jump_was_performed
20
21   -  fixed_memory_copy_ovhd:  Copying memory areas of 0 bytes
22   -  memory_copy_per_byte_ovhd:  Variable copying memory areas per byte.
23
24   NOTES:  I don't take the mutex
25
26 */
27
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <time.h> // For clock_nanosleep
33 #include <limits.h>
34
35 #include <assert.h>
36
37 #include "frsh_error.h"
38 #include "fosa.h"
39 #include "frsh_fosa.h"
40 #include "timespec_operations.h"
41
42
43
44 /*************************/
45 /* D E F I N I T I O N S */
46 /*************************/
47 #define NUMBER_OF_TESTS 1000
48
49 static struct timespec minimum_budget_for_timer = {0, 100000};  // 100 us
50
51 #define NUMBER_OF_BYTES_TO_SIMULATE 10000  // Stack limit 40k in
52                                            // current MaRTE configuration
53
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)
57
58 #define MINIMUM_BUDGET_FOR_TIMER_USECS 100
59
60 #define SIGNAL_CALIBRATE_FINISHED (FRSH_SIGNAL_MIN + 6)
61
62
63 typedef struct _individual_results_t
64 {
65     int first_time_passed;
66     int second_time_passed;
67
68     struct timespec first_interval;
69     
70     /* The rest of min, max and average are taken over the REST of the
71        tests */
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;
79
80 } individual_results_t;
81
82 typedef struct _thread_data_t
83 {
84     individual_results_t *results;
85     frsh_thread_id_t parent_tid;
86 } thread_data_t;
87
88 typedef struct _measurements
89 {
90     individual_results_t fixed_abort_ovhd;
91     individual_results_t fixed_memory_copy_ovhd;
92     individual_results_t memory_copy_per_byte_ovhd;
93 } measurements_t;
94
95
96 /*************************/
97 /*  P R O T O T Y P E S  */
98 /*************************/
99 static void work_under_a_interruptible_budget();
100
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);
104
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);
108
109 static struct timespec timespec_divide_by_int(struct timespec numerator, long int  denominator);
110
111
112
113 int main()
114 {
115     int terror = -1;
116     measurements_t measurements;
117     
118     memset(&measurements, 0, sizeof(measurements) );
119
120     /* We set the signal mask */
121
122     PRW(  frsh_sharedobj_calibrate(&measurements.fixed_abort_ovhd,
123                                    &measurements.fixed_memory_copy_ovhd,
124                                    &measurements.memory_copy_per_byte_ovhd) );
125
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);
133
134
135     printf("End of test\n");
136     return 0;
137 }
138
139 // -----------------------------------------------------------------
140     
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)
144 {
145     int terror = -1;
146
147     frsh_signal_t signal_set[1];
148     thread_data_t thread_data;
149
150     frsh_thread_attr_t calibrate_thread_attr;
151     frsh_thread_id_t calibrate_tid;
152
153     frsh_signal_t signal_received;
154     frsh_signal_info_t signal_info_received;
155
156     fosa_clock_id_t cpu_clock;
157     struct timespec initial_time = {-1, -1};
158     struct timespec final_time = {-1, -1};
159
160     char memory_region_source[NUMBER_OF_BYTES_TO_SIMULATE];
161     char memory_region_destination[NUMBER_OF_BYTES_TO_SIMULATE];
162     int i = 0;
163
164     memset(&signal_set, 0, sizeof(signal_set) );
165     memset(&thread_data, 0, sizeof(thread_data) );
166
167     memset(&calibrate_thread_attr, 0, sizeof(calibrate_thread_attr) );
168     memset(&calibrate_tid, 0, sizeof(calibrate_tid) );
169
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) );
173
174     
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)  );
180
181     /* We get our CPU clock */
182     PRW(  fosa_thread_get_cputime_clock( fosa_thread_self(), &cpu_clock) );
183
184     /* We measure the fixed_abort_ovhd */
185     /***********************************/
186     thread_data.results = fixed_abort_ovhd;
187     thread_data.parent_tid = pthread_self();
188
189     PRW(  frsh_thread_attr_init(&calibrate_thread_attr) );
190     PRW(  fosa_thread_attr_set_prio(&calibrate_thread_attr, CALIBRATE_THREAD_PRIORITY)  );
191
192     PRW(  fosa_thread_create(&calibrate_tid, &calibrate_thread_attr, fixed_abort_ovhd_thread_code, 
193                              &thread_data ) );
194
195     /* We wait for the signal to arrive */
196     PRW(  fosa_signal_wait(signal_set, 1, &signal_received, &signal_info_received) );
197     
198
199     /* We measure fixed_memory_copy_ovhd */
200     /*************************************/
201     for(i = 0 ; i < NUMBER_OF_TESTS ; i++)
202     {
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
206
207         decr_timespec(&final_time, &initial_time);
208
209         process_result(fixed_memory_copy_ovhd, final_time);
210     }
211
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);
215
216     /* We measure memory_copy_per_byte_ovhd */
217     /****************************************/
218     for(i = 0 ; i < NUMBER_OF_TESTS ; i++)
219     {
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
223
224         decr_timespec(&final_time, &initial_time);
225
226         final_time = timespec_divide_by_int(final_time, NUMBER_OF_BYTES_TO_SIMULATE / 1024);
227
228         process_result(memory_copy_per_byte_ovhd, final_time);
229     }
230
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);
234
235     return 0;
236 }
237
238
239 // ------------------------------------------------------------------------
240
241 typedef struct _protection_parameters
242 {
243     bool initialised;
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;
250
251 // ------------------------------------------------------------------------
252
253 static void *fixed_abort_ovhd_thread_code(void *thread_arg)
254 {
255     int terror = -1;
256
257     thread_data_t *thread_data = NULL;
258     individual_results_t *results = NULL;
259
260     protection_parameters_t protection_parameters;
261
262     frsh_signal_info_t signal_info_to_send;
263     frsh_mutex_t mutex;
264
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) );
268
269     thread_data = (thread_data_t *) thread_arg;
270     results = thread_data->results;
271     
272     PXW(  fosa_mutex_init(&mutex, MUTEX_CEILING) );
273
274
275     /* Periodic loop */
276     /*****************/
277     protection_parameters.initialised = false;
278
279     results->number_of_tries = 0;
280     while (results->number_of_tries < NUMBER_OF_TESTS)
281     {
282         int jumped = -1;
283         struct timespec budget = {-1, -1};
284         static fosa_long_jump_context_t context;
285
286         struct timespec before_timestamp = {-1, -1 };
287         struct timespec after_timestamp = {-1, -1 };
288
289         
290         /* We initialise variables */
291         jumped = 0;
292         memset(&before_timestamp, 0, sizeof(before_timestamp) );
293         memset(&after_timestamp, 0, sizeof(after_timestamp) );
294
295         budget.tv_sec = 0;
296         budget.tv_nsec = MINIMUM_BUDGET_FOR_TIMER_USECS * 1000;
297         
298
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);
302         
303
304         /* This is only executed once per thread */
305         if (protection_parameters.initialised == false)
306         {
307             PXW(  fosa_long_jump_install_handler(&protection_parameters.jump_signal, 
308                                            &protection_parameters.jump_handler_thread) );
309
310             PXW(  fosa_thread_get_cputime_clock( fosa_thread_self(), &protection_parameters.cpu_clock) );
311             protection_parameters.jump_signal_info.sival_ptr = &context;
312             
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)  );
318
319             protection_parameters.initialised = true;
320         }
321
322         PXW(  fosa_mutex_lock(&mutex)  );
323
324         /* We arm the jump_timer */
325         PXW(  fosa_timer_arm(protection_parameters.jump_timer, false, &budget)  );
326         
327         /* This is the point where the jump returns */
328         fosa_long_jump_save_context(&context);
329
330         /* Query if we come from a jump */
331         fosa_long_jump_was_performed(&context, &jumped);
332         if (!jumped)
333         {
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");
339         }
340         
341         PXW(  fosa_mutex_unlock(&mutex) );
342
343
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);
347
348         decr_timespec(&after_timestamp, &before_timestamp);
349
350         decr_timespec(&after_timestamp, &minimum_budget_for_timer);
351
352         process_result(results, after_timestamp);
353
354     }
355
356     results->average_interval = timespec_divide_by_int(results->total_interval, results->number_of_tries - 1);
357     
358     PXW(  fosa_signal_queue(SIGNAL_CALIBRATE_FINISHED, signal_info_to_send, thread_data->parent_tid) );
359
360     return NULL;
361 }
362
363
364 // ------------------------------------------------------------------------------
365
366 static void work_under_a_interruptible_budget()
367 {
368     struct timespec upper_execution_limit = {1, 0};
369
370     frsh_eat(&upper_execution_limit);
371 }
372
373 // ------------------------------------------------------------------------------
374
375 static void process_result(individual_results_t *results, struct timespec interval)
376 {
377     results->number_of_tries++;
378
379     if (results->first_time_passed == 0)
380     {
381         results->first_interval = interval;
382         results->first_time_passed = 1;
383     }
384     else if (results->second_time_passed == 0)
385     {
386         results->max_interval = interval;
387         results->iteration_max_interval = results->number_of_tries;
388             
389         results->min_interval = interval;
390         results->iteration_min_interval = results->number_of_tries;
391
392         results->second_time_passed = 1;
393         
394         incr_timespec(&results->total_interval, &interval);
395     }
396     else
397     {
398         if (smaller_timespec(&results->max_interval, &interval) )
399         {
400             results->max_interval = interval;
401             results->iteration_max_interval = results->number_of_tries;
402         }
403             
404         if (smaller_timespec(&interval, &results->min_interval) )
405         {
406             results->min_interval = interval;
407             results->iteration_min_interval = results->number_of_tries;
408         }
409
410         incr_timespec(&results->total_interval, &interval);
411     }
412
413 }
414
415 // ------------------------------------------------------------------------------
416
417 static void print_results(individual_results_t results)
418 {
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);
423
424     printf("FIRST interval time:  %d ns.  All other stats apply to other invocations\n",
425            results.first_interval.tv_nsec);
426
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);
430
431     printf("AVERAGE interval time: %d ns, Number of tries %ld\n",
432            results.average_interval.tv_nsec, results.number_of_tries);
433 }
434
435 // ------------------------------------------------------------------------------
436
437 static struct timespec timespec_divide_by_int(struct timespec numerator, long int  denominator)
438 {
439     struct timespec result = {-1, -1};
440     long int reminder = -1;
441
442     assert(denominator < 1000000000);  // For simplicity
443
444     result.tv_sec = numerator.tv_sec/denominator;
445
446     reminder = numerator.tv_sec % denominator;
447
448     result.tv_nsec = (reminder * 1000000000 + numerator.tv_nsec)/denominator;
449
450     return result;
451 }