alpha_trace.c 4.25 KB
/*
 * Copyright (C) 1998 by the Board of Trustees
 *    of Leland Stanford Junior University.
 * Copyright (C) 1998 Digital Equipment Corporation
 *
 * This file is part of the SimOS distribution.
 * See LICENSE file for terms of the license.
 *
 */

/*****************************************************************
 * 
 * trace.c 
 * 
 * 
 ****************************************************************/

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

#include "sim_error.h"
#include "machine_params.h"
#include "simtypes.h"
#include "tcl_init.h"

#include "alpha.h"
#include "alpha_trace.h"


struct TracingState trace;


/*****************************************************************
 * TraceInit
 *****************************************************************/
static void TraceInit(void)
{   
   int i; 
   if (trace.active) return;

   CPUWarning("\nInitializing ALPHA tracing... \n");

   trace.active = 1;
   trace.fd = open("trace.out",O_WRONLY|O_CREAT,0644);

   ASSERT(trace.fd>0);
   for (i=0; i< TOTAL_CPUS; i++) {
      trace.cpuMask[i] = 0;
   }
   trace.buffer    = malloc(TRACE_BUFFER_SIZE*sizeof(uint64));
   trace.bufferPtr = &trace.buffer[0];
   trace.bufferEnd = trace.bufferPtr + TRACE_BUFFER_SIZE;

   ASSERT(TOTAL_CPUS < 1<<(56-52));
   ASSERT(VA_BITS < 50);


}

void TraceDump(void) 
{
   int len;
   int chk;
   ASSERT (trace.active);
   len = (trace.bufferPtr-trace.buffer)*sizeof(uint64);
   while(1) { 
      chk = write(trace.fd,trace.buffer,len);
      if (chk==-1 && errno==EINTR) {
	 CPUWarning("alpha_trace::TraceDump. system call interrupted. Retry \n");
	 continue;
      }
      ASSERT(chk==len);
      break;
   }

   trace.bufferPtr = &trace.buffer[0];
}


void TraceLog(char *string)
{
   uint64 empty=0;
   uint64 code = TRACE_FORMAT(TRACE_ASCII,0,0);
   size_t len = strlen(string);
   int chk;

   TraceInit();
   TraceDump();
   write(trace.fd,(char*)&code,sizeof(uint64));
   if (len) {
      while(1) { 
  	 chk = write(trace.fd,string,len);
	 if (chk==-1 && errno==EINTR) {
	 CPUWarning("alpha_trace::TraceLog. system call interrupted. Retry \n");
	 continue;
      }
	 ASSERT(chk==len);
      break;
      }
   } 
   len = len & 7;  
   write(trace.fd,(char*)&empty,8-len);
}
     
   

static int 
TraceTclCmd(ClientData clientData, Tcl_Interp *interp, 
                int argc, char *argv[])
{

#ifndef TRACING
   Tcl_AppendResult(interp, 
                    "traceDump not supported unless compiled -DTRACING",
                    NULL);
   return TCL_ERROR;
#else

   int i;
   TraceInit();

   if (argc < 2) {
      Tcl_AppendResult(interp, 
                       "Usage: traceDump <log|all|off|list of cpunumbers>", 
                       NULL);
      return TCL_ERROR;
   }

   if (!strcmp(argv[1], "off")) {
      CPUWarning("traceDump: Turning trace dumping OFF\n");
      for (i = 0; i < SIM_MAXCPUS; i++) {
         trace.cpuMask[i] = 0;
      }
      return TCL_OK;
   }
   if (!strcmp(argv[1], "all")) {
      CPUWarning("traceDump: Turning trace dumping on for ALL cpus\n");
      for (i = 0; i < SIM_MAXCPUS; i++) {
         trace.cpuMask[i] = 1;
      }
      return TCL_OK;
   } 

   if (!strcmp(argv[1],"log")) {
      if (argc !=3) {
         Tcl_AppendResult(interp,"'traceDump log string'. Wrong number of arguments \n",NULL);
         return TCL_ERROR;
      }
      TraceLog(argv[2]);
      return TCL_OK;
   }

   if (!strcmp(argv[1],"dump")) {
      if (argc !=2) {
         Tcl_AppendResult(interp,"'traceDump'. Wrong number of arguments \n",NULL);
         return TCL_ERROR;
      }
      TraceDump();
      return TCL_OK;
   }

   for (i=1; i<argc; i++) {
      int cpuNum;
      if ((Tcl_GetInt(interp, argv[i], &cpuNum) != TCL_OK)
          || cpuNum >= SIM_MAXCPUS ) {
         Tcl_AppendResult(interp, "Bad cpu num to traceDump command",
                          NULL);
         return TCL_ERROR;
      }
      trace.cpuMask[cpuNum] = 1;
      CPUWarning("traceDump: Enabling trace dumping for cpu %d\n", cpuNum);
      TraceLog("StartingTrace");
   }

   return TCL_OK;
#endif
}



void
AlphaTraceTclInit(Tcl_Interp *interp)
{
   int i;
   ASSERT(interp);
   Tcl_CreateCommand(interp, "alphaTrace", TraceTclCmd,
                     (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
}