--- /dev/null
+/*
+** testbench_long_jump.c
+**
+** Made by (Miguel marciano)
+** Login <miguel@namir.ctr.unican.es>
+**
+** Started on Fri Nov 23 11:42:09 2007 Miguel marciano
+** Last update Sun May 12 01:17:25 2002 Speed Blue
+*/
+
+/*
+ TO DO:
+
+ Objective: To get the following overhead:
+
+ - fixed_abort_ovhd: install handler (only for worst case)
+ save context
+ jumped return
+ fosa_long_jump_was_performed
+
+ - fixed_memory_copy_ovhd: Copying memory areas of 0 bytes
+ - memory_copy_per_byte_ovhd: Variable copying memory areas per byte.
+
+ NOTES: I don't take the mutex
+
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h> // For clock_nanosleep
+
+#include "frsh_error.h"
+#include "fosa.h"
+#include "frsh_fosa.h"
+#include "timespec_operations.h"
+
+
+
+/*************************/
+/* D E F I N I T I O N S */
+/*************************/
+#define NUMBER_OF_TESTS 100
+#define MINIMUM_BUDGET_FOR_TIMER_USECS 100
+
+#define CALIBRATE_THREAD_PRIORITY (fosa_get_priority_min() + 4)
+#define MAIN_THREAD_PRIORITY (fosa_get_priority_min() + 3)
+
+
+
+#define SIGNAL_CALIBRATE_FINISHED (FRSH_SIGNAL_MIN + 6)
+
+typedef struct _individual_results_t
+{
+ double first_interval_usec;
+
+ /* The rest of min, max and average are taken over the REST of the
+ tests */
+ double average_interval_usec;
+ double min_interval_usec;
+ int iteration_min_interval;
+ double max_interval_usec;
+ int iteration_max_interval;
+ double total_interval_usec;
+ int number_of_tries;
+
+} individual_results_t;
+
+typedef struct _thread_data_t
+{
+ individual_results_t *results;
+ frsh_thread_id_t parent_tid;
+} thread_data_t;
+
+typedef struct _measurements
+{
+ individual_results_t fixed_abort_ovhd;
+ individual_results_t fixed_memory_copy_ovhd;
+ individual_results_t memory_copy_per_byte_ovhd;
+} measurements_t;
+
+
+/*************************/
+/* P R O T O T Y P E S */
+/*************************/
+static void work_under_a_interruptible_budget();
+
+static int frsh_sharedobj_calibrate(measurements_t *measurements);
+static void *calibrate_thread_code(void *thread_arg);
+static void print_results(individual_results_t results);
+
+
+int main()
+{
+ int terror = -1;
+ measurements_t measurements;
+
+ memset(&measurements, 0, sizeof(measurements) );
+
+ /* We set the signal mask */
+
+ PRW( frsh_sharedobj_calibrate(&measurements) );
+
+ /* Print info here */
+ printf("FIXED ABORT OVHD:\n");
+ print_results(measurements.fixed_abort_ovhd);
+
+ printf("End of test\n");
+ return 0;
+}
+
+// -----------------------------------------------------------------
+
+static int frsh_sharedobj_calibrate(measurements_t *measurements)
+{
+ int terror = -1;
+
+ frsh_signal_t signal_set[1];
+ thread_data_t thread_data;
+
+ frsh_thread_attr_t calibrate_thread_attr;
+ frsh_thread_id_t calibrate_tid;
+
+ frsh_signal_t signal_received;
+ frsh_signal_info_t signal_info_received;
+
+
+ memset(&signal_set, 0, sizeof(signal_set) );
+ memset(&thread_data, 0, sizeof(thread_data) );
+
+ memset(&calibrate_thread_attr, 0, sizeof(calibrate_thread_attr) );
+ memset(&calibrate_tid, 0, sizeof(calibrate_tid) );
+
+ memset(&signal_received, 0, sizeof(signal_received) );
+ memset(&signal_info_received, 0, sizeof(signal_info_received) );
+
+
+ /* We set the signal mask and adjust our priority */
+ /**************************************************/
+ signal_set[0] = SIGNAL_CALIBRATE_FINISHED;
+ PRW( fosa_set_accepted_signals(signal_set, 1) );
+ PRW( fosa_thread_set_prio(fosa_thread_self(), MAIN_THREAD_PRIORITY) );
+
+ /* We measure the fixed_abort_ovhd */
+ /***********************************/
+ thread_data.results = &measurements->fixed_abort_ovhd;
+ thread_data.parent_tid = pthread_self();
+
+ PRW( frsh_thread_attr_init(&calibrate_thread_attr) );
+ PRW( fosa_thread_attr_set_prio(&calibrate_thread_attr, CALIBRATE_THREAD_PRIORITY) );
+ PRW( fosa_thread_create(&calibrate_tid, &calibrate_thread_attr, calibrate_thread_code,
+ &thread_data ) );
+
+ printf("Main waits for the calibrate code to finish...\n");
+ PRW( fosa_signal_wait(signal_set, 1, &signal_received, &signal_info_received) );
+
+ return 0;
+}
+
+
+// ------------------------------------------------------------------------
+
+typedef struct _protection_parameters
+{
+ bool initialised;
+ fosa_clock_id_t cpu_clock;
+ frsh_thread_id_t jump_handler_thread;
+ frsh_signal_t jump_signal;
+ frsh_signal_info_t jump_signal_info;
+ fosa_timer_id_t jump_timer;
+} protection_parameters_t;
+
+// ------------------------------------------------------------------------
+
+static void *calibrate_thread_code(void *thread_arg)
+{
+ int terror = -1;
+
+ thread_data_t *thread_data = NULL;
+ individual_results_t *results = NULL;
+
+ bool first_time = false;
+ bool stats_initialised = false;
+ protection_parameters_t protection_parameters;
+
+ frsh_signal_info_t signal_info_to_send;
+
+ memset(&protection_parameters, 0, sizeof(protection_parameters) );
+ memset(&signal_info_to_send, 0, sizeof(signal_info_to_send) );
+
+
+ thread_data = (thread_data_t *) thread_arg;
+ results = thread_data->results;
+
+
+ /* Periodic loop */
+ /*****************/
+ first_time = true;
+ stats_initialised = false; // For the second time onwards
+ protection_parameters.initialised = false;
+
+ results->number_of_tries = 0;
+ while (results->number_of_tries < NUMBER_OF_TESTS)
+ {
+ int jumped = -1;
+ struct timespec budget = {-1, -1};
+ static fosa_long_jump_context_t context;
+
+ struct timespec before_timestamp = {-1, -1 };
+ struct timespec after_timestamp = {-1, -1 };
+ double interval_usec = 0.0;
+
+
+ /* We initialise variables */
+ jumped = 0;
+ memset(&before_timestamp, 0, sizeof(before_timestamp) );
+ memset(&after_timestamp, 0, sizeof(after_timestamp) );
+
+ budget.tv_sec = 0;
+ budget.tv_nsec = MINIMUM_BUDGET_FOR_TIMER_USECS * 1000;
+
+
+ /* S T A R T M E A S U R I N G H E R E */
+ /*********************************************/
+ fosa_clock_get_time(FOSA_CLOCK_REALTIME, &before_timestamp);
+
+
+ /* This is only executed once per thread */
+ if (protection_parameters.initialised == false)
+ {
+ PXW( fosa_long_jump_install_handler(&protection_parameters.jump_signal,
+ &protection_parameters.jump_handler_thread) );
+
+ PXW( fosa_thread_get_cputime_clock( fosa_thread_self(), &protection_parameters.cpu_clock) );
+ protection_parameters.jump_signal_info.sival_ptr = &context;
+
+ PXW( fosa_timer_create_with_receiver(protection_parameters.cpu_clock,
+ protection_parameters.jump_signal,
+ protection_parameters.jump_signal_info,
+ &protection_parameters.jump_timer,
+ protection_parameters.jump_handler_thread) );
+
+ protection_parameters.initialised = true;
+ }
+
+ /* We arm the jump_timer */
+ fosa_timer_arm(protection_parameters.jump_timer, false, &budget);
+
+ /* This is the point where the jump returns */
+ fosa_long_jump_save_context(&context);
+
+ /* Query if we come from a jump */
+ fosa_long_jump_was_performed(&context, &jumped);
+ if (!jumped)
+ {
+ /* HERE COMES THE WORK THAT CAN BE INTERRUPTED */
+ work_under_a_interruptible_budget();
+ PERROR_AND_EXIT(FRSH_ERR_INTERNAL_ERROR, "The jump should always prevent us from arriving here\n");
+ }
+
+ /* E N D O F M E A S U R I N G H E R E */
+ /***************************************************/
+ fosa_clock_get_time(FOSA_CLOCK_REALTIME, &after_timestamp);
+
+ results->number_of_tries++;
+ decr_timespec(&after_timestamp, &before_timestamp);
+ interval_usec = t2d(after_timestamp) * 1000000;
+
+ /* We remove the 20 ms that we made it wait for */
+ interval_usec -= MINIMUM_BUDGET_FOR_TIMER_USECS;
+
+ if (first_time)
+ {
+ results->first_interval_usec = interval_usec;
+ first_time = false;
+ }
+ else
+ {
+ if (stats_initialised == false)
+ {
+ results->max_interval_usec = interval_usec;
+ results->iteration_max_interval = results->number_of_tries;
+
+ results->min_interval_usec = interval_usec;
+ results->iteration_min_interval = results->number_of_tries;
+
+ stats_initialised = true;
+ }
+
+ results->total_interval_usec += interval_usec;
+
+ if (interval_usec > results->max_interval_usec)
+ {
+ results->max_interval_usec = interval_usec;
+ results->iteration_max_interval = results->number_of_tries;
+ }
+
+ if (interval_usec < results->min_interval_usec)
+ {
+ results->min_interval_usec = interval_usec;
+ results->iteration_min_interval = results->number_of_tries;
+ }
+ }
+ }
+
+ results->average_interval_usec = results->total_interval_usec / (results->number_of_tries - 1);
+
+ PXW( fosa_signal_queue(SIGNAL_CALIBRATE_FINISHED, signal_info_to_send, thread_data->parent_tid) );
+
+ return NULL;
+}
+
+
+// ------------------------------------------------------------------------------
+
+static void work_under_a_interruptible_budget()
+{
+ struct timespec upper_execution_limit = {1, 0};
+
+ frsh_eat(&upper_execution_limit);
+}
+
+// ------------------------------------------------------------------------------
+
+static void print_results(individual_results_t results)
+{
+
+ printf("FIRST interval time: %6.3f usecs. All other stats apply to other invocations\n",
+ results.average_interval_usec);
+ printf("MAX interval time: %6.3f usecs at %d try, MIN interval time: %6.3f usecs at %d try\n",
+ results.max_interval_usec, results.iteration_max_interval,
+ results.min_interval_usec, results.iteration_min_interval);
+
+ printf("AVERAGE interval time: %6.3f usecs, Number of tries: %d\n",
+ results.average_interval_usec, results.number_of_tries);
+}