Subversion Repositories shark

Compare Revisions

Ignore whitespace Rev 1632 → Rev 1631

/advdemos/trunk/cash/testcash.c
0,0 → 1,455
/*
* Project: HARTIK (HA-rd R-eal TI-me K-ernel)
*
* Coordinators: Giorgio Buttazzo <giorgio@sssup.it>
* Gerardo Lamastra <gerardo@sssup.it>
*
* Authors : Paolo Gai <pj@hartik.sssup.it>
* (see authors.txt for full list of hartik's authors)
*
* ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
*
* http://www.sssup.it
* http://retis.sssup.it
* http://hartik.sssup.it
*/
 
/**
------------
CVS : $Id: testcash.c,v 1.1.1.1 2004-05-24 17:54:49 giacomo Exp $
 
File: $File$
Revision: $Revision: 1.1.1.1 $
Last update: $Date: 2004-05-24 17:54:49 $
------------
 
testcash.c
test for the CASH Module, directly derived from Test Number 13 (D)
 
**/
 
/*
* Copyright (C) 2000 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
*
*/
 
#include "kernel/kern.h"
#include "modules/edf.h"
#include "cash.h"
#include <math.h>
#include <string.h>
 
#define ASTER_LIM 60
#define DISPLAY_MAX 15
 
#define STAT_Y 9
 
#define INPUT 0.5
 
 
 
#define MAX_STAT 10000
#define RVAL 1
#define XVAL 2
#define DVAL 3
 
 
struct statistic {
TIME r_time;
TIME ex_time;
long dead_post;
};
 
 
 
struct statistic stat[MAX_STAT];
TIME val[MAX_STAT];
 
int n_stat = 0;
 
TASK hard_asteroide(void)
{
int i;
int y = rand() % 7 + 1;
double avg, l, fix, u;
double wcet = 40200;
int load1,j;
 
char s[2];
 
s[0] = 'H'; s[1] = 0;
/* exponential distribution parameters */
fix = wcet - 10.0/9.0 * wcet * (1 - INPUT);
avg = 1.0/9.0 * wcet * (1 - INPUT);
l = 10.0 / 9.0 * wcet * (1 - INPUT);
for (;;) {
i = 1;
while (i < ASTER_LIM) {
/* exponential distribution */
u = (double)rand();
u = u / (double)RAND_MAX;
u = -avg * log(u);
if (u > l)
u = avg;
 
load1 = fix + u;
for (j=0; j<load1; j++) {
puts_xy(i,y,rand()%15+1,s);
}
//kern_cli();
//stat[n_stat].r_time = CBSGHD_get_response_time(1, exec_shadow);
//jet_gettable(exec_shadow, &stat[n_stat].ex_time, 1);
//kern_sti();
//n_stat++;
task_endcycle();
puts_xy(i,y,WHITE," ");
i++;
}
}
}
 
 
TASK hard_asteroide1(void)
{
int i;
int y = rand() % 7 + 1;
 
int load1,j;
 
char s[2];
 
s[0] = 'H'; s[1] = 0;
 
for (;;) {
i = 1;
while (i < ASTER_LIM) {
load1 = 40000 + rand()%20000;
for (j=0; j<load1; j++) {
puts_xy(i,y,rand()%15+1,s);
}
//kern_cli();
//stat[n_stat].r_time = CBSGHD_get_response_time(1, exec_shadow);
//jet_gettable(exec_shadow, &stat[n_stat].ex_time, 1);
//kern_sti();
//n_stat++;
task_endcycle();
puts_xy(i,y,WHITE," ");
i++;
}
}
}
 
 
TASK hard_asteroide2(void)
{
int i;
int y = rand() % 7 + 1;
 
int load1,j;
 
char s[2];
 
s[0] = 'H'; s[1] = 0;
 
for (;;) {
i = 1;
while (i < ASTER_LIM) {
load1 = 80500; // + rand()%6000;
for (j=0; j<load1; j++) {
puts_xy(i,y,rand()%15+1,s);
}
//kern_cli();
//stat[n_stat].r_time = CBSGHD_get_response_time(5, exec_shadow);
//jet_gettable(exec_shadow, &stat[n_stat].ex_time, 1);
//kern_sti();
//n_stat++;
task_endcycle();
puts_xy(i,y,WHITE," ");
i++;
}
}
}
 
TASK hard_asteroide3(void)
{
int i;
int y = rand() % 7 + 1;
 
int load1,j;
 
char s[2];
 
s[0] = 'T'; s[1] = 0;
 
for (;;) {
i = 1;
while (i < ASTER_LIM) {
load1 = 27000;
for (j=0; j<load1; j++) {
puts_xy(i,y,rand()%15+1,s);
}
//kern_cli();
//stat[n_stat].r_time = CBSGHD_get_response_time(5, exec_shadow);
//jet_gettable(exec_shadow, &stat[n_stat].ex_time, 1);
//kern_sti();
//n_stat++;
task_endcycle();
puts_xy(i,y,WHITE," ");
i++;
}
}
}
 
 
TASK clock()
{
int s = 0, m = 0;
 
while(1) {
printf_xy(62,1,WHITE,"%2d:%2d",m,s);
printf_xy(62,2,WHITE,"Utot=%12u",MAX_BANDWIDTH);
printf_xy(62,3,WHITE,"Uedf=%12u",EDF_usedbandwidth(0));
printf_xy(62,4,WHITE,"Ucbs=%12u",CBSGHD_usedbandwidth(1));
task_endcycle();
if (++s > 59) {
s = 0;
m++;
}
printf_xy(62,1,WHITE,"%2d:%2d",m,s);
printf_xy(62,2,WHITE,"Utot=%12u",MAX_BANDWIDTH);
printf_xy(62,3,WHITE,"Uedf=%12u",EDF_usedbandwidth(0));
printf_xy(62,4,WHITE,"Ucbs=%12u",CBSGHD_usedbandwidth(1));
task_endcycle();
}
}
 
 
 
/* we consider the first ASTER_MAX + 2 tasks from the PID 2
and plot on the screen the elapsed times... */
TASK jetcontrol()
{
int i; /* a counter */
TIME sum, max, curr, last[5];
int nact;
int j; /* the elements set by jet_gettable */
PID p;
 
 
kern_cli();
printf_xy(0,STAT_Y,WHITE,"PID ³ Mean T.³ Max T. ³ N.A. ³ Curr. ³ Last1 ³ Last2 ³ Last3 ³ Last4 ³ Last5");
kern_sti();
 
for (;;) {
for (i=0,p=0; i<DISPLAY_MAX+5 && p<MAX_PROC; p++) {
if (jet_getstat(p, &sum, &max, &nact, &curr) == -1) continue;
 
for (j=0; j<5; j++) last[j] = 0;
jet_gettable(p, &last[0], 5);
kern_cli();
printf_xy(0,STAT_Y+i+1,WHITE,"%-3d ³ %-6ld ³ %-6ld ³ %-4d ³ %-7ld ³ %-5ld ³ %-5ld ³ %-5ld ³ %-5ld ³ %-5ld", p, sum/(nact==0 ? 1 : nact), max,
nact, curr, last[0], last[1], last[2], last[3], last[4]);
kern_sti();
i++;
}
task_endcycle();
}
}
 
 
void save_stat(struct statistic p[], int n, char *name, int type)
{
DOS_FILE *f;
int i;
char outstring[500];
for(i = 0; i < 500; i++)
outstring[i] = '0';
f = DOS_fopen(name, "w");
if (!f) {
cprintf("Cannot open %s!!!", name);
goto end1;
}
for(i = 0; i < n; i++) {
if (type == RVAL)
val[i] = p[i].r_time;
if (type == XVAL)
val[i] = p[i].ex_time;
if (type == DVAL)
val[i] = p[i].dead_post;
}
memset(outstring, 0, 300);
sprintf(outstring, "%ld \n", (long int)n);
cprintf("%s", outstring);
DOS_fwrite(outstring, 1, strlen(outstring), f);
 
for(i = 0; i < n; i++) {
memset(outstring, 0, 300);
sprintf(outstring, "%ld %lu\n", (long int)i, val[i]);
//cprintf("%s", outstring);
DOS_fwrite(outstring, 1, strlen(outstring), f);
}
DOS_fclose(f);
end1:cprintf("OK?");
}
 
 
void result_save(void *p)
{
save_stat(stat, n_stat, "stat1.tim", RVAL);
}
 
 
void fine()
{
sys_end();
}
 
int main(int argc, char **argv)
{
PID p1,p2,p3, p4, p5, p6, p7;
 
ELASTIC_HARD_TASK_MODEL m;
// int i;
struct timespec fineprg;
 
 
//sys_atrunlevel(result_save, NULL, RUNLEVEL_AFTER_EXIT);
srand(7);
 
elastic_hard_task_default_model(m);
elastic_hard_task_def_wcet(m,500);
elastic_hard_task_def_maxperiod(m,500000);
elastic_hard_task_def_cnormal(m,500);
elastic_hard_task_def_period(m,500000);
elastic_hard_task_def_group(m,1);
elastic_hard_task_def_ctrl_jet(m);
 
 
p1 = task_create("Clock",clock,&m,NULL);
if (p1 == -1) {
perror("testhd.c(main): Could not create task <Clock> ...");
sys_end();
}
 
 
 
 
elastic_hard_task_def_wcet(m,1000);
elastic_hard_task_def_maxperiod(m,100000);
elastic_hard_task_def_cnormal(m,1000);
elastic_hard_task_def_period(m,100000);
p2 = task_create("JetControl",jetcontrol,&m,NULL);
if (p2 == -1) {
perror("testhd.c(main): Could not create task <JetControl> ...");
sys_end();
}
 
elastic_hard_task_def_wcet(m,21000);
elastic_hard_task_def_maxperiod(m,155000);
elastic_hard_task_def_cnormal(m,21000);
elastic_hard_task_def_period(m,155000);
 
 
p3 = task_create("Hard_asteroide1",hard_asteroide1,&m,NULL);
if (p3 == -1) {
perror("testhd.c(main): Could not create task <Hard asteroide> ...");
sys_end();
}
 
elastic_hard_task_def_wcet(m,12000);
elastic_hard_task_def_maxperiod(m,61000);
elastic_hard_task_def_cnormal(m,12000);
elastic_hard_task_def_period(m,61000);
 
 
 
p4 = task_create("Hard_asteroide2",hard_asteroide,&m,NULL);
if (p4 == -1) {
perror("testhd.c(main): Could not create task <Hard asteroide> ...");
sys_end();
}
 
 
elastic_hard_task_def_wcet(m,30000);
elastic_hard_task_def_maxperiod(m,200000);
elastic_hard_task_def_cnormal(m,30000);
elastic_hard_task_def_period(m,200000);
 
 
p5 = task_create("Hard_asteroide3",hard_asteroide2,&m,NULL);
if (p5 == -1) {
perror("testhd.c(main): Could not create task <Hard asteroide> ...");
sys_end();
}
 
elastic_hard_task_def_wcet(m,30000);
elastic_hard_task_def_maxperiod(m,100000);
elastic_hard_task_def_cnormal(m,30000);
elastic_hard_task_def_period(m,100000);
 
 
p6 = task_create("Hard_asteroide3",hard_asteroide2,&m,NULL);
if (p6 == -1) {
perror("testhd.c(main): Could not create task <Hard asteroide> ...");
sys_end();
}
elastic_hard_task_def_wcet(m,10000);
elastic_hard_task_def_maxperiod(m,200000);
elastic_hard_task_def_cnormal(m,2500);
elastic_hard_task_def_period(m,49000);
 
 
p7 = task_create("Hard_asteroide3",hard_asteroide3,&m,NULL);
if (p7 == -1) {
perror("testhd.c(main): Could not create task <Hard asteroide> ...");
sys_end();
}
 
 
 
printf_xy(0,STAT_Y + 15,WHITE,"Hard asteroide PID= %-3d ",p3);
printf_xy(0,STAT_Y + 17,WHITE,"Clock PID= %-3d ",p1);
printf_xy(0,STAT_Y + 18,WHITE,"JetControl PID= %-3d ",p2);
 
task_nopreempt();
fineprg.tv_sec = 30;
fineprg.tv_nsec = 0;
kern_event_post(&fineprg,fine,NULL);
group_activate(1);
return 0;
}
 
/advdemos/trunk/cash/cash.c
0,0 → 1,814
/*
* Project: S.Ha.R.K.
*
* Coordinators:
* Giorgio Buttazzo <giorgio@sssup.it>
* Paolo Gai <pj@gandalf.sssup.it>
*
* Authors :
* Paolo Gai <pj@gandalf.sssup.it>
* Massimiliano Giorgi <massy@gandalf.sssup.it>
* Luca Abeni <luca@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: cash.c,v 1.1.1.1 2004-05-24 17:54:49 giacomo Exp $
 
File: $File$
Revision: $Revision: 1.1.1.1 $
Last update: $Date: 2004-05-24 17:54:49 $
------------
 
This file contains the aperiodic server CBS (Total Bandwidth Server)
 
Read CBS.h for further details.
 
**/
 
/*
* Copyright (C) 2000 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
*
*/
 
 
#include "cash.h"
#include <ll/stdio.h>
#include <ll/string.h>
#include <kernel/model.h>
#include <kernel/descr.h>
#include <kernel/var.h>
#include <kernel/func.h>
 
/*+ Status used in the level +*/
#define CBSGHD_IDLE APER_STATUS_BASE /*+ waiting the activation +*/
#define CBSGHD_ZOMBIE APER_STATUS_BASE+1 /*+ waiting the period end +*/
 
/* structure of an element of the capacity queue */
struct cap_queue {
int cap;
struct timespec dead;
struct cap_queue *next;
};
 
/*+ the level redefinition for the CBS_HD level +*/
typedef struct {
level_des l; /*+ the standard level descriptor +*/
 
/* The wcet are stored in the task descriptor, but we need
an array for the deadlines. We can't use the timespec_priority
field because it is used by the master level!!!...
Notice that however the use of the timespec_priority field
does not cause any problem... */
 
struct timespec cbsghd_dline[MAX_PROC]; /*+ CBSGHD deadlines +*/
TIME period[MAX_PROC]; /*+ CBSGHD activation period +*/
 
TIME maxperiod[MAX_PROC]; /*+ maximum period of each elastic task +*/
int cremaining[MAX_PROC]; /*+ instance remaining computation time +*/
 
TIME act_period[MAX_PROC]; /*+ actual period of each elastic task: it
must be less than maxperiod!!! +*/
 
struct timespec request_time[MAX_PROC]; /* used for the response time */
TIME last_response_time[MAX_PROC]; /* response time of the last instance */
TIME cnormal[MAX_PROC]; /*+ CBSGHD normal computation time +*/
 
struct timespec reactivation_time[MAX_PROC];
/*+ the time at witch the reactivation timer is post +*/
int reactivation_timer[MAX_PROC];
/*+ the recativation timer +*/
 
struct cap_queue *queue; /* pointer to the spare capacity queue */
 
int flags; /*+ the init flags... +*/
 
bandwidth_t U; /*+ the used bandwidth by the server +*/
 
int idle; /* the idle flag... */
struct timespec start_idle; /*gives the start time of the last idle period */
LEVEL scheduling_level;
 
} CBSGHD_level_des;
 
 
/* insert a capacity in the queue capacity ordering by deadline */
 
static int c_insert(struct timespec dead, int cap, struct cap_queue **que,
PID p)
{
struct cap_queue *prev, *n, *new;
 
prev = NULL;
n = *que;
 
while ((n != NULL) &&
!TIMESPEC_A_LT_B(&dead, &n->dead)) {
prev = n;
n = n->next;
}
 
new = (struct cap_queue *)kern_alloc(sizeof(struct cap_queue));
if (new == NULL) {
kern_printf("\nNew cash_queue element failed\n");
kern_raise(XINVALID_TASK, p);
return -1;
}
new->next = NULL;
new->cap = cap;
new->dead = dead;
if (prev != NULL)
prev->next = new;
else
*que = new;
 
if (n != NULL)
new->next = n;
return 0;
}
 
/* extract the first element from the capacity queue */
 
static int c_extractfirst(struct cap_queue **que)
{
struct cap_queue *p = *que;
 
 
if (*que == NULL) return(-1);
*que = (*que)->next;
kern_free(p, sizeof(struct cap_queue));
return(1);
}
 
/* read data of the first element from the capacity queue */
 
static void c_readfirst(struct timespec *d, int *c, struct cap_queue *que)
{
*d = que->dead;
*c = que->cap;
}
 
/* write data of the first element from the capacity queue */
 
static void c_writefirst(struct timespec dead, int cap, struct cap_queue *que)
{
que->dead = dead;
que->cap = cap;
}
 
 
static void CBSGHD_activation(CBSGHD_level_des *lev,
PID p,
struct timespec *acttime)
{
JOB_TASK_MODEL job;
/* This rule is used when we recharge the budget at initial task activation
and each time a new task instance must be activated */
if (TIMESPEC_A_GT_B(acttime, &lev->cbsghd_dline[p])) {
/* we modify the deadline ... */
TIMESPEC_ASSIGN(&lev->cbsghd_dline[p], acttime);
}
 
lev->act_period[p] = 0;
if (proc_table[p].avail_time > 0)
proc_table[p].avail_time = 0;
 
 
 
 
/* there is a while because if the wcet is << than the system tick
we need to postpone the deadline many times */
while (proc_table[p].avail_time <= 0) {
/* A spare capacity is inserted in the capacity queue!! */
ADDUSEC2TIMESPEC(lev->period[p], &lev->cbsghd_dline[p]);
lev->act_period[p] += lev->period[p];
c_insert(lev->cbsghd_dline[p], lev->cnormal[p], &lev->queue, p);
/* it exploits available capacities from the capacity queue */
while (proc_table[p].avail_time < (int)lev->cnormal[p] &&
lev->queue != NULL) {
struct timespec dead;
int cap, delta;
delta = lev->cnormal[p] - proc_table[p].avail_time;
c_readfirst(&dead, &cap, lev->queue);
if (!TIMESPEC_A_GT_B(&dead, &lev->cbsghd_dline[p])) {
if (cap > delta) {
proc_table[p].avail_time += delta;
c_writefirst(dead, cap - delta, lev->queue);
}
else {
proc_table[p].avail_time += cap;
c_extractfirst(&lev->queue);
}
}
else
break;
}
}
lev->cremaining[p] = proc_table[p].wcet - proc_table[p].avail_time;
 
#ifdef TESTG
if (starttime && p == 3) {
oldx = x;
x = ((lev->cbsghd_dline[p].tv_sec*1000000+lev->cbsghd_dline[p].tv_nsec/1000)/5000 - starttime) + 20;
// kern_printf("(a%d)",lev->cbsghd_dline[p].tv_sec*1000000+lev->cbsghd_dline[p].tv_nsec/1000);
if (oldx > x) sys_end();
if (x<640)
grx_plot(x, 15, 8);
}
#endif
 
/* and, finally, we reinsert the task in the master level */
job_task_default_model(job, lev->cbsghd_dline[p]);
job_task_def_yesexc(job);
level_table[ lev->scheduling_level ]->
private_insert(lev->scheduling_level, p, (TASK_MODEL *)&job);
}
 
 
/* this is the periodic reactivation of the task... */
static void CBSGHD_timer_reactivate(void *par)
{
PID p = (PID) par;
CBSGHD_level_des *lev;
 
lev = (CBSGHD_level_des *)level_table[proc_table[p].task_level];
 
if (proc_table[p].status == CBSGHD_IDLE) {
/* the task has finished the current activation and must be
reactivated */
/* request_time represents the time of the last instance release!! */
TIMESPEC_ASSIGN(&lev->request_time[p], &lev->reactivation_time[p]);
/* If idle=1, then we have to discharge the capacities stored in
the capacity queue up to the length of the idle interval */
if (lev->idle == 1) {
TIME interval;
struct timespec delta;
lev->idle = 0;
SUBTIMESPEC(&lev->request_time[p], &lev->start_idle, &delta);
/* length of the idle interval expressed in usec! */
interval = TIMESPEC2NANOSEC(&delta) / 1000;
 
/* it discharge the available capacities from the capacity queue */
while (interval > 0 && lev->queue != NULL) {
struct timespec dead;
int cap;
c_readfirst(&dead, &cap, lev->queue);
if (cap > interval) {
c_writefirst(dead, cap - interval, lev->queue);
interval = 0;
}
else {
interval -= cap;
c_extractfirst(&lev->queue);
}
}
}
 
CBSGHD_activation(lev,p,&lev->reactivation_time[p]);
 
/* check the constraint on the maximum period permitted... */
if (lev->act_period[p] > lev->maxperiod[p]) {
kern_printf("Deadline miss(timer_react.! process:%d act_period:%lu maxperiod:%lu\n",
p, lev->act_period[p], lev->maxperiod[p]);
kern_raise(XDEADLINE_MISS,p);
}
 
/* Set the reactivation timer */
TIMESPEC_ASSIGN(&lev->reactivation_time[p], &lev->cbsghd_dline[p]);
lev->reactivation_timer[p] = kern_event_post(&lev->reactivation_time[p],
CBSGHD_timer_reactivate,
(void *)p);
event_need_reschedule();
}
else {
/* this situation cannot occur */
kern_printf("Trying to reactivate a task which is not IDLE!!!/n");
kern_raise(XINVALID_TASK,p);
}
}
 
 
 
 
 
static void CBSGHD_avail_time_check(CBSGHD_level_des *lev, PID p)
{
/*+ if the capacity became negative the remaining computation time
is diminuished.... +*/
/* if (p==4)
kern_printf("(old dead:%d av_time:%d crem:%d)\n",
lev->cbsghd_dline[p].tv_sec*1000000+
lev->cbsghd_dline[p].tv_nsec/1000, proc_table[p].avail_time,
lev->cremaining[p]); */
 
if (proc_table[p].avail_time < 0)
lev->cremaining[p] += proc_table[p].avail_time;
if (lev->cremaining[p] <= 0) {
kern_printf("Task:%d WCET violation \n", p);
kern_raise(XWCET_VIOLATION, p);
ll_abort(666);
}
 
/* there is a while because if the wcet is << than the system tick
we need to postpone the deadline many times */
while (proc_table[p].avail_time <= 0) {
/* it exploits available capacities from the capacity queue */
while (proc_table[p].avail_time < lev->cremaining[p]
&& lev->queue != NULL) {
struct timespec dead;
int cap, delta;
delta = lev->cremaining[p] - proc_table[p].avail_time;
c_readfirst(&dead, &cap, lev->queue);
if (!TIMESPEC_A_GT_B(&dead, &lev->cbsghd_dline[p])) {
if (cap > delta) {
proc_table[p].avail_time += delta;
c_writefirst(dead, cap - delta, lev->queue);
}
else {
proc_table[p].avail_time += cap;
c_extractfirst(&lev->queue);
}
}
else
break;
}
 
/* if (p==5 && proc_table[p].avail_time <= 0 &&
lev->cremaining[p] > lev->cnormal[p])
kern_printf("(inter dead:%d av_time:%d crem:%d)\n",
lev->cbsghd_dline[p].tv_sec*1000000+
lev->cbsghd_dline[p].tv_nsec/1000, proc_table[p].avail_time,
lev->cremaining[p]); */
/* The remaining computation time is modified according
to the new budget! */
if (proc_table[p].avail_time > 0)
lev->cremaining[p] -= proc_table[p].avail_time;
else {
/* the CBSGHD rule for recharging the capacity: */
if (lev->cremaining[p] > lev->cnormal[p]) {
ADDUSEC2TIMESPEC(lev->period[p], &lev->cbsghd_dline[p]);
lev->act_period[p] += lev->period[p];
/* A spare capacity is inserted in the capacity queue!! */
c_insert(lev->cbsghd_dline[p], lev->cnormal[p], &lev->queue, p);
}
else {
TIME t;
t = (lev->cremaining[p] * lev->period[p]) / lev->cnormal[p];
ADDUSEC2TIMESPEC(t, &lev->cbsghd_dline[p]);
lev->act_period[p] += t;
/* A spare capacity is inserted in the capacity queue!! */
c_insert(lev->cbsghd_dline[p], lev->cremaining[p], &lev->queue, p);
}
}
}
/* if (p==4)
kern_printf("n dead:%d av_time:%d crem:%d)\n",
lev->cbsghd_dline[p].tv_sec*1000000+
lev->cbsghd_dline[p].tv_nsec/1000, proc_table[p].avail_time,
lev->cremaining[p]); */
 
/* check the constraint on the maximum period permitted... */
if (lev->act_period[p] > lev->maxperiod[p]) {
/*kern_printf("n dead:%d av_time:%d crem:%d)\n",
lev->cbsghd_dline[p].tv_sec*1000000+
lev->cbsghd_dline[p].tv_nsec/1000, proc_table[p].avail_time,
lev->cremaining[p]); */
kern_printf("Deadline miss(av.time_check! process:%d act_period:%lu maxperiod:%lu\n",
p, lev->act_period[p], lev->maxperiod[p]);
kern_raise(XDEADLINE_MISS,p);
}
 
 
if (TIMESPEC_A_LT_B(&lev->reactivation_time[p], &lev->cbsghd_dline[p])) {
/* we delete the reactivation timer */
kern_event_delete(lev->reactivation_timer[p]);
/* repost the event at the next instance deadline... */
lev->reactivation_time[p] = lev->cbsghd_dline[p];
lev->reactivation_timer[p] = kern_event_post(&lev->reactivation_time[p],
CBSGHD_timer_reactivate,
(void *)p);
}
#ifdef TESTG
if (starttime && p == 3) {
oldx = x;
x = ((lev->cbsghd_dline[p].tv_sec*1000000+
lev->cbsghd_dline[p].tv_nsec/1000)/5000 - starttime) + 20;
// kern_printf("(e%d avail%d)",lev->cbsghd_dline[p].tv_sec*1000000+
lev->cbsghd_dline[p].tv_nsec/1000,proc_table[p].avail_time);
if (oldx > x) sys_end();
if (x<640)
grx_plot(x, 15, 2);
}
#endif
}
 
 
/*+ this function is called when a killed or ended task reach the
period end +*/
static void CBSGHD_timer_zombie(void *par)
{
PID p = (PID) par;
CBSGHD_level_des *lev;
 
lev = (CBSGHD_level_des *)level_table[proc_table[p].task_level];
 
/* we finally put the task in the FREE status */
proc_table[p].status = FREE;
iq_insertfirst(p,&freedesc);
 
/* and free the allocated bandwidth */
lev->U -= (MAX_BANDWIDTH/lev->period[p]) * lev->cnormal[p];
 
}
 
static PID CBSGHD_public_scheduler(LEVEL l)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
/* it stores the actual time and set the IDLE flag in order to handle
the capacity queue discharging!!! */
lev->idle = 1;
kern_gettime(&lev->start_idle);
 
/* the CBSGHD don't schedule anything...
it's an EDF level or similar that do it! */
return NIL;
}
 
/* The on-line guarantee is enabled only if the appropriate flag is set... */
static int CBSGHD_public_guarantee(LEVEL l, bandwidth_t *freebandwidth)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
 
if (lev->flags & CBSGHD_FAILED_GUARANTEE) {
*freebandwidth = 0;
//kern_printf("guarantee :garanzia fallita!!!!!!\n");
return 0;
}
else if (*freebandwidth >= lev->U) {
*freebandwidth -= lev->U;
return 1;
}
else {
//kern_printf("guarantee :garanzia fallita per mancanza di banda!!!!!!\n");
//kern_printf("freeband: %d request band: %d", *freebandwidth, lev->U);
return 0;
}
}
 
static int CBSGHD_public_create(LEVEL l, PID p, TASK_MODEL *m)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
ELASTIC_HARD_TASK_MODEL *s;
bandwidth_t b1, b2;
 
if (m->pclass != ELASTIC_HARD_PCLASS) return -1;
if (m->level != 0 && m->level != l) return -1;
s = (ELASTIC_HARD_TASK_MODEL *)m;
 
/* kern_printf("accept :ELASTIC TASK found!!!!!!\n"); */
b1 = (MAX_BANDWIDTH / s->period) * s->cnormal;
b2 = (MAX_BANDWIDTH / s->maxperiod) * s->wcet;
if (!(s->wcet && s->cnormal && s->period && s->maxperiod &&
s->wcet >= s->cnormal && b1 >= b2) )
return -1;
/* kern_printf("period: %d maxperiod: %d cnormal: %d wcet: %d, b1: %d b2:
%d\n", s->period, s->maxperiod, s->cnormal, s->wcet, b1, b2); */
 
/* now we know that m is a valid model */
 
 
/* Enable wcet check */
proc_table[p].avail_time = 0;
proc_table[p].wcet = s->wcet;
proc_table[p].control |= CONTROL_CAP;
 
lev->period[p] = s->period;
lev->maxperiod[p] = s->maxperiod;
lev->cnormal[p] = s->cnormal;
NULL_TIMESPEC(&lev->cbsghd_dline[p]);
NULL_TIMESPEC(&lev->request_time[p]);
 
 
/* update the bandwidth... */
if (lev->flags & CBSGHD_ENABLE_GUARANTEE) {
bandwidth_t b;
b = (MAX_BANDWIDTH / s->period) * s->cnormal;
 
/* really update lev->U, checking an overflow... */
if (MAX_BANDWIDTH - lev->U > b)
lev->U += b;
else
/* The task can NOT be guaranteed (U>MAX_BANDWIDTH)...
(see EDF.c) */
lev->flags |= CBSGHD_FAILED_GUARANTEE;
}
 
 
return 0; /* OK, also if the task cannot be guaranteed... */
}
 
static void CBSGHD_public_detach(LEVEL l, PID p)
{
/* the CBSGHD level doesn't introduce any dinamic allocated new field.
we have only to reset the NO_GUARANTEE FIELD and decrement the allocated
bandwidth */
 
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
 
if (lev->flags & CBSGHD_FAILED_GUARANTEE)
lev->flags &= ~CBSGHD_FAILED_GUARANTEE;
else
lev->U -= (MAX_BANDWIDTH / lev->period[p]) * lev->cnormal[p];
 
}
 
static void CBSGHD_public_dispatch(LEVEL l, PID p, int nostop)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
level_table[ lev->scheduling_level ]->
private_dispatch(lev->scheduling_level,p,nostop);
 
}
 
static void CBSGHD_public_epilogue(LEVEL l, PID p)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
JOB_TASK_MODEL job;
 
/* check if the budget is finished... */
if ( proc_table[p].avail_time <= 0) {
/* we kill the current activation */
level_table[ lev->scheduling_level ]->
private_extract(lev->scheduling_level, p);
 
/* we modify the deadline */
CBSGHD_avail_time_check(lev, p);
 
/* and, finally, we reinsert the task in the master level */
job_task_default_model(job, lev->cbsghd_dline[p]);
job_task_def_yesexc(job);
level_table[ lev->scheduling_level ]->
private_insert(lev->scheduling_level, p, (TASK_MODEL *)&job);
// kern_printf("epil : dl %d per %d p %d |\n",
// lev->cbsghd_dline[p].tv_nsec/1000,lev->period[p],p);
 
}
else
/* the task has been preempted. it returns into the ready queue by
calling the guest_epilogue... */
level_table[ lev->scheduling_level ]->
private_epilogue(lev->scheduling_level,p);
}
 
static void CBSGHD_public_activate(LEVEL l, PID p)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
 
kern_gettime(&lev->request_time[p]);
/* If idle=1, then we have to discharge the capacities stored in
the capacity queue up to the length of the idle interval */
if (lev->idle == 1) {
TIME interval;
struct timespec delta;
lev->idle = 0;
SUBTIMESPEC(&lev->request_time[p], &lev->start_idle, &delta);
/* length of the idle interval expressed in usec! */
interval = TIMESPEC2NANOSEC(&delta) / 1000;
 
/* it discharge the available capacities from the capacity queue */
while (interval > 0 && lev->queue != NULL) {
struct timespec dead;
int cap;
c_readfirst(&dead, &cap, lev->queue);
if (cap > interval) {
c_writefirst(dead, cap - interval, lev->queue);
interval = 0;
}
else {
interval -= cap;
c_extractfirst(&lev->queue);
}
}
}
CBSGHD_activation(lev, p, &lev->request_time[p]);
 
 
/* check the constraint on the maximum period permitted... */
if (lev->act_period[p] > lev->maxperiod[p]) {
kern_printf("Deadline miss(task_activ.! process:%d act_period:%lu maxperiod:%lu\n",
p, lev->act_period[p], lev->maxperiod[p]);
kern_raise(XDEADLINE_MISS,p);
}
/* Set the reactivation timer */
TIMESPEC_ASSIGN(&lev->reactivation_time[p], &lev->cbsghd_dline[p]);
lev->reactivation_timer[p] = kern_event_post(&lev->reactivation_time[p],
CBSGHD_timer_reactivate,
(void *)p);
// kern_printf("act : %d %d |",lev->cbsghd_dline[p].tv_nsec/1000,p);
}
 
static void CBSGHD_public_unblock(LEVEL l, PID p)
{
printk("CBSGHD_task_insert\n");
kern_raise(XINVALID_TASK,p);
}
 
static void CBSGHD_public_block(LEVEL l, PID p)
{
printk("CBSGHD_task_extract\n");
kern_raise(XINVALID_TASK,p);
}
 
static int CBSGHD_public_message(LEVEL l, PID p, void *m)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
struct timespec act_time, res;
 
/* It computes the response time of the current instance... */
kern_gettime(&act_time);
SUBTIMESPEC(&act_time, &lev->request_time[p], &res);
/* response time expressed in usec! */
lev->last_response_time[p] = TIMESPEC2NANOSEC(&res) / 1000;
level_table[ lev->scheduling_level ]->
private_extract(lev->scheduling_level,p);
 
/* A spare capacity is inserted in the capacity queue!! */
if (proc_table[p].avail_time > 0) {
c_insert(lev->cbsghd_dline[p], proc_table[p].avail_time, &lev->queue, p);
proc_table[p].avail_time = 0;
}
 
proc_table[p].status = CBSGHD_IDLE;
 
jet_update_endcycle(); /* Update the Jet data... */
 
return 0;
}
 
static void CBSGHD_public_end(LEVEL l, PID p)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
 
/* check if the capacity became negative... */
/* there is a while because if the wcet is << than the system tick
we need to postpone the deadline many times */
while (proc_table[p].avail_time < 0) {
/* the CBSGHD rule for recharging the capacity */
proc_table[p].avail_time += lev->cnormal[p];
ADDUSEC2TIMESPEC(lev->period[p], &lev->cbsghd_dline[p]);
}
level_table[ lev->scheduling_level ]->
private_extract(lev->scheduling_level,p);
 
/* we delete the reactivation timer */
kern_event_delete(lev->reactivation_timer[p]);
lev->reactivation_timer[p] = -1;
 
/* Finally, we post the zombie event. when the end period is reached,
the task descriptor and banwidth are freed */
proc_table[p].status = CBSGHD_ZOMBIE;
lev->reactivation_timer[p] = kern_event_post(&lev->cbsghd_dline[p],
CBSGHD_timer_zombie,
(void *)p);
}
 
/* Registration functions */
 
/*+ Registration function:
int flags the init flags ... see CBS.h +*/
LEVEL CBSGHD_register_level(int flags, LEVEL master)
{
LEVEL l; /* the level that we register */
CBSGHD_level_des *lev; /* for readableness only */
PID i; /* a counter */
 
printk("CBSGHD_register_level\n");
 
/* request an entry in the level_table */
l = level_alloc_descriptor(sizeof(CBSGHD_level_des));
 
lev = (CBSGHD_level_des *)level_table[l];
 
printk(" lev=%d\n",(int)lev);
 
/* fill the standard descriptor */
lev->l.public_scheduler = CBSGHD_public_scheduler;
 
if (flags & CBSGHD_ENABLE_GUARANTEE)
lev->l.public_guarantee = CBSGHD_public_guarantee;
else
lev->l.public_guarantee = NULL;
 
lev->l.public_create = CBSGHD_public_create;
lev->l.public_detach = CBSGHD_public_detach;
lev->l.public_end = CBSGHD_public_end;
lev->l.public_dispatch = CBSGHD_public_dispatch;
lev->l.public_epilogue = CBSGHD_public_epilogue;
lev->l.public_activate = CBSGHD_public_activate;
lev->l.public_unblock = CBSGHD_public_unblock;
lev->l.public_block = CBSGHD_public_block;
lev->l.public_message = CBSGHD_public_message;
 
/* fill the CBSGHD descriptor part */
for (i=0; i<MAX_PROC; i++) {
NULL_TIMESPEC(&lev->cbsghd_dline[i]);
lev->period[i] = 0;
NULL_TIMESPEC(&lev->request_time[i]);
lev->last_response_time[i] = 0;
NULL_TIMESPEC(&lev->reactivation_time[i]);
lev->reactivation_timer[i] = -1;
}
 
 
lev->U = 0;
lev->idle = 0;
lev->queue = NULL;
lev->scheduling_level = master;
 
lev->flags = flags & 0x07;
 
return l;
}
 
 
int CBSGHD_get_response_time(LEVEL l, PID p)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
 
return lev->last_response_time[p];
}
 
 
bandwidth_t CBSGHD_usedbandwidth(LEVEL l)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
 
return lev->U;
}
 
/advdemos/trunk/cash/initcash.c
0,0 → 1,128
/*
* 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: initcash.c,v 1.1.1.1 2004-05-24 17:54:49 giacomo Exp $
 
File: $File$
Revision: $Revision: 1.1.1.1 $
Last update: $Date: 2004-05-24 17:54:49 $
------------
 
System initialization file
 
The tick is set to TICK ms.
 
This file contains the 2 functions needed to initialize the system.
 
These functions register the following levels:
 
an EDF (Earliest Deadline First) level
a RR (Round Robin) level
a CBSHD (Constant Bandwidth Server with Hard Deadlines) level
a Dummy level
 
 
 
It can accept these task models (into () the mandatory fields):
 
HARD_TASK_MODEL (wcet+mit) at level 0
NRT_TASK_MODEL at level 1
ELASTIC_HARD_TASK_MODEL (cnormal,period,wcet,maxperiod) at level 5
 
**/
 
/*
* Copyright (C) 2000 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
*
*/
 
 
 
#include "kernel/kern.h"
#include "modules/edf.h"
#include "modules/rr.h"
#include "modules/tbs.h"
#include "modules/cbs.h"
#include "cash.h"
#include "modules/dummy.h"
#include "modules/sem.h"
#include "modules/hartport.h"
#include "drivers/keyb.h"
 
 
/*+ sysyem tick in us +*/
#define TICK 300
 
#define RRTICK 5000
 
 
TIME __kernel_register_levels__(void *arg)
{
struct multiboot_info *mb = (struct multiboot_info *)arg;
 
EDF_register_level(EDF_ENABLE_ALL);
CBSGHD_register_level(CBSGHD_ENABLE_ALL, 0);
RR_register_level(RRTICK, RR_MAIN_YES, mb);
/* CBS_register_level(CBS_ENABLE_ALL, 0); */
//CBSHD_register_level(CBSHD_ENABLE_ALL, 0);
dummy_register_level();
 
SEM_register_module();
 
return TICK;
}
 
TASK __init__(void *arg)
{
struct multiboot_info *mb = (struct multiboot_info *)arg;
 
HARTPORT_init();
 
KEYB_init(NULL);
 
__call_main__(mb);
 
return (void *)0;
}
 
 
 
 
 
 
 
 
 
 
/advdemos/trunk/cash/cash.h
0,0 → 1,177
/*
* Project: S.Ha.R.K.
*
* Coordinators:
* Giorgio Buttazzo <giorgio@sssup.it>
* Paolo Gai <pj@gandalf.sssup.it>
*
* Authors :
* Paolo Gai <pj@gandalf.sssup.it>
* Massimiliano Giorgi <massy@gandalf.sssup.it>
* Luca Abeni <luca@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: cash.h,v 1.1.1.1 2004-05-24 17:54:50 giacomo Exp $
 
File: $File$
Revision: $Revision: 1.1.1.1 $
Last update: $Date: 2004-05-24 17:54:50 $
------------
 
This file contains the server CBSHD (CASH Algorithm)
 
Title:
CBSHD (Constant Bandwidth Server with hard deadlines)
 
Task Models Accepted:
ELASTIC_HARD_TASK_MODEL - Elastic Hard Tasks
wcet field must be != 0
cnormal field must be != 0
period field must be != 0
Description:
This module schedule his tasks following the CBSHD scheme.
(see Marco Caccamo, Giorgio Buttazzo and Lui Sha
"Elastic Feedback Control"
Proceedings of the EUROMICRO 2000)
 
The tasks are inserted in an EDF level (or similar) with a JOB_TASK_MODEL,
and the CBSHD level expects that the task is scheduled with the absolute
deadline passed in the model.
 
The task guarantee is based on the factor utilization approach.
 
Exceptions raised:
XUNVALID_GUEST
This level doesn't support guests. When a guest operation
is called, the exception is raised.
 
These exceptions are pclass-dependent...
XDEADLINE_MISS
If a task miss his deadline, the exception is raised.
Restrictions & special features:
- This level doesn't manage the main task.
- At init time we have to specify:
. guarantee check
(when all task are created the system will check that the task_set
will not use more than the available bandwidth)
- A function to return the used bandwidth of the level is provided.
- A function to return the pending activations of the task.
 
**/
 
/*
* Copyright (C) 2000 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
*
*/
 
 
#ifndef __CBSGHD_H__
#define __CBSGHD_H__
 
#include <ll/ll.h>
#include <kernel/config.h>
#include <sys/types.h>
#include <kernel/types.h>
 
 
 
 
 
 
 
 
/*+ flags... +*/
#define CBSGHD_ENABLE_GUARANTEE 1 /*+ Task Guarantee enabled +*/
#define CBSGHD_ENABLE_ALL 1
 
#define CBSGHD_FAILED_GUARANTEE 8 /*+ used in the module, unsettabl
in EDF_register_level... +*/
 
 
 
 
 
#define ELASTIC_HARD_PCLASS 0x0600
 
#define CBSGHD_LEVELNAME "CBSGHD base"
#define CBSGHD_LEVEL_CODE 106
#define CBSGHD_LEVEL_VERSION 1
 
 
/* -----------------------------------------------------------------------
ELASTIC_HARD_TASK_MODEL: elastic hard Tasks
----------------------------------------------------------------------- */
 
typedef struct {
TASK_MODEL t;
TIME cnormal;
TIME period;
TIME wcet;
TIME maxperiod;
} ELASTIC_HARD_TASK_MODEL;
 
#define elastic_hard_task_default_model(m) \
task_default_model((m).t,ELASTIC_HARD_PCLASS), \
(m).cnormal = 0, \
(m).period = 0, \
(m).wcet = 0, \
(m).maxperiod = 0
#define elastic_hard_task_def_level(m,l) task_def_level((m).t,l)
#define elastic_hard_task_def_arg(m,a) task_def_arg((m).t,a)
#define elastic_hard_task_def_stack(m,s) task_def_stack((m).t,s)
#define elastic_hard_task_def_stackaddr(m,s) task_def_stackaddr((m).t,s)
#define elastic_hard_task_def_group(m,g) task_def_group((m).t,g)
#define elastic_hard_task_def_usemath(m) task_def_usemath((m).t)
#define elastic_hard_task_def_system(m) task_def_system((m).t)
#define elastic_hard_task_def_nokill(m) task_def_nokill((m).t)
#define elastic_hard_task_def_ctrl_jet(m) task_def_ctrl_jet((m).t)
#define elastic_hard_task_def_cnormal(m,c) (m).cnormal = (c)
#define elastic_hard_task_def_period(m,p) (m).period = (p)
#define elastic_hard_task_def_wcet(m,w) (m).wcet = (w)
#define elastic_hard_task_def_maxperiod(m,p) (m).maxperiod = (p)
#define elastic_hard_task_def_joinable(m) task_def_joinable((m).t)
#define elastic_hard_task_def_unjoinable(m) task_def_unjoinable((m).t)
 
 
 
 
/*+ Registration function:
int flags Options to be used in this level instance...
LEVEL master the level that must be used as master level for the
CBSGHD tasks
 
returns the level number at which the module has been registered.
+*/
LEVEL CBSGHD_register_level(int flags, LEVEL master);
 
/*+ Returns the used bandwidth of a level +*/
bandwidth_t CBSGHD_usedbandwidth(LEVEL l);
 
#endif
 
/advdemos/trunk/cash/readme.txt
0,0 → 1,6
This Example has been made by Marco Caccamo.
 
There is not a lot of documentation available, so if you have problems please
send an e-mail to Marco ( http://gandalf.sssup.it/~caccamo/ )
 
Paolo
/advdemos/trunk/cash/makefile
0,0 → 1,17
#
#
#
 
ifndef BASE
BASE=../..
endif
 
include $(BASE)/config/config.mk
 
PROGS=testcash
 
include $(BASE)/config/example.mk
 
testcash:
make -f $(SUBMAKE) APP=testcash INIT= OTHEROBJS="initcash.o cash.o" OTHERINCL= SHARKOPT="__OLDCHAR__ __GRX__"