Example

From ChronOS Linux

(Difference between revisions)
Jump to: navigation, search
(Page creation)
Line 1: Line 1:
-
This is an example
+
There are maybe better examples but this illustrates the fundamental idea/schema to write a real-time periodic task in ChronOS?. You will learn how to write a real-time task (locking the memory, i.e. do not allow the OS to swap the application memory) pin a task to a cpu (affinity mask).. all within ChronOS?!
 +
 
 +
<tt>
 +
/*
 +
* Antonio Barbalace
 +
* periodic segments benchmark
 +
* this work was done in the integration phase of the AUV code with ChronOS
 +
*
 +
* The whole code derive from the sched_test_app (Aaron version)
 +
* This version is terrible system with just one periodic thread
 +
*/
 +
 
 +
#include <pthread.h>
 +
#include <sys/types.h>
 +
#include <unistd.h>
 +
#include "libchronos/chronos.h"
 +
 
 +
/* PARAMETERS */
 +
#define SET_SCHED_ALGO        SCHED_RT_RMA
 +
//#define SET_SCHED_FLAG        (SCHED_FLAG_PI | SCHED_FLAG_HUA | SCHED_FLAG_NO_DEADLOCKS)
 +
#define SET_SCHED_FLAG        0
 +
#define SET_SCHED_PRIO        ((SET_SCHED_ALGO & SCHED_GLOBAL_MASK) ? TASK_RUN_PRIO : -1)
 +
#define SET_SCHED_PROC        0
 +
 
 +
#define UTIL                50
 +
#define PERIOD              1000000
 +
#define EXEC                  50
 +
 
 +
#define JOBS_NUM            32
 +
#define ITER_NUM            4096
 +
 
 +
/* macros to set or zero cpus in a cpu mask */
 +
#define MASK_ZERO(mask) (mask) = 0
 +
#define MASK_SET(mask, cpu) (mask) |= (unsigned long) pow(2, cpu)
 +
 
 +
/* TASK_xxx_PRIO */
 +
#define MAIN_PRIO                      98
 +
#define TASK_CREATE_PRIO                96
 +
#define TASK_START_PRIO                94
 +
#define TASK_CLEANUP_PRIO              92
 +
#define TASK_RUN_PRIO                  90
 +
 
 +
/* Numerical definitions */
 +
#define THOUSAND  1000
 +
#define MILLION    1000000
 +
#define BILLION    1000000000
 +
 
 +
static pthread_attr_t attr;
 +
static struct sched_param tparam;
 +
 
 +
static inline long long timespec_subtract_us(struct timespec *x,
 +
                        struct timespec *y)
 +
{
 +
    long long sec, nsec;
 +
    sec = x->tv_sec - y->tv_sec;
 +
    nsec = x->tv_nsec - y->tv_nsec;
 +
    if (nsec < 0) {
 +
        nsec += BILLION;
 +
        sec--;
 +
    }
 +
 
 +
    return (sec * MILLION) + (nsec / THOUSAND);
 +
}
 +
 
 +
static void find_job_deadline(int job, long period, struct timespec * start_time, struct timespec *deadline)
 +
{
 +
    unsigned long long nsec, carry;
 +
    unsigned long offset = (job + 1) * period;    //the offset from the start time this deadline is
 +
 
 +
    nsec = start_time->tv_nsec + offset * THOUSAND;
 +
    carry = nsec / BILLION;
 +
 
 +
    deadline->tv_nsec = nsec % BILLION;
 +
    deadline->tv_sec = start_time->tv_sec + carry;
 +
}
 +
 
 +
void *start_task(void *arg)
 +
{
 +
    int job;
 +
    long period = PERIOD;
 +
    long i, l;
 +
    struct sched_param param;
 +
    struct timespec start_time, end_time, deadline, release, tperiod;
 +
 
 +
    tperiod.tv_sec = PERIOD / MILLION;
 +
    tperiod.tv_nsec = (PERIOD % MILLION) * THOUSAND;
 +
 
 +
//    struct task *t = (struct task *)arg;
 +
    pid_t tid, pid;
 +
    long long tardiness;
 +
    unsigned long thread_mask = SET_SCHED_PROC;
 +
 
 +
    //tid = gettid(); //get our thread's tid
 +
    //pid = getpid(); //same as gettid
 +
    //printf("tid %d pid %d\n", tid, pid);
 +
 
 +
    //set the affinity of this thread to whatever was specified in the taskset file
 +
    if(sched_setaffinity(0, sizeof(thread_mask), (cpu_set_t *) &thread_mask)) {
 +
        printf("Failed to set processor affinity of a task.");
 +
        pthread_exit(0);
 +
    }
 +
 
 +
    //increase priority to TASK_START_PRIO
 +
    param.sched_priority = TASK_START_PRIO;
 +
    pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);
 +
 
 +
    //get the start time and CAS on the start-time so all the threads agree on when they got here
 +
    clock_gettime(CLOCK_REALTIME, &start_time);
 +
 
 +
// periodic LOOP
 +
    for (job = 0; job<JOBS_NUM; job++) {
 +
        find_job_deadline(job, period, &start_time, &deadline);    //find the deadline for this taskset
 +
        clock_gettime(CLOCK_REALTIME, &release);    // real release time
 +
 
 +
        //enter real-time segment
 +
//        long begin_rtseg_self(int prio, int max_util, struct timespec* deadline,
 +
                    //struct timespec* period, unsigned long exec_time);
 +
        begin_rtseg_self(TASK_RUN_PRIO, UTIL, &deadline, &tperiod, EXEC);
 +
 
 +
        // DO SOMETHING like a printf... :-)
 +
        printf("job %d\n", job);
 +
        l = 123456789;
 +
        for (i=0; i< ITER_NUM; i++) {
 +
            l *= i;
 +
            // or nop
 +
        }
 +
        i = l;
 +
 
 +
        //end real time segment
 +
        clock_gettime(CLOCK_REALTIME, &end_time);    //get the endtime
 +
        end_rtseg_self(TASK_CLEANUP_PRIO);    //end the real-time segment
 +
 
 +
        tardiness = timespec_subtract_us(&deadline, &end_time);    //calculate tardiness from deadline and endtime
 +
 
 +
        if (tardiness >= 0) {    //otherwise, did we meet our deadline?
 +
            //sleep for however much time remains before the next release of this task
 +
            if (tardiness > 0)
 +
                usleep(tardiness);
 +
        }
 +
    }
 +
 
 +
    pthread_exit(NULL);
 +
}
 +
 
 +
int main(int argc, char* argv[]) {
 +
 
 +
    int i;
 +
    struct sched_param param, old_param;
 +
    unsigned long main_mask = 0;
 +
    pthread_t thread;
 +
 
 +
    //TODO we have to put mem lock all and mem unlock all at the end
 +
 
 +
    //set outselves as a real-time task
 +
    sched_getparam(0, &old_param);
 +
    param.sched_priority = MAIN_PRIO;
 +
    if (sched_setscheduler(0, SCHED_FIFO, &param) == -1) {
 +
        printf("sched_setscheduler() failed.");
 +
        return 0;
 +
    }
 +
 
 +
    //set task affinity of this main thread to the first processor
 +
    MASK_ZERO(main_mask);
 +
    MASK_SET(main_mask, 0);
 +
    if (sched_setaffinity(0, sizeof(main_mask), (cpu_set_t *) & main_mask)
 +
        < 0) {
 +
        printf("sched_setaffinity() failed.");
 +
        return 0;
 +
    }
 +
 
 +
    if (set_scheduler(SET_SCHED_ALGO | SET_SCHED_FLAG, SET_SCHED_PRIO, SET_SCHED_PROC)) {
 +
            printf("Selection of RT scheduler failed! Is the scheduler loaded?");
 +
            return 0;
 +
    }
 +
 
 +
    tparam.sched_priority = TASK_CREATE_PRIO;
 +
    pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
 +
    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
 +
    pthread_attr_setschedparam(&attr, &tparam);
 +
 
 +
    if (pthread_create(thread, &attr, start_task,0)) {
 +
            printf("Failed to pthread_create one of the task threads.");
 +
            return 0;
 +
    }
 +
    if (pthread_join(thread, NULL)) {
 +
        printf("Failed to pthread_join one of the task threads.");
 +
        return 0;
 +
    }
 +
 
 +
    //return us to a normal scheduler and priority
 +
    sched_setscheduler(0, SCHED_OTHER, &old_param);
 +
    return 0;
 +
}
 +
</tt>

Revision as of 19:26, 17 April 2014

There are maybe better examples but this illustrates the fundamental idea/schema to write a real-time periodic task in ChronOS?. You will learn how to write a real-time task (locking the memory, i.e. do not allow the OS to swap the application memory) pin a task to a cpu (affinity mask).. all within ChronOS?!

/*

* Antonio Barbalace
* periodic segments benchmark
* this work was done in the integration phase of the AUV code with ChronOS
*
* The whole code derive from the sched_test_app (Aaron version)
* This version is terrible system with just one periodic thread
*/
  1. include <pthread.h>
  2. include <sys/types.h>
  3. include <unistd.h>
  4. include "libchronos/chronos.h"

/* PARAMETERS */

  1. define SET_SCHED_ALGO SCHED_RT_RMA

//#define SET_SCHED_FLAG (SCHED_FLAG_PI | SCHED_FLAG_HUA | SCHED_FLAG_NO_DEADLOCKS)

  1. define SET_SCHED_FLAG 0
  2. define SET_SCHED_PRIO ((SET_SCHED_ALGO & SCHED_GLOBAL_MASK) ? TASK_RUN_PRIO : -1)
  3. define SET_SCHED_PROC 0
  1. define UTIL 50
  2. define PERIOD 1000000
  3. define EXEC 50
  1. define JOBS_NUM 32
  2. define ITER_NUM 4096

/* macros to set or zero cpus in a cpu mask */

  1. define MASK_ZERO(mask) (mask) = 0
  2. define MASK_SET(mask, cpu) (mask) |= (unsigned long) pow(2, cpu)

/* TASK_xxx_PRIO */

  1. define MAIN_PRIO 98
  2. define TASK_CREATE_PRIO 96
  3. define TASK_START_PRIO 94
  4. define TASK_CLEANUP_PRIO 92
  5. define TASK_RUN_PRIO 90

/* Numerical definitions */

  1. define THOUSAND 1000
  2. define MILLION 1000000
  3. define BILLION 1000000000

static pthread_attr_t attr; static struct sched_param tparam;

static inline long long timespec_subtract_us(struct timespec *x,

                        struct timespec *y)

{

   long long sec, nsec;
   sec = x->tv_sec - y->tv_sec;
   nsec = x->tv_nsec - y->tv_nsec;
   if (nsec < 0) {
       nsec += BILLION;
       sec--;
   }
   return (sec * MILLION) + (nsec / THOUSAND);

}

static void find_job_deadline(int job, long period, struct timespec * start_time, struct timespec *deadline) {

   unsigned long long nsec, carry;
   unsigned long offset = (job + 1) * period;    //the offset from the start time this deadline is
   nsec = start_time->tv_nsec + offset * THOUSAND;
   carry = nsec / BILLION;
   deadline->tv_nsec = nsec % BILLION;
   deadline->tv_sec = start_time->tv_sec + carry;

}

void *start_task(void *arg) {

   int job;
   long period = PERIOD;
   long i, l;
   struct sched_param param;
   struct timespec start_time, end_time, deadline, release, tperiod;
   tperiod.tv_sec = PERIOD / MILLION;
   tperiod.tv_nsec = (PERIOD % MILLION) * THOUSAND;

// struct task *t = (struct task *)arg;

   pid_t tid, pid;
   long long tardiness;
   unsigned long thread_mask = SET_SCHED_PROC;
   //tid = gettid(); //get our thread's tid
   //pid = getpid(); //same as gettid
   //printf("tid %d pid %d\n", tid, pid);
   //set the affinity of this thread to whatever was specified in the taskset file
   if(sched_setaffinity(0, sizeof(thread_mask), (cpu_set_t *) &thread_mask)) {
       printf("Failed to set processor affinity of a task.");
       pthread_exit(0);
   }
   //increase priority to TASK_START_PRIO
   param.sched_priority = TASK_START_PRIO;
   pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);
   //get the start time and CAS on the start-time so all the threads agree on when they got here
   clock_gettime(CLOCK_REALTIME, &start_time);

// periodic LOOP

   for (job = 0; job<JOBS_NUM; job++) {
       find_job_deadline(job, period, &start_time, &deadline);    //find the deadline for this taskset
       clock_gettime(CLOCK_REALTIME, &release);    // real release time
       //enter real-time segment

// long begin_rtseg_self(int prio, int max_util, struct timespec* deadline,

                   //struct timespec* period, unsigned long exec_time);
       begin_rtseg_self(TASK_RUN_PRIO, UTIL, &deadline, &tperiod, EXEC);
       // DO SOMETHING like a printf... :-)
       printf("job %d\n", job);
       l = 123456789;
       for (i=0; i< ITER_NUM; i++) {
           l *= i;
           // or nop
       }
       i = l;
       //end real time segment
       clock_gettime(CLOCK_REALTIME, &end_time);    //get the endtime
       end_rtseg_self(TASK_CLEANUP_PRIO);    //end the real-time segment
       tardiness = timespec_subtract_us(&deadline, &end_time);    //calculate tardiness from deadline and endtime
       if (tardiness >= 0) {    //otherwise, did we meet our deadline?
           //sleep for however much time remains before the next release of this task
           if (tardiness > 0)
               usleep(tardiness);
       }
   }
   pthread_exit(NULL);

}

int main(int argc, char* argv[]) {

   int i;
   struct sched_param param, old_param;
   unsigned long main_mask = 0;
   pthread_t thread;
   //TODO we have to put mem lock all and mem unlock all at the end
   //set outselves as a real-time task
   sched_getparam(0, &old_param);
   param.sched_priority = MAIN_PRIO;
   if (sched_setscheduler(0, SCHED_FIFO, &param) == -1) {
       printf("sched_setscheduler() failed.");
       return 0;
   }
   //set task affinity of this main thread to the first processor
   MASK_ZERO(main_mask);
   MASK_SET(main_mask, 0);
   if (sched_setaffinity(0, sizeof(main_mask), (cpu_set_t *) & main_mask)
       < 0) {
       printf("sched_setaffinity() failed.");
       return 0;
   }
   if (set_scheduler(SET_SCHED_ALGO | SET_SCHED_FLAG, SET_SCHED_PRIO, SET_SCHED_PROC)) {
           printf("Selection of RT scheduler failed! Is the scheduler loaded?");
           return 0;
   }
   tparam.sched_priority = TASK_CREATE_PRIO;
   pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
   pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
   pthread_attr_setschedparam(&attr, &tparam);
   if (pthread_create(thread, &attr, start_task,0)) {
           printf("Failed to pthread_create one of the task threads.");
           return 0;
   }
   if (pthread_join(thread, NULL)) {
       printf("Failed to pthread_join one of the task threads.");
       return 0;
   }
   //return us to a normal scheduler and priority
   sched_setscheduler(0, SCHED_OTHER, &old_param);
   return 0;

}

Personal tools