- inserted command statistic

- add runscript parameter to environment object
- added Arg2Tcl0 function
This commit is contained in:
zolliker
2006-06-20 13:28:17 +00:00
parent bd533e6131
commit f88f48fca9
15 changed files with 334 additions and 32 deletions

View File

@ -57,6 +57,7 @@
#include <assert.h>
#include <string.h>
#include <tcl.h>
#include <time.h>
#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,15 +453,25 @@ 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 != NULL)
{
tail = pCurrent;
pCurrent = pCurrent->pNext;
}
/* delete Commandlist (reversed order) */
if (tail) {
pCurrent = tail;
while(pCurrent)
{
if(pCurrent->KFunc)
@ -464,10 +483,11 @@ extern char *SkipSpace(char *pPtr);
/* printf("Deleting %s\n",pCurrent->pName); */
free(pCurrent->pName);
}
pTemp = pCurrent->pNext;
pTemp = pCurrent->pPrevious;
free(pCurrent);
pCurrent = pTemp;
}
}
FreeAliasList(&self->AList); /* M.Z. */

View File

@ -10,6 +10,7 @@
#ifndef SICSINTERPRETER
#define SICSINTERPRETER
#include "Scommon.h"
#include "statistics.h"
#include <tcl.h>
/* 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

View File

@ -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);
}
/*--------------------------------------------------------------------------*/
@ -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");
}

View File

@ -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.

View File

@ -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.

View File

@ -132,6 +132,7 @@
char *lastCommand = NULL, comBuffer[132];
int iRet = 0,i;
int iMacro;
Statistics *old;
/* get the datastructures */
pSics = (struct __SicsUnknown *)pData;
@ -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;

View File

@ -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

1
ofac.c
View File

@ -410,6 +410,7 @@
/* insert here initialization routines ... */
INIT(SiteInit); /* site specific initializations */
INIT(StatisticsInit);
}
/*--------------------------------------------------------------------------*/

View File

@ -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);

View File

@ -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;
if (prepend) {
prependlen = strlen(prepend);
l = prependlen + 1;
} else {
prependlen = 0;
l = 0;
}
firstArgToQuote = argc;
quote = 0;
for (i=0; i<argc; i++) {
@ -443,6 +449,11 @@ char *Arg2Tcl(int argc, char *argv[], char *buffer, int buffersize) {
if (buffer == NULL) return NULL;
}
res = buffer;
if (prepend) {
strcpy(res, prepend);
res += prependlen;
*res++ = ' ';
}
for (i=0; i<argc; i++) {
if (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

View File

@ -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

149
statistics.c Normal file
View File

@ -0,0 +1,149 @@
#include <sics.h>
#include <sys/time.h>
#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(&current->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("<idle>");
current = idle;
}
}

36
statistics.h Normal file
View File

@ -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

View File

@ -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);

View File

@ -120,6 +120,7 @@
{
deleteCircular(self->pTail);
}
free(self); /* M.Z. */
return 1;
}
/*--------------------------------------------------------------------------*/