diff --git a/devIocStats/devIocStats.h b/devIocStats/devIocStats.h index 1d1b85c..1a76ef8 100644 --- a/devIocStats/devIocStats.h +++ b/devIocStats/devIocStats.h @@ -38,8 +38,9 @@ #define LOAD_TYPE 1 #define FD_TYPE 2 #define CA_TYPE 3 -#define STATIC_TYPE 4 -#define TOTAL_TYPES 5 +#define QUEUE_TYPE 4 +#define STATIC_TYPE 5 +#define TOTAL_TYPES 6 /* Names of environment variables (may be redefined in OSD include) */ #define STARTUP "STARTUP" diff --git a/devIocStats/devIocStatsAnalog.c b/devIocStats/devIocStatsAnalog.c index f668d1d..543edef 100644 --- a/devIocStats/devIocStatsAnalog.c +++ b/devIocStats/devIocStatsAnalog.c @@ -112,6 +112,7 @@ #include #include #include +#include #include #include @@ -124,9 +125,12 @@ #include #include #include +#include #include "devIocStats.h" +#define BASE_HAS_QUEUE_STATUS (EPICS_VERSION_INT == VERSION_INT(3, 16, 2, 0)) || (EPICS_VERSION_INT >= VERSION_INT(7, 0, 2, 0)) + struct aStats { long number; @@ -213,6 +217,20 @@ static void statsIFOErrs(double *); static void statsRecords(double *); static void statsPID(double *); static void statsPPID(double *); +static void statsScanOnceQHiWtrMrk(double*); +static void statsScanOnceQUsed(double*); +static void statsScanOnceQSize(double*); +static void statsScanOnceQOverruns(double*); +static void statsCbQSize(double*); +static void statsCbLowQHiWtrMrk(double*); +static void statsCbLowQUsed(double*); +static void statsCbLowQOverruns(double*); +static void statsCbMediumQHiWtrMrk(double*); +static void statsCbMediumQUsed(double*); +static void statsCbMediumQOverruns(double*); +static void statsCbHighQHiWtrMrk(double*); +static void statsCbHighQUsed(double*); +static void statsCbHighQOverruns(double*); struct { char *name; @@ -222,6 +240,7 @@ struct { { "cpu_scan_rate", 20.0 }, { "fd_scan_rate", 10.0 }, { "ca_scan_rate", 15.0 }, + { "queue_scan_rate", 1.0 }, { NULL, 0.0 }, }; @@ -253,6 +272,20 @@ static validGetParms statsGetParms[]={ { "records", statsRecords, STATIC_TYPE }, { "proc_id", statsPID, STATIC_TYPE }, { "parent_proc_id", statsPPID, STATIC_TYPE }, + { "scanOnceQueueHiWtrMrk", statsScanOnceQHiWtrMrk, QUEUE_TYPE }, + { "scanOnceQueueUsed", statsScanOnceQUsed, QUEUE_TYPE }, + { "scanOnceQueueSize", statsScanOnceQSize, STATIC_TYPE }, + { "scanOnceQueueOverruns", statsScanOnceQOverruns, QUEUE_TYPE }, + { "cbQueueSize", statsCbQSize, STATIC_TYPE }, + { "cbLowQueueHiWtrMrk", statsCbLowQHiWtrMrk, QUEUE_TYPE }, + { "cbLowQueueUsed", statsCbLowQUsed, QUEUE_TYPE }, + { "cbLowQueueOverruns", statsCbLowQOverruns, QUEUE_TYPE }, + { "cbMediumQueueHiWtrMrk", statsCbMediumQHiWtrMrk, QUEUE_TYPE }, + { "cbMediumQueueUsed", statsCbMediumQUsed, QUEUE_TYPE }, + { "cbMediumQueueOverruns", statsCbMediumQOverruns, QUEUE_TYPE }, + { "cbHighQueueHiWtrMrk", statsCbHighQHiWtrMrk, QUEUE_TYPE }, + { "cbHighQueueUsed", statsCbHighQUsed, QUEUE_TYPE }, + { "cbHighQueueOverruns", statsCbHighQOverruns, QUEUE_TYPE }, { NULL,NULL,0 } }; @@ -265,6 +298,11 @@ epicsExportAddress(dset,devAiClusts); static memInfo meminfo = {0.0,0.0,0.0,0.0,0.0,0.0}; static memInfo workspaceinfo = {0.0,0.0,0.0,0.0,0.0,0.0}; +#if BASE_HAS_QUEUE_STATUS +static scanOnceQueueStats scanOnceQStatus; +static callbackQueueStats callbackQStatus; +#endif +static int queueDataInitialized; static scanInfo scan[TOTAL_TYPES] = {{0}}; static fdInfo fdusage = {0,0}; static loadInfo loadinfo = {1,0.,0.}; @@ -310,6 +348,14 @@ static void notifyOnCaServInit(initHookState state) } } +static void getQueueData() { + #if BASE_HAS_QUEUE_STATUS + scanOnceQueueStatus(0, &scanOnceQStatus); + callbackQueueStatus(0, &callbackQStatus); + #endif + queueDataInitialized = 1; +} + static void scan_time(int type) { switch(type) { @@ -374,6 +420,13 @@ static void scan_time(int type) epicsMutexUnlock(scan_mutex); break; } + case QUEUE_TYPE: + { + epicsMutexLock(scan_mutex); + getQueueData(); + epicsMutexUnlock(scan_mutex); + break; + } default: break; } @@ -756,3 +809,134 @@ static void statsPPID(double *val) *val = 0; devIocStatsGetPPID(val); } + +static void statsScanOnceQHiWtrMrk(double *val) +{ +#if BASE_HAS_QUEUE_STATUS + if(!queueDataInitialized) getQueueData(); + *val = scanOnceQStatus.maxUsed; +#else + *val = 0; +#endif +} +static void statsScanOnceQUsed(double *val) +{ +#if BASE_HAS_QUEUE_STATUS + if(!queueDataInitialized) getQueueData(); + *val = scanOnceQStatus.numUsed; +#else + *val = 0; +#endif +} +static void statsScanOnceQSize(double *val) +{ +#if BASE_HAS_QUEUE_STATUS + if(!queueDataInitialized) getQueueData(); + *val = scanOnceQStatus.size; +#else + *val = 0; +#endif +} +static void statsScanOnceQOverruns(double *val) +{ +#if BASE_HAS_QUEUE_STATUS + if(!queueDataInitialized) getQueueData(); + *val = scanOnceQStatus.numOverflow; +#else + *val = 0; +#endif +} + +static void statsCbQSize(double *val) +{ +#if BASE_HAS_QUEUE_STATUS + if(!queueDataInitialized) getQueueData(); + *val = callbackQStatus.size; +#else + *val = 0; +#endif +} + +static void statsCbLowQHiWtrMrk(double *val) +{ +#if BASE_HAS_QUEUE_STATUS + if(!queueDataInitialized) getQueueData(); + *val = callbackQStatus.maxUsed[priorityLow]; +#else + *val = 0; +#endif +} +static void statsCbLowQUsed(double *val) +{ +#if BASE_HAS_QUEUE_STATUS + if(!queueDataInitialized) getQueueData(); + *val = callbackQStatus.numUsed[priorityLow]; +#else + *val = 0; +#endif +} +static void statsCbLowQOverruns(double *val) +{ +#if BASE_HAS_QUEUE_STATUS + if(!queueDataInitialized) getQueueData(); + *val = callbackQStatus.numOverflow[priorityLow]; +#else + *val = 0; +#endif +} + +static void statsCbMediumQHiWtrMrk(double *val) +{ +#if BASE_HAS_QUEUE_STATUS + if(!queueDataInitialized) getQueueData(); + *val = callbackQStatus.maxUsed[priorityMedium]; +#else + *val = 0; +#endif +} +static void statsCbMediumQUsed(double *val) +{ +#if BASE_HAS_QUEUE_STATUS + if(!queueDataInitialized) getQueueData(); + *val = callbackQStatus.numUsed[priorityMedium]; +#else + *val = 0; +#endif +} +static void statsCbMediumQOverruns(double *val) +{ +#if BASE_HAS_QUEUE_STATUS + if(!queueDataInitialized) getQueueData(); + *val = callbackQStatus.numOverflow[priorityMedium]; +#else + *val = 0; +#endif +} + +static void statsCbHighQHiWtrMrk(double *val) +{ +#if BASE_HAS_QUEUE_STATUS + if(!queueDataInitialized) getQueueData(); + *val = callbackQStatus.maxUsed[priorityHigh]; +#else + *val = 0; +#endif +} +static void statsCbHighQUsed(double *val) +{ +#if BASE_HAS_QUEUE_STATUS + if(!queueDataInitialized) getQueueData(); + *val = callbackQStatus.numUsed[priorityHigh]; +#else + *val = 0; +#endif +} +static void statsCbHighQOverruns(double *val) +{ +#if BASE_HAS_QUEUE_STATUS + if(!queueDataInitialized) getQueueData(); + *val = callbackQStatus.numOverflow[priorityHigh]; +#else + *val = 0; +#endif +} diff --git a/iocAdmin/Db/ioc.template b/iocAdmin/Db/ioc.template index 47e9c8a..eaa06ab 100644 --- a/iocAdmin/Db/ioc.template +++ b/iocAdmin/Db/ioc.template @@ -361,3 +361,28 @@ record(ai, "$(IOCNAME):PARENT_ID") { field(DTYP, "IOC stats") field(INP, "@parent_proc_id") } + +record(ai, "$(IOCNAME):SCANONCE_Q_SIZE") { + field(DESC, "max # entries in IOC scanOnce queue") + field(DTYP, "IOC stats") + field(INP, "@scanOnceQueueSize") + field(PINI, "YES") +} +record(ai, "$(IOCNAME):CB_Q_SIZE") { + field(DESC, "max # entries in IOC callback queues") + field(DTYP, "IOC stats") + field(INP, "@cbQueueSize") + field(PINI, "YES") +} + +substitute "QUEUE=scanOnce, QUEUE_CAPS=SCANONCE, QUEUE_TYPE=SCANONCE" +include "iocQueue.db" + +substitute "QUEUE=cbLow, QUEUE_CAPS=CBLOW, QUEUE_TYPE=CB" +include "iocQueue.db" + +substitute "QUEUE=cbMedium, QUEUE_CAPS=CBMEDIUM, QUEUE_TYPE=CB" +include "iocQueue.db" + +substitute "QUEUE=cbHigh, QUEUE_CAPS=CBHIGH, QUEUE_TYPE=CB" +include "iocQueue.db" diff --git a/iocAdmin/Db/iocQueue.db b/iocAdmin/Db/iocQueue.db new file mode 100644 index 0000000..ab49b88 --- /dev/null +++ b/iocAdmin/Db/iocQueue.db @@ -0,0 +1,45 @@ +record(ai, "$(IOCNAME):$(QUEUE_CAPS)_Q_HIGH") { + field(DESC, "max # of elmts in IOC's $(QUEUE) queue") + field(SCAN, "I/O Intr") + field(DTYP, "IOC stats") + field(INP, "@$(QUEUE)QueueHiWtrMrk") + field(PINI, "YES") + field(FLNK, "$(IOCNAME):$(QUEUE_CAPS)_Q_HIGHPER") +} + +record(calc, "$(IOCNAME):$(QUEUE_CAPS)_Q_HIGHPER") { + field(DESC, "Max. usage of IOC's $(QUEUE) queue") + field(INPA, "$(IOCNAME):$(QUEUE_CAPS)_Q_HIGH NPP MS") + field(INPB, "$(IOCNAME):$(QUEUE_TYPE)_Q_SIZE NPP MS") + field(CALC, "100*A/B") + field(LOPR, "0") + field(HOPR, "100") + field(EGU, "%") +} + +record(ai, "$(IOCNAME):$(QUEUE_CAPS)_Q_USED") { + field(DESC, "# of entries in IOC's $(QUEUE) queue") + field(SCAN, "I/O Intr") + field(DTYP, "IOC stats") + field(INP, "@$(QUEUE)QueueUsed") + field(PINI, "YES") + field(FLNK, "$(IOCNAME):$(QUEUE_CAPS)_Q_USEDPER") +} + +record(calc, "$(IOCNAME):$(QUEUE_CAPS)_Q_USEDPER") { + field(DESC, "Percentage of IOC's $(QUEUE) queue used") + field(INPA, "$(IOCNAME):$(QUEUE_CAPS)_Q_USED NPP MS") + field(INPB, "$(IOCNAME):$(QUEUE_TYPE)_Q_SIZE NPP MS") + field(CALC, "100*A/B") + field(LOPR, "0") + field(HOPR, "100") + field(EGU, "%") +} + +record(ai, "$(IOCNAME):$(QUEUE_CAPS)_Q_OVERRUNS") { + field(DESC, "# of overruns of IOC's $(QUEUE) queue") + field(SCAN, "I/O Intr") + field(DTYP, "IOC stats") + field(INP, "@$(QUEUE)QueueOverruns") + field(PINI, "YES") +}