Subversion Repositories shark

Rev

Blame | Last modification | View Log | RSS feed

/*
 * Project: S.Ha.R.K.
 *
 * Coordinators:
 *   Giorgio Buttazzo    <giorgio@sssup.it>
 *   Paolo Gai           <pj@gandalf.sssup.it>
 *
 * Authors     :
 *   Paolo Gai           <pj@gandalf.sssup.it>
 *   (see the web pages for full authors list)
 *
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
 *
 * http://www.sssup.it
 * http://retis.sssup.it
 * http://shark.sssup.it
 */


/**
 ------------
 CVS :        $Id: crunch.c,v 1.1 2004-07-05 14:17:12 pj Exp $

 File:        $File$
 Revision:    $Revision: 1.1 $
 Last update: $Date: 2004-07-05 14:17:12 $
 ------------

**/


/*
 * Copyright (C) 2001 Paolo Gai
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */




/*
 * Crunch.c
 */



//#define DEBUG_CONFFILE
//#define DEBUG_MASTER_HARDCREATE
//#define DEBUG_MASTER_VALUECREATE

#include "valmodel.h"
#include "crunch.h"
#include <kernel/kern.h>

/*
 *  This small application simply reads the tasks and executes them.
 *  When they are all finished, the system shuts down.
 */





/*
 * this table contains all the tasks information collected from the
 * configuration file
 */


#define MAX_PATTERN 100000
struct task_struct pattern[MAX_PATTERN];
int pattern_dim;

/* This is some data collected by the task destructors that
 * can be useful for understanding how the Module works     */


/* this int contains the value as seen by the application */
int current_value = 0;
int max_value = 0;
int min_value = 0;
int max_created_value = 0;
int min_created_value = 0;

/* the number of finished tasks */
int current_finished_tasks = 0;

/* this flag is triggered by the master task  when it finishes */
int finished = 0;

/* number of instances of an hard tasks
   NOTE that it is 79 and not 80 as in the generation algorithm!!! */

#define ASTER_LIM 79

// Master task stuffs
PID master_pid;    // the PID of the master task
int current_task;  // the current position in the pattern array

// number of periodic tasks currently running...
int current_periodic_tasks = 0;

PID info_pid;    // the PID of the master task


/*
 * This function prints all the data read from the configuration file
 */

void print_conffile(char *name)
{
  int i;

  cprintf("--------------------------------------------------------------------\n");
  cprintf("Configuration file name        : %s\n", name);
  cprintf("Number of tasks in the pattern : %d\n", pattern_dim);
  cprintf("      Time Hard/Value      Dline       WCET Iterations Value Penalty\n");
  cprintf("--------------------------------------------------------------------\n");

  for (i=0; i<pattern_dim; i++) {
    cprintf("%10d %10d %10d %10d %10d %5d %7d\n",
            pattern[i].time,
            pattern[i].type,
            pattern[i].reldline,
            pattern[i].wcet,
            pattern[i].iterations,
            pattern[i].value,
            pattern[i].penalty);
  }
  cprintf("--------------------------------------------------------------------\n");
}

/*
 * main()
 */


void scenario(void);
void create_master_task(void);
void create_info_task(void);
void update_scenario(void);
void print_statistics(void);

int main(int argc, char **argv)
{
  srand(18);

  set_exchandler_grx();

  /*
   * Parse the configuration file
   */

  crunch_file(pattern, &pattern_dim, MAX_PATTERN);

  if (!pattern_dim) {
    cprintf("Nothing to do!\n");
    sys_end();
  }

  /*
   * Print configuration file
   */

  #ifdef DEBUG_CONFFILE
  print_conffile(argv[1]); return 0;
  #endif

  /*
   * Print the scenario
   */

  scenario();

  /*
   * Create the high priority task that will create all the periodic
   * and value tasks.
   */

  create_master_task();

  /*
   * Create a periodic task to display some statistical informations
   */

  create_info_task();

  /*
   * While in idle time, update the scenario
   */

  while (!finished || task_counter != 3) {
    update_scenario();
  }

  print_statistics();

  return 0;
}


/*
 *
 * MASTER TASK STUFFS
 *
 */



void activate_master_task(void *);
void *master_task(void *);
void *hard_task(void *);
void *value_task(void *);

void create_master_task()
{
  NRT_TASK_MODEL nrt;
  struct timespec t;

  nrt_task_default_model(nrt);
  nrt_task_def_usemath(nrt);
  nrt_task_def_ctrl_jet(nrt);
  nrt_task_def_save_arrivals(nrt);

  master_pid = task_create("master", master_task, &nrt, NULL);
  if(master_pid == -1) {
    cprintf("Cannot create the master task!!!\n");
    sys_end();
  }

  current_task = 0;
  NULL_TIMESPEC(&t);
  ADDUSEC2TIMESPEC(pattern[0].time, &t);
  kern_cli();
  kern_event_post(&t, activate_master_task, NULL);
  kern_sti();
}

void activate_master_task(void *arg)
{
  task_activate(master_pid);
}

void *master_task(void *arg)
{
  int current_time;

  HARD_TASK_MODEL hard;
  PID phard;

  VALUE_TASK_MODEL value;

  PID group_container_pid[100];
  int group_container_pattern[100];
  int group_container_index;

  // used to record the group_creation for value task
  int i;
  PID p;

  task_nopreempt();

  hard_task_default_model(hard);
  hard_task_def_usemath(hard);
  value_task_default_model(value);
  value_task_def_usemath(value);

  do {
    // current_task indexes the next task to be activated.

    current_time = pattern[current_task].time;

    // create and activate all the hard tasks with the same starting time
    if (!pattern[current_task].type) {
      do {
        #ifdef DEBUG_MASTER_HARDCREATE
          { int i=current_task; cprintf("%10d %10d %10d %10d %10d %5d %7d\n",
            pattern[i].time, pattern[i].type, pattern[i].reldline,
            pattern[i].wcet, pattern[i].iterations, pattern[i].value,
            pattern[i].penalty); }
        #endif

        hard_task_def_mit(hard, pattern[current_task].reldline);
        hard_task_def_wcet(hard, pattern[current_task].wcet);
        hard_task_def_arg(hard, (void *)current_task);

        phard = task_create("hard_task", hard_task, &hard, NULL);
        if (phard == NIL) {
          clear();
          cprintf("Cannot create hard task! (errno=%d)\n", errno);
          sys_end();
        }
        else {
          task_activate(phard);
          current_periodic_tasks++;
        }

        current_task++;
      } while (current_task != pattern_dim &&
               pattern[current_task].time == current_time &&
               !pattern[current_task].type);
    }

    // create and activate all the soft tasks with the same starting time
    if (current_task != pattern_dim &&
        pattern[current_task].time == current_time &&
        pattern[current_task].type) {
      group_container_index = 0;

      kern_cli();
      while (current_task != pattern_dim &&
             pattern[current_task].time == current_time &&
             pattern[current_task].type) {

        #ifdef DEBUG_MASTER_VALUECREATE
          { int i=current_task; cprintf("V%10d %10d %10d %10d %10d %5d %7d\n",
            pattern[i].time, pattern[i].type, pattern[i].reldline,
            pattern[i].wcet, pattern[i].iterations, pattern[i].value,
            pattern[i].penalty); }
        #endif

//  kern_printf("master_task: current_value=%d\n",current_value);

        value_task_def_wcet(value,pattern[current_task].wcet);
        value_task_def_dline(value,pattern[current_task].reldline);
        value_task_def_value(value,pattern[current_task].value);
        value_task_def_penalty(value,pattern[current_task].penalty);
        value_task_def_arg(value, (void *)current_task);
        p = group_create("value_task", value_task, (TASK_MODEL *)&value, NULL);
//        kern_printf("\nCreating %d PID = %d\n",current_task, p);
        // we need to know which task we are inserting, so we insert it in
        // a list to check them later
        group_container_pid[group_container_index]=p;
        group_container_pattern[group_container_index]=current_task;
        group_container_index++;

        current_task++;
      }

/*      {kern_printf("group_container: index=%d, 0=%d, 1=%d, 2=%d, 3=%d\n",
       group_container_index, group_container_pid[0], group_container_pid[1],
       group_container_pid[2], group_container_pid[3]);}*/


      guarantee();
//      kern_printf("group_container_index=%d\n",group_container_index);
      for (i=0; i<group_container_index; i++) {
//      {kern_printf("i=%d, group_container: index=%d, 0=%d, 1=%d, 2=%d, 3=%d\n",i,
//       group_container_index, group_container_pid[0], group_container_pid[1],
//       group_container_pid[2], group_container_pid[3]);}
        p = group_container_pid[i];
//        kern_printf("+%d\n",p);
        max_created_value += pattern[group_container_pattern[i]].value;
        min_created_value -= pattern[group_container_pattern[i]].penalty;

        if (p == NIL) continue;

        if (crunch_taskaccepted(p)) {
          // we need to pass the original model for the task...
          // but just the common part is needed O:-)

          // account for the penalty before the task starts
          current_value -= pattern[group_container_pattern[i]].penalty;
          max_value += pattern[group_container_pattern[i]].value;
          min_value -= pattern[group_container_pattern[i]].penalty;

          value_task_def_arg(value, (void *)group_container_pattern[i]);
          group_create_accept(p,(TASK_MODEL *)&value);
//          kern_printf("Accetto task PID=%d\n",p);
        }
        else {
          group_container_pid[i] = NIL;
//          kern_printf("Rigetto task PID=%d\n",p);

          group_create_reject(p);
        }
      }
      kern_sti();

      for (i=0; i<group_container_index; i++) {
//        kern_printf("Attivo %d PID=%d\n",i,group_container_pid[i]);
        if (group_container_pid[i] != NIL)
          task_activate(group_container_pid[i]);
      }
    }
 
    if (current_task != pattern_dim) {
      struct timespec t;
      NULL_TIMESPEC(&t);
      ADDUSEC2TIMESPEC(pattern[current_task].time, &t);
      kern_cli();
      kern_event_post(&t, activate_master_task, NULL);
      task_endcycle();
    }
  } while(current_task != pattern_dim);

  /* since all the tasks has been activated, the master_task will stop
     forever.
     In that way we can look at the elapsed time consumed by the master task.
  */

//  task_nopreempt();
  finished = 1;
  task_endcycle();

  return (void *)0;
}

#define DEFAULT_SHIFT 1000000
void *hard_task(void *arg)
{
  struct timespec dl, curr;  // for deadline checking

  int index, j, x, y, temp;
  char s[2];

  struct timespec t;
  int b;

  task_setcanceltype(TASK_CANCEL_ASYNCHRONOUS,&temp);

  index = (int)arg;

  NULL_TIMESPEC(&t);
  ADDUSEC2TIMESPEC((DEFAULT_SHIFT*2)/3,&t);

  b = TIMESPEC_A_LT_B(&proc_table[exec_shadow].request_time,&t);

  do {
    x = 0;
    y = rand() % 6 + 3;
    s[0] = '*'; s[1] = 0;
    while (x < ASTER_LIM) {
      for (j=0; j<pattern[index].iterations; j++) {
        s[0] = '*' + rand() % 100;
        puts_xy(x,y,rand()%15+1,s);
      }
 
      // Dline check :-) it is not perfect, but it works :-)
      kern_cli();
      ll_gettime(TIME_EXACT,&curr);
      dl = proc_table[exec_shadow].request_time;
      ADDUSEC2TIMESPEC(pattern[index].reldline, &dl);
      if (TIMESPEC_A_LT_B(&dl,&curr)) {
        cprintf("\n\nPERIODIC TASK %d: Deadline miss!!!\n", index);
        cprintf("current time= %10ld sec, %10ld ns\n", curr.tv_sec, curr.tv_nsec);
        cprintf("deadline    = %10ld sec, %10ld ns\n", dl.tv_sec, dl.tv_nsec);
        sys_end();
      }
      task_endcycle();
 
      puts_xy(x,y,WHITE," ");
      x++;
    }
  } while (b && !finished);

  kern_cli();

  // account for a finished task
  current_finished_tasks++;
  current_periodic_tasks--;

  // Dline check :-) it is not perfect, but it works :-)
  ll_gettime(TIME_EXACT,&curr);
  dl=proc_table[exec_shadow].request_time;
  ADDUSEC2TIMESPEC(pattern[index].reldline, &dl);
  if (TIMESPEC_A_LT_B(&dl,&curr)) {
    cprintf("\n\nPERIODIC TASK %d: Deadline miss!!!\n", index);
    cprintf("current time= %10ld sec, %10ld ns\n", curr.tv_sec, curr.tv_nsec);
    cprintf("deadline    = %10ld sec, %10ld ns\n", dl.tv_sec, dl.tv_nsec);
    sys_end();
  }

  return (void *)0;
}

void *value_task(void *arg)
{
  struct timespec dl, curr;  // for deadline checking
  int index, j, x, y, temp;
  char s[2];

  task_setcanceltype(TASK_CANCEL_ASYNCHRONOUS,&temp);

  index = (int)arg;

  //  kern_printf("Ú%dÙ",index);

  x = rand() % 26 + 1;
  y = rand() % 3  + 10;
  s[0] = '*'; s[1] = 0;
  for (j=0; j<pattern[index].iterations; j++) {
    s[0] = '*' + rand() % 100;
    puts_xy(x,y,rand()%15+1,s);
  }
//  kern_printf("*%d*\n",exec_shadow);

  kern_cli();

  // account for a finished task
  current_finished_tasks++;

  // Dline check :-) it is not perfect, but it works :-)
  ll_gettime(TIME_EXACT,&curr);
  TIMESPEC_ASSIGN(&dl, &proc_table[exec_shadow].request_time);
  ADDUSEC2TIMESPEC(pattern[index].reldline, &dl);

  if (TIMESPEC_A_GT_B(&dl,&curr)) {
    // The task finishes in time. account for the value
    current_value += pattern[index].penalty + pattern[index].value;
  }
  //  kern_printf("value: arg=%d current_value=%d pen=%d val=%d\n",arg,current_value,
  //  ((struct task_struct *)arg)->penalty,
  //      ((struct task_struct *)arg)->value);

  return (void *)0;
}

void *info_task(void *);

void create_info_task(void)
{
  HARD_TASK_MODEL hard;

  hard_task_default_model(hard);
  hard_task_def_usemath(hard);
  hard_task_def_mit(hard, 2000000);
  hard_task_def_wcet(hard, 2000);

  info_pid = task_create("info_task", info_task, &hard, NULL);
  task_activate(info_pid);
}

void *info_task(void *arg)
{
  int x;

  task_setcanceltype(TASK_CANCEL_ASYNCHRONOUS,&x);

  for (;;) {
    update_scenario();
    task_endcycle();
  }
}

void print_statistics(void)
{
  TIME sum;

  clear();

  jet_getstat(master_pid, &sum, 0, 0, 0);
  task_activate(master_pid);         // let the master task die...
  task_kill(info_pid);

  clear();
  cprintf("CRUNCH 1.12 - by Paolo Gai 2001\n\n");
  cprintf("ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n\n");
  cprintf("Final Results:\n\n");

  cprintf("The Master task elapsed time   : %d microseconds.\n\n",(int)sum);

  cprintf("Total number of tasks          : %9d\n", pattern_dim);
  cprintf("Total number of scheduled tasks: %9d\n\n",current_task);

  cprintf("Per.tasks created but not ended: %9d\n\n",current_periodic_tasks);
  cprintf("Maximum created value          : %9d\n",max_created_value);
  cprintf("Minimum created value          : %9d\n\n",min_created_value);
  cprintf("Maximum value                  : %9d\n",max_value);
  cprintf("Minimum value                  : %9d\n\n",min_value);
  cprintf("Total Value (from Module)      : %9d\n",crunch_getvalue());
  cprintf("Total Value (from CRUNCH)      : %9d\n",current_value);
  cprintf("ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n\n");
}

/*
 * Scenario
 */


void scenario(void)
{
  char buf[100];
  clear();

  puts_xy(0, 0,BLUE , "CRUNCH 1.12");
  puts_xy(15,0,GREEN, "by Paolo Gai 2001");
  puts_xy(0, 2,WHITE, "ÄÄÄ Hard Periodic Tasks ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ");
  puts_xy(0, 9,WHITE, "ÂÄÄ Soft Aperiodic Tasks ÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ");
  puts_xy(0,10,WHITE, "³                          ³");
  puts_xy(0,11,WHITE, "³                          ³");
  puts_xy(0,12,WHITE, "³                          ³");
  puts_xy(0,13,WHITE, "ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ");
  puts_xy(29,10,YELLOW, "Statistics:");
  sprintf(buf,"Total: %5d Already created:        Periodic:",pattern_dim);
  puts_xy(29,11,CYAN,   buf);
  puts_xy(29,12,BLUE,   "Value reported (by Modules):");
  puts_xy(29,13,RED,    "               (by CRUNCH ):");
  puts_xy(69,12,7,   "Min:");
  puts_xy(69,13,7,   "Max:");

  puts_xy(0,14,WHITE, "ÄÄÄ Debug space for Logging Module functions... ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ");
  place(0,15);
}

void update_scenario(void)
{
  char buf[100];
  sprintf(buf,"%5d",current_task);
  puts_xy(58,11,WHITE,buf);
  sprintf(buf,"%5d",current_periodic_tasks);
  puts_xy(75,11,WHITE,buf);
  sprintf(buf,"%5d",crunch_getvalue());
  puts_xy(58,12,WHITE,buf);
  sprintf(buf,"%5d",current_value);
  puts_xy(58,13,WHITE,buf);
  sprintf(buf,"%6d",min_value);
  puts_xy(74,12,WHITE,buf);
  sprintf(buf,"%6d",max_value);
  puts_xy(74,13,WHITE,buf);
}