Subversion Repositories shark

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

/*
 * Project: HARTIK (HA-rd R-eal TI-me K-ernel)
 *
 * Coordinators: Giorgio Buttazzo <giorgio@sssup.it>
 *               Gerardo Lamastra <gerardo@sssup.it>
 *
 * Authors     : Massimiliano Giorgi <massy@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
 */


/*
 * Copyright (C) 2000 Massimiliano Giorgi
 *
 * 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
 *
 */


/*
 * CVS :        $Id: trace.c,v 1.1.1.1 2002-03-29 14:12:53 pj Exp $
 *
 * File:        $File$
 * Revision:    $Revision: 1.1.1.1 $
 * Last update: $Date: 2002-03-29 14:12:53 $
 */


#include <ll/sys/types.h>
#include <kernel/assert.h>
#include <kernel/func.h>
#include <kernel/log.h>

#include <kernel/trace.h>
#include <modules/trace.h>
#include <modules/traceevt.h>
#include <modules/tracestr.h>

/* Well...
 * TRC_init2() and tracer() must be called when the system is up,
 * so they can call functions of the unistd.h
 */

#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

/* -- */

/*+ number of event per blocks +*/
#define TRC_BLOCKSIZE     1024

/*+ numbers of tables can grow until this is raggiunto +*/
#define TRC_MAXNUMTABLES    48

/* -- */

#define DEBUG_INIT KERN_DEBUG
//#undef DEBUGINIT

#ifdef DEBUG_INIT
#define printk0(fmt,args...) printk(DEBUG_INIT fmt,##args)
#else
#define printk0(fmt,args...)
#endif


/* -- */

static __inline__ void *allocmemory(long size)
{
  SYS_FLAGS f;
  void *ptr;
  f=kern_fsave();
  ptr=kern_alloc(size+sizeof(long));
  kern_frestore(f);
  if (ptr!=NULL) {
    *((long*)ptr)=size;
    return (char *)ptr+sizeof(long);
  }
  return ptr;
}

static __inline__ void freememory(void *ptr)
{
  SYS_FLAGS f;
  long size;
  size=*(long*)((char *)ptr-sizeof(long));
  f=kern_fsave();
  kern_free(ptr-sizeof(long),size+sizeof(long));
  kern_frestore(f);
}

/* -- */

typedef struct TAGtrc_events {
  struct TAGtrc_events *next;
  trc_event_t event[TRC_BLOCKSIZE] __attribute__((packed));
} trc_events;

static int counter;
static int hoops;
static trc_events *acttable,*writable;
static int actindex,wriindex;
static int handle=-1;

static int numtables;

static TASK tracer(void *dummy)
{
  int index,n,res;
  res=0;
  for (;;) {
    while (counter>0) {
      kern_cli();
      if (acttable!=writable) {
        kern_sti();
        n=TRC_BLOCKSIZE-wriindex;
        res=write(handle,writable->event+wriindex,n*sizeof(trc_event_t));
        writable=writable->next;
        wriindex=0;
      } else {
        index=actindex;
        kern_sti();
        n=index-wriindex;
        assertk(n>0);
        res=write(handle,writable->event+wriindex,n*sizeof(trc_event_t));
        wriindex=index;
      }
      if (res!=n*sizeof(trc_event_t)) {
        res=-1;
        break;
      }
      counter-=n;
      assertk(counter>=0);
    }
    /* errors trap */
    if (res==-1) {
      SYS_FLAGS f;
      f=kern_fsave();
      printk(KERN_ERR "tracer task write error!");
      kern_frestore(f);
      for (;;) task_endcycle();
    }
    task_endcycle();
  }
}

static TRACE_PARMS defparms=BASE_TRACE;
static TRACE_PARMS *myparms=&defparms;

static void internal_trc_logevent(PID pid, int event, void *ptr, int size);

int TRC_init_phase1(TRACE_PARMS *inparms)
{
  trc_events *nexttable;

  printk0("tracer init: START phase1");
 
  acttable=allocmemory(sizeof(trc_events));
  if (acttable==NULL) goto ERROR;
  printk0("tracer init: first table created");
  nexttable=allocmemory(sizeof(trc_events));
  if (nexttable==NULL) {
    freememory(acttable);
    acttable=NULL;
    goto ERROR;
  }
  printk0("tracer init: second table created");

  acttable->next=nexttable;
  nexttable->next=acttable;
  actindex=0;
  writable=acttable;
  wriindex=0;
  counter=0;
  hoops=0;
  numtables=2;
  printk0("tracer init: internal variables initialized");
 
  if (inparms!=NULL) myparms=inparms;

  trc_resume();
  printk0("tracer init: END phase 1 (tracer started)");
  return 0;
 
ERROR:
  printk(KERN_ERR "tracer initialization fails!");
  return -1;
}

static void TRC_end(void *dummy);

int TRC_init_phase2(void)
{
  trc_event_t event;
  SOFT_TASK_MODEL model;
  int res;
  PID pid;

  printk0("tracer init: START phase 2");

  /* for safety */
  if (acttable==NULL) return -1;
  printk0("tracer init: safety test passed");

  handle=open(myparms->filename,O_CREAT|O_TRUNC|O_WRONLY);  
  if (handle==-1) goto ERROR;
  printk0("tracer init: file opened");

  event.size=sizeof(trc_event_t);
  event.what=TRC_INITLOG;
  event.x.id=TRC_INITID;
 
  //cprintf("size=====%li\n",sizeof(trc_event_t));
 
  res=write(handle,&event,sizeof(trc_event_t));
  if (res!=sizeof(trc_event_t)) goto ERROR;
  printk0("tracer init: write");
 
  soft_task_default_model(model);
  soft_task_def_system(model);
  soft_task_def_notrace(model);
  soft_task_def_periodic(model);
  soft_task_def_period(model,myparms->period);
  soft_task_def_met(model,myparms->slice);
  soft_task_def_wcet(model,myparms->slice);
 
  pid=task_create("sysTracer",tracer,&model,NULL);
  if (pid==-1) goto ERROR;
  task_activate(pid);
  printk0("tracer init: tracer task created and activated");
 
  //sys_atexit(TRC_end,(void*)handle,BEFORE_EXIT);
  printk0("tracer init: END phase 2");
  printk (KERN_NOTICE "tracer started!");
  return 0;

ERROR:
  kern_cli();
  freememory(acttable->next);
  freememory(acttable);
  acttable=NULL;
  kern_sti();
  if (handle!=-1) close(handle);
  printk(KERN_ERR "tracer initialization fails (%s)!",strerror(errno));
  return -1;
}

static void (*old_logevent)(PID pid, int event, void *ptr, int size)=NULL;
             
int trc_resume(void)
{
  SYS_FLAGS f;
  int ret=-1;
  f=kern_fsave();
  if (acttable!=NULL&&old_logevent==NULL) {  
    old_logevent=trc_logevent;
    trc_logevent=internal_trc_logevent;
    ret=0;
  }
  kern_frestore(f);
  return ret;
}

int trc_suspend(void)
{
  SYS_FLAGS f;
  int ret=-1;
  f=kern_fsave();
  if (acttable!=NULL&&old_logevent!=NULL) {    
    trc_logevent=old_logevent;
    old_logevent=NULL;
    ret=0;
  }
  kern_frestore(f);
  return 0;
}

static void TRC_end(void *dummy)
{
  printk(KERN_INFO "shuting down tracer...");
 
  trc_suspend();
  if (counter>0) {
    /* wait a bit for flushing events queue */
    int x=30;
    while (counter>0) {
      cprintf("<%li>",(long)counter);
      task_delay(100000); // 100msec
      if (x--==0) break;
    }
  }
  close(handle);

  printk(KERN_DEBUG "tracer hoops:     %5i",hoops);
  printk(KERN_DEBUG "tracer numtables: %5i",numtables);  
}

static trc_event_t *getrecord(void)
{
  trc_events  *newtable;
  trc_event_t *event;
  event=&acttable->event[actindex];
  actindex++;
  if (actindex==TRC_BLOCKSIZE) {
    actindex=0;    
    if (acttable->next==writable) {
      if (numtables==TRC_MAXNUMTABLES) {
        hoops++;
        actindex=TRC_BLOCKSIZE-1;
        return NULL;
      }
      newtable=allocmemory(sizeof(trc_events));
      if (newtable==NULL) {
        hoops++;
        actindex=TRC_BLOCKSIZE-1;
        return NULL;
      }
      newtable->next=acttable->next;
      acttable->next=newtable;
      acttable=newtable;
      numtables++;
    }
    else acttable=acttable->next;    
  }
  return event;
}

static void internal_trc_logevent(int event, PID pid, void *ptr, int size)
{
  SYS_FLAGS f;
  trc_event_t *evt;

  if (acttable==NULL) return;
 
  f=kern_fsave();
  evt=getrecord();  
  if (evt!=NULL) {

    evt->size=sizeof(trc_event_t);
    evt->what=event;
    if ((event&0xff00)==(TRC_USR_EVENTS<<8)) {
          evt->x.user.when=ll_gettime(TIME_EXACT,NULL);
          evt->x.user.who=(pid==TRC_NOPID?exec_shadow:pid);
          if (ptr!=NULL) memcpy(&evt->x.user.info,ptr,TRC_MAXUSERINFO);  
    } else
      switch (event) {
        case TRC_TASKNAME:
          evt->x.tskname.who=pid;
          memcpy(&evt->x.tskname.name,ptr,TRC_MAXNAMESIZE);
          break;
        case TRC_SCHEDULE:
          evt->x.sched.when=ll_gettime(TIME_EXACT,NULL);
          memcpy(&evt->x.sched.info,ptr,sizeof(trc_schedule_t));
          break;
        default:
          evt->x.norm.when=ll_gettime(TIME_EXACT,NULL);
          evt->x.norm.who=pid;
          break;
      }
   
    counter++;
  }
  kern_frestore(f);
 
  return;
}