diff --git a/SCinter.c b/SCinter.c index 193b2055..52d10f11 100644 --- a/SCinter.c +++ b/SCinter.c @@ -57,6 +57,7 @@ #include #include #include +#include #include "fortify.h" #include "sics.h" #include "splitter.h" @@ -151,6 +152,7 @@ static void freeList(int listID); pNew->pData = pData; pNew->pNext = NULL; pNew->startupOnly = startupOnly; + pNew->stat = StatisticsNew(pBueffel); /* find end of list */ tail = NULL; @@ -232,10 +234,14 @@ static void freeList(int listID); { pInterp->pCList = pVictim->pNext; } + if (pVictim->stat) { + StatisticsKill(pVictim->stat); + } free(pVictim); return 1; } + #define MAXLEN 256 #define MAXCOM 50 extern char *stptok(char *s, char *tok, unsigned int toklen, char *brk); @@ -252,6 +258,7 @@ extern char *SkipSpace(char *pPtr); char *pPtr; char **argv = NULL; commandContext comCon; + Statistics *old; assert(self); @@ -307,7 +314,9 @@ extern char *SkipSpace(char *pPtr); Tcl_ResetResult((Tcl_Interp *)self->pTcl); MacroPush(pCon); pCon->conStatus = 0; + old = StatisticsBegin(pCommand->stat); iRet = pCommand->OFunc(pCon, self, pCommand->pData, argc, argv); + StatisticsEnd(old); /* If a task is registered with the dev exec then conStatus is HWBusy*/ if (pCon->conStatus != HWBusy) { comCon = SCGetContext(pCon); @@ -444,29 +453,40 @@ extern char *SkipSpace(char *pPtr); void DeleteInterp(SicsInterp *self) { CommandList *pCurrent = NULL; - CommandList *pTemp; + CommandList *pTemp, *tail; Tcl_Interp *pTcl = NULL; int i; assert(self); self->iDeleting = 1; - /* delete Commandlist */ + /* find end of list */ + tail = NULL; pCurrent = self->pCList; - while(pCurrent) + while(pCurrent != NULL) { - if(pCurrent->KFunc) + tail = pCurrent; + pCurrent = pCurrent->pNext; + } + + /* delete Commandlist (reversed order) */ + if (tail) { + pCurrent = tail; + while(pCurrent) { - pCurrent->KFunc(pCurrent->pData); + if(pCurrent->KFunc) + { + pCurrent->KFunc(pCurrent->pData); + } + if(pCurrent->pName) + { + /* printf("Deleting %s\n",pCurrent->pName); */ + free(pCurrent->pName); + } + pTemp = pCurrent->pPrevious; + free(pCurrent); + pCurrent = pTemp; } - if(pCurrent->pName) - { - /* printf("Deleting %s\n",pCurrent->pName); */ - free(pCurrent->pName); - } - pTemp = pCurrent->pNext; - free(pCurrent); - pCurrent = pTemp; } FreeAliasList(&self->AList); /* M.Z. */ diff --git a/SCinter.h b/SCinter.h index dacaf28d..9bb8c3ff 100644 --- a/SCinter.h +++ b/SCinter.h @@ -10,6 +10,7 @@ #ifndef SICSINTERPRETER #define SICSINTERPRETER #include "Scommon.h" +#include "statistics.h" #include /* M.Z. */ #include "definealias.i" @@ -31,6 +32,7 @@ typedef struct __Clist { struct __Clist *pNext; struct __Clist *pPrevious; int startupOnly; + Statistics *stat; } CommandList; typedef struct __SINTER diff --git a/evcontroller.c b/evcontroller.c index 991dcde4..69aea67a 100644 --- a/evcontroller.c +++ b/evcontroller.c @@ -71,13 +71,29 @@ static long EVIDrive(void *pData, SConnection *pCon, float fVal) { pEVControl self = NULL; - int iRet, iCode, i, iFix; + int iRet, iCode, i, iFix, savedStatus; char pError[132], pBueffel[256]; - + Tcl_Interp *pTcl = NULL; + self = (pEVControl)pData; assert(self); assert(pCon); + if (self->runScript != NULL) { + savedStatus = GetStatus(); + SetStatus(eBatch); + pTcl = InterpGetTcl(pServ->pSics); + snprintf(pBueffel, sizeof(pBueffel), "%s %f", self->runScript, fVal); + iRet = Tcl_Eval(pTcl,pBueffel); + SetStatus(savedStatus); + if(iRet != TCL_OK) + { + SCPrintf(pCon, eError, + "ERROR: %s while processing runscript for %s", + pTcl->result,self->pName); + } + } + self->fTarget = fVal; self->eMode = EVDrive; self->iStop = 0; @@ -848,6 +864,10 @@ static void ErrReport(pEVControl self) { free(self->creationArgs); } + if (self->runScript != NULL) + { + free(self->runScript); + } free(self); } /*--------------------------------------------------------------------------*/ @@ -855,7 +875,7 @@ static void ErrReport(pEVControl self) { char pBueffel[256], pError[132]; int iRet; - + assert(self); assert(pCon); @@ -1025,7 +1045,14 @@ static void ErrReport(pEVControl self) snprintf(pBueffel,255,"%s.errorScript = UNDEFINED", self->pName); } SCWrite(pCon,pBueffel, eValue); - + if(self->runScript != NULL) + { + SCPrintf(pCon, eValue, "%s.runScript = %s", self->pName, self->runScript); + } + else + { + SCPrintf(pCon, eValue, "%s.runScript = none", self->pName); + } return 1; } /*-------------------------------------------------------------------------*/ @@ -1161,10 +1188,10 @@ static void ErrReport(pEVControl self) } else /* parameter request */ { + strtolower(argv[1]); /* catch case of errorScript */ - strtolower(argv[1]); if(strcmp(argv[1],"errorscript") == 0) { if(self->errorScript != NULL) @@ -1180,6 +1207,22 @@ static void ErrReport(pEVControl self) SCWrite(pCon,pBueffel,eValue); return 1; } + /* + catch case of runScript + */ + if(strcmp(argv[1],"runscript") == 0) + { + if(self->runScript != NULL) + { + SCPrintf(pCon, eValue,"%s.runScript = %s",self->pName, + self->runScript); + } + else + { + SCPrintf(pCon, eValue,"%s.runScript = none",self->pName); + } + return 1; + } /* catch case for drivername */ @@ -1208,10 +1251,10 @@ static void ErrReport(pEVControl self) } else /* try to set parameter */ { + strtolower(argv[1]); /* first catch case of errorScript */ - strtolower(argv[1]); if(strcmp(argv[1],"errorscript") == 0) { if(self->errorScript != NULL) @@ -1223,6 +1266,24 @@ static void ErrReport(pEVControl self) SCparChange(pCon); return 1; } + /* + catch case of runScript + */ + if(strcmp(argv[1],"runscript") == 0) + { + if(self->runScript != NULL) + { + free(self->runScript); + } + if (strcasecmp(argv[2],"none") == 0) { + self->runScript = NULL; + } else { + self->runScript = Arg2Tcl(argc-2,&argv[2],NULL,0); + } + SCSendOK(pCon); + SCparChange(pCon); + return 1; + } iRet = Tcl_GetDouble(pSics->pTcl,argv[2],&dVal); if(iRet != TCL_OK) { @@ -1263,6 +1324,9 @@ static int EVSaveStatus(void *pData, char *name, FILE *fil) if(evc->errorScript != NULL) { fprintf(fil, " %s errorScript %s\n", evc->pName, evc->errorScript); } + if(evc->runScript != NULL) { + fprintf(fil, " %s runScript %s\n", evc->pName, evc->runScript); + } } fprintf(fil, "}\n"); } diff --git a/evcontroller.tex b/evcontroller.tex index 06900005..3514e5c8 100644 --- a/evcontroller.tex +++ b/evcontroller.tex @@ -54,6 +54,7 @@ $\langle$evdata {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ int iStop;@\\ \mbox{}\verb@ SCStore conn;@\\ \mbox{}\verb@ char *creationArgs;@\\ +\mbox{}\verb@ char *runScript;@\\ \mbox{}\verb@ void *pPrivate;@\\ \mbox{}\verb@ void (*KillPrivate)(void *pData);@\\ \mbox{}\verb@ } EVControl;@\\ @@ -88,6 +89,10 @@ holding the logging information. Then there is a switch, iWarned, which is used to prevent execessive output on environment controller error handling. iTcl is a boolean stating if the driver used is a proper C language driver or a Tcl driver. + creationArgs are the arguments needed to recreate the device. runScript +is a script called on every run or drive command. This script is intended +to set control parameters depending on the targetValue. The script is +called with the target temperature as argument. This is followed by the void pointer for use by a derived class. KillPrivate is a pointer to a function capable of deleting pPrivate properly. diff --git a/evcontroller.w b/evcontroller.w index ee8304b1..e9e4aeb6 100644 --- a/evcontroller.w +++ b/evcontroller.w @@ -49,6 +49,7 @@ used by EVControl: int iStop; SCStore conn; char *creationArgs; + char *runScript; void *pPrivate; void (*KillPrivate)(void *pData); } EVControl; @@ -76,6 +77,10 @@ holding the logging information. Then there is a switch, iWarned, which is used to prevent execessive output on environment controller error handling. iTcl is a boolean stating if the driver used is a proper C language driver or a Tcl driver. + creationArgs are the arguments needed to recreate the device. runScript +is a script called on every run or drive command. This script is intended +to set control parameters depending on the targetValue. The script is +called with the target temperature as argument. This is followed by the void pointer for use by a derived class. KillPrivate is a pointer to a function capable of deleting pPrivate properly. diff --git a/macro.c b/macro.c index 216156e3..c2d5134d 100644 --- a/macro.c +++ b/macro.c @@ -132,7 +132,8 @@ char *lastCommand = NULL, comBuffer[132]; int iRet = 0,i; int iMacro; - + Statistics *old; + /* get the datastructures */ pSics = (struct __SicsUnknown *)pData; assert(pSics); @@ -181,7 +182,9 @@ /* invoke */ iMacro = SCinMacro(pCon); SCsetMacro(pCon,1); + old=StatisticsBegin(pCommand->stat); iRet = pCommand->OFunc(pCon,pSinter,pCommand->pData,margc, myarg); + StatisticsEnd(old); SCsetMacro(pCon,iMacro); /* lastUnkown gets deeply stacked with each SICS command exec'd. @@ -881,7 +884,7 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp, } /* make a string */ - pCommand = Arg2Tcl(argc,argv,pBueffel,sizeof(pBueffel)); + pCommand = Arg2Tcl0(argc-1,argv+1,pBueffel,sizeof(pBueffel),self->command); if (!pCommand) { SCWrite(pCon, "ERROR: no more memory", eError); return 0; diff --git a/make_gen b/make_gen index 865d8930..f31d9607 100644 --- a/make_gen +++ b/make_gen @@ -30,7 +30,7 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \ s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) mcreader.o mccontrol.o\ hmdata.o nxscript.o tclintimpl.o sicsdata.o mcstascounter.o \ mcstashm.o initializer.o remob.o tclmotdriv.o protocol.o \ - sinfox.o sicslist.o cone.o + sinfox.o sicslist.o cone.o statistics.o MOTOROBJ = motor.o simdriv.o COUNTEROBJ = countdriv.o simcter.o counter.o diff --git a/ofac.c b/ofac.c index 56d827fa..b09ae2f4 100644 --- a/ofac.c +++ b/ofac.c @@ -410,6 +410,7 @@ /* insert here initialization routines ... */ INIT(SiteInit); /* site specific initializations */ + INIT(StatisticsInit); } /*--------------------------------------------------------------------------*/ diff --git a/remob.c b/remob.c index fca5591e..12dc5187 100644 --- a/remob.c +++ b/remob.c @@ -534,7 +534,6 @@ int RemobAction(SConnection *pCon, SicsInterp *pSics, void *pData, float fValue; long lID; char *endp; - char *argv0; char *cmd; /* char acce[128], inte[128]; @@ -559,10 +558,7 @@ int RemobAction(SConnection *pCon, SicsInterp *pSics, void *pData, snprintf(inte, sizeof(inte), "!%s.interruptmode", remob->name); */ - argv0 = argv[0]; - argv[0] = remob->name; - cmd = Arg2Tcl(argc, argv, buf, sizeof buf); - argv[0] = argv0; + cmd = Arg2Tcl0(argc-1, argv+1, buf, sizeof buf, remob->name); if (cmd) { RemTransact(remserver, rc, pCon, cmd, ">", NULL); if (cmd != buf) free(cmd); diff --git a/splitter.c b/splitter.c index 7d67de02..13f97702 100644 --- a/splitter.c +++ b/splitter.c @@ -400,12 +400,18 @@ typedef enum _CharType {eSpace, eNum,eeText,eQuote} CharType; return 1; } /*--------------------------------------------------------------------------*/ -char *Arg2Tcl(int argc, char *argv[], char *buffer, int buffersize) { - int i, l, firstArgToQuote, quote; +char *Arg2Tcl0(int argc, char *argv[], char *buffer, int buffersize, char *prepend) { + int i, l, firstArgToQuote, quote, prependlen; char ch; char *res, *arg; - l = 0; + if (prepend) { + prependlen = strlen(prepend); + l = prependlen + 1; + } else { + prependlen = 0; + l = 0; + } firstArgToQuote = argc; quote = 0; for (i=0; i= firstArgToQuote) *res++ = '"'; arg = argv[i]; @@ -464,6 +475,10 @@ char *Arg2Tcl(int argc, char *argv[], char *buffer, int buffersize) { *res='\0'; return buffer; } +/*--------------------------------------------------------------------------*/ +char *Arg2Tcl(int argc, char *argv[], char *buffer, int buffersize) { + return Arg2Tcl0(argc, argv, buffer, buffersize, NULL); +} /*============================================================================ Testprogram, can be activated by defining MAIN diff --git a/splitter.h b/splitter.h index a5e6fbbf..2dfb3448 100644 --- a/splitter.h +++ b/splitter.h @@ -87,5 +87,10 @@ typedef struct _TokenEntry { if (result != NULL && result != buffer) free(result); !*/ - + char *Arg2Tcl0(int argc, char *argv[], char *buffer, int buffersize, char *prepend); + /*! + This function is added for convenience, and acts similar to Arg2Tcl. + If prepend is not NULL, its contents appear untreated before the args. + A space is used as separator. + !*/ #endif diff --git a/statistics.c b/statistics.c new file mode 100644 index 00000000..504a531d --- /dev/null +++ b/statistics.c @@ -0,0 +1,149 @@ +#include +#include +#include "statistics.h" + +typedef struct timeval tv_t; + +struct Statistics { + tv_t tim; + long cnt; + char *name; + Statistics *next; +}; + +static Statistics *current; +static tv_t last, lastStat; +static Statistics *idle = NULL, *list; +static int init = 1; +/*-----------------------------------------------------------------------*/ +tv_t timeDif(tv_t t1, tv_t t2) { + tv_t result; + + result.tv_usec = t2.tv_usec - t1.tv_usec; + result.tv_sec = t2.tv_sec - t1.tv_sec; + if (result.tv_usec < 0) { + result.tv_usec += 1000000; + result.tv_sec --; + } + if (result.tv_sec < 0) { + result.tv_sec += 24*3600; + } + return result; +} +/*-----------------------------------------------------------------------*/ +void timeAdd(tv_t *t1, tv_t t2) { + t1->tv_usec += t2.tv_usec; + t1->tv_sec += t2.tv_sec + (t1->tv_usec / 1000000); + t1->tv_usec %= 1000000; +} +/*-----------------------------------------------------------------------*/ +double timeFloat(tv_t t) { + return t.tv_sec + 1e-6 * t.tv_usec; +} +/*-----------------------------------------------------------------------*/ +int StatisticsCommand(SConnection *con, SicsInterp *pSics, void *pData, + int argc, char *argv[]) { + Statistics *p; + tv_t now; + double dif, percent, dt; + + gettimeofday(&now, 0); + dif = timeFloat(timeDif(lastStat, now)); + SCPrintf(con, eStatus, " calls time[%] mean[ms] command"); + SCPrintf(con, eStatus, "--------------------------------------"); + for (p = list; p != NULL; p = p->next) { + if (dif > 0) { + percent = timeFloat(p->tim) * 100 / dif; + if (percent > 0) { + if (p->cnt > 0) { + dt = timeFloat(p->tim) * 1000.0 / p->cnt; + } else { + dt = 0; + } + SCPrintf(con, eStatus, "%7ld %7.1f %8.2f %s", p->cnt, + percent, dt, p->name); + } + } + p->cnt = 0; + p->tim.tv_sec = 0; + p->tim.tv_usec = 0; + } + lastStat = now; + return 1; +} +/*-----------------------------------------------------------------------*/ +Statistics *StatisticsNew(char *name) { + Statistics *new; + + if (init) { + gettimeofday(&lastStat, 0); + last = lastStat; + init = 0; + } + new = calloc(1,sizeof(*new)); + if (new) { + new->cnt = 0; + new->tim.tv_sec = 0; + new->tim.tv_usec = 0; + new->next = list; + new->name = strdup(name); + list = new; + } + return new; +} +/*-----------------------------------------------------------------------*/ +void StatisticsKill(Statistics *stat) { + Statistics *p, **last; + + /* find in list */ + last = &list; + for (p = list; p != NULL && p != stat; p = p->next) { + last = &p->next; + } + + /* remove from list */ + if (p == stat) { + *last = p->next; + } + + /* kill it */ + if (stat->name) { + free(stat->name); + stat->name = NULL; + } + free(stat); +} +/*-----------------------------------------------------------------------*/ +static void StatisticsSet(Statistics *stat) { + tv_t now; + + if (stat != NULL) { + gettimeofday(&now, 0); + timeAdd(¤t->tim, timeDif(last, now)); + last = now; + } + current = stat; +} +/*-----------------------------------------------------------------------*/ +Statistics *StatisticsBegin(Statistics *stat) { + Statistics *res; + + res = current; + StatisticsSet(stat); + current->cnt ++; + return res; +} +/*-----------------------------------------------------------------------*/ +void StatisticsEnd(Statistics *stat) { + StatisticsSet(stat); +} +/*-----------------------------------------------------------------------*/ +void StatisticsInit(void) { + if (idle == NULL) { + AddCmd("statistics", StatisticsCommand); + last = lastStat; + idle = StatisticsNew(""); + current = idle; + } +} + diff --git a/statistics.h b/statistics.h new file mode 100644 index 00000000..b3d5b599 --- /dev/null +++ b/statistics.h @@ -0,0 +1,36 @@ +/* statistics.h + + statistics on the time spend for commands/tasks + +*/ + +#ifndef STATISTICS_H +#define STATISTICS_H + +typedef struct Statistics Statistics; + +Statistics *StatisticsNew(char *name); +/* create a new Statistics item */ + +void StatisticsKill(Statistics *s); +/* kill item */ + +Statistics *StatisticsBegin(Statistics *s); +void StatisticsEnd(Statistics *s); +/* + Switch statistics to item s. + + Typical usage: + + old = StatisticsBegin(thisItem); + + ...do work related with thisItem... + + StatisticsEnd(old); +*/ + +void StatisticsInit(void); + +/* initialize module and activate statistics command */ + +#endif diff --git a/tclintimpl.c b/tclintimpl.c index f64bf7b1..ec3b16f5 100644 --- a/tclintimpl.c +++ b/tclintimpl.c @@ -162,7 +162,7 @@ int TclIntAction(SConnection *pCon, SicsInterp *pSics, void *pData, cmd = Arg2Tcl(argc-2, &argv[2],pBuffer,1023); if (cmd) { if(self->fd != NULL){ - fprintf(self->fd,"%s\n",pBuffer); + fprintf(self->fd,"%s\n",cmd); } if (cmd != pBuffer) free(cmd); SCSendOK(pCon); diff --git a/varlog.c b/varlog.c index 16b5cd22..806821d6 100644 --- a/varlog.c +++ b/varlog.c @@ -120,6 +120,7 @@ { deleteCircular(self->pTail); } + free(self); /* M.Z. */ return 1; } /*--------------------------------------------------------------------------*/