diff --git a/src/ioc/db/callback.c b/src/ioc/db/callback.c index ae074141c..1b6c24906 100644 --- a/src/ioc/db/callback.c +++ b/src/ioc/db/callback.c @@ -54,6 +54,7 @@ typedef struct cbQueueSet { epicsEventId semWakeUp; epicsRingPointerId queue; int queueOverflow; + int queueOverflows; int shutdown; int threadsConfigured; int threadsRunning; @@ -103,6 +104,51 @@ int callbackSetQueueSize(int size) return 0; } +int callbackQueueStatus(const int reset, callbackQueueStats *result) +{ + int ret; + if (!callbackIsInit) return -1; + if (result) { + int prio; + result->size = callbackQueueSize; + for(prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) { + epicsRingPointerId qId = callbackQueue[prio].queue; + result->numUsed[prio] = epicsRingPointerGetUsed(qId); + result->maxUsed[prio] = epicsRingPointerGetHighWaterMark(qId); + result->numOverflow[prio] = epicsAtomicGetIntT(&callbackQueue[prio].queueOverflows); + } + ret = 0; + } else { + ret = -2; + } + if (reset) { + int prio; + for(prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) { + epicsRingPointerResetHighWaterMark(callbackQueue[prio].queue); + } + } + return ret; +} + +void callbackQueuePrintStatus(const int reset) +{ + callbackQueueStats stats; + if (callbackQueueStatus(reset, &stats) == -1) { + fprintf(stderr, "Callback system not initialized, yet. Please run " + "iocInit before using this command.\n"); + } else { + int prio; + printf("PRIORITY HIGH-WATER MARK ITEMS IN Q Q SIZE %% USED Q OVERFLOWS\n"); + for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) { + double qusage = 100.0 * stats.numUsed[prio] / stats.size; + printf("%8s %15d %10d %6d %6.1f %11d\n", + threadNamePrefix[prio], stats.maxUsed[prio], + stats.numUsed[prio], stats.size, qusage, + stats.numOverflow[prio]); + } + } +} + int callbackParallelThreads(int count, const char *prio) { if (callbackIsInit) { @@ -290,6 +336,7 @@ int callbackRequest(CALLBACK *pcallback) if (!pushOK) { epicsInterruptContextMessage(fullMessage[priority]); mySet->queueOverflow = TRUE; + epicsAtomicIncrIntT(&mySet->queueOverflows); return S_db_bufFull; } epicsEventSignal(mySet->semWakeUp); diff --git a/src/ioc/db/callback.h b/src/ioc/db/callback.h index fa626d1d0..dd13cdb81 100644 --- a/src/ioc/db/callback.h +++ b/src/ioc/db/callback.h @@ -48,6 +48,13 @@ typedef epicsCallback CALLBACK; typedef void (*CALLBACKFUNC)(struct callbackPvt*); +typedef struct callbackQueueStats { + int size; + int numUsed[NUM_CALLBACK_PRIORITIES]; + int maxUsed[NUM_CALLBACK_PRIORITIES]; + int numOverflow[NUM_CALLBACK_PRIORITIES]; +} callbackQueueStats; + #define callbackSetCallback(PFUN, PCALLBACK) \ ( (PCALLBACK)->callback = (PFUN) ) #define callbackSetPriority(PRIORITY, PCALLBACK) \ @@ -73,6 +80,8 @@ epicsShareFunc void callbackCancelDelayed(CALLBACK *pcallback); epicsShareFunc void callbackRequestProcessCallbackDelayed( CALLBACK *pCallback, int Priority, void *pRec, double seconds); epicsShareFunc int callbackSetQueueSize(int size); +epicsShareFunc int callbackQueueStatus(const int reset, callbackQueueStats *result); +void callbackQueuePrintStatus(const int reset); epicsShareFunc int callbackParallelThreads(int count, const char *prio); #ifdef __cplusplus diff --git a/src/ioc/db/dbIocRegister.c b/src/ioc/db/dbIocRegister.c index 4d0b88cd9..cecf75608 100644 --- a/src/ioc/db/dbIocRegister.c +++ b/src/ioc/db/dbIocRegister.c @@ -296,6 +296,17 @@ static void scanOnceSetQueueSizeCallFunc(const iocshArgBuf *args) scanOnceSetQueueSize(args[0].ival); } +/* scanOnceQueueStatus */ +static const iocshArg scanOnceQueueStatusArg0 = { "reset",iocshArgInt}; +static const iocshArg * const scanOnceQueueStatusArgs[1] = + {&scanOnceQueueStatusArg0}; +static const iocshFuncDef scanOnceQueueStatusFuncDef = + {"scanOnceQueueStatus",1,scanOnceQueueStatusArgs}; +static void scanOnceQueueStatusCallFunc(const iocshArgBuf *args) +{ + scanOnceQueuePrintStatus(args[0].ival); +} + /* scanppl */ static const iocshArg scanpplArg0 = { "rate",iocshArgDouble}; static const iocshArg * const scanpplArgs[1] = {&scanpplArg0}; @@ -335,6 +346,17 @@ static void callbackSetQueueSizeCallFunc(const iocshArgBuf *args) callbackSetQueueSize(args[0].ival); } +/* callbackQueueStatus */ +static const iocshArg callbackQueueStatusArg0 = { "reset", iocshArgInt}; +static const iocshArg * const callbackQueueStatusArgs[1] = + {&callbackQueueStatusArg0}; +static const iocshFuncDef callbackQueueStatusFuncDef = + {"callbackQueueStatus",1,callbackQueueStatusArgs}; +static void callbackQueueStatusCallFunc(const iocshArgBuf *args) +{ + callbackQueuePrintStatus(args[0].ival); +} + /* callbackParallelThreads */ static const iocshArg callbackParallelThreadsArg0 = { "no of threads", iocshArgInt}; static const iocshArg callbackParallelThreadsArg1 = { "priority", iocshArgString}; @@ -441,12 +463,14 @@ void dbIocRegister(void) iocshRegister(&dbLockShowLockedFuncDef,dbLockShowLockedCallFunc); iocshRegister(&scanOnceSetQueueSizeFuncDef,scanOnceSetQueueSizeCallFunc); + iocshRegister(&scanOnceQueueStatusFuncDef,scanOnceQueueStatusCallFunc); iocshRegister(&scanpplFuncDef,scanpplCallFunc); iocshRegister(&scanpelFuncDef,scanpelCallFunc); iocshRegister(&postEventFuncDef,postEventCallFunc); iocshRegister(&scanpiolFuncDef,scanpiolCallFunc); iocshRegister(&callbackSetQueueSizeFuncDef,callbackSetQueueSizeCallFunc); + iocshRegister(&callbackQueueStatusFuncDef,callbackQueueStatusCallFunc); iocshRegister(&callbackParallelThreadsFuncDef,callbackParallelThreadsCallFunc); /* Needed before callback system is initialized */ diff --git a/src/ioc/db/dbScan.c b/src/ioc/db/dbScan.c index e5c78fea1..e0e14e0d2 100644 --- a/src/ioc/db/dbScan.c +++ b/src/ioc/db/dbScan.c @@ -24,6 +24,7 @@ #include "cantProceed.h" #include "dbDefs.h" #include "ellLib.h" +#include "epicsAtomic.h" #include "epicsEvent.h" #include "epicsMutex.h" #include "epicsPrint.h" @@ -63,6 +64,7 @@ static volatile enum ctl scanCtl; static int onceQueueSize = 1000; static epicsEventId onceSem; static epicsRingBytesId onceQ; +static int onceQOverruns = 0; static epicsThreadId onceTaskId; static void *exitOnce; @@ -676,6 +678,7 @@ int scanOnceCallback(struct dbCommon *precord, once_complete cb, void *usr) if (!pushOK) { if (newOverflow) errlogPrintf("scanOnce: Ring buffer overflow\n"); newOverflow = FALSE; + epicsAtomicIncrIntT(&onceQOverruns); } else { newOverflow = TRUE; } @@ -722,6 +725,40 @@ int scanOnceSetQueueSize(int size) return 0; } +int scanOnceQueueStatus(const int reset, scanOnceQueueStats *result) +{ + int ret; + if (!onceQ) return -1; + if (result) { + result->size = epicsRingBytesSize(onceQ) / sizeof(onceEntry); + result->numUsed = epicsRingBytesUsedBytes(onceQ) / sizeof(onceEntry); + result->maxUsed = epicsRingBytesHighWaterMark(onceQ) / sizeof(onceEntry); + result->numOverflow = epicsAtomicGetIntT(&onceQOverruns); + ret = 0; + } else { + ret = -2; + } + if (reset) { + epicsRingBytesResetHighWaterMark(onceQ); + } + return ret; +} + +void scanOnceQueuePrintStatus(const int reset) +{ + scanOnceQueueStats stats; + if (scanOnceQueueStatus(reset, &stats) == -1) { + fprintf(stderr, "scanOnce system not initialized, yet. Please run " + "iocInit before using this command.\n"); + } else { + double qusage = 100.0 * stats.numUsed / stats.size; + printf("PRIORITY HIGH-WATER MARK ITEMS IN Q Q SIZE %% USED Q OVERFLOWS\n"); + printf("%8s %15d %10d %6d %6.1f %11d\n", "scanOnce", stats.maxUsed, + stats.numUsed, stats.size, qusage, + epicsAtomicGetIntT(&onceQOverruns)); + } +} + static void initOnce(void) { if ((onceQ = epicsRingBytesLockedCreate(sizeof(onceEntry)*onceQueueSize)) == NULL) { diff --git a/src/ioc/db/dbScan.h b/src/ioc/db/dbScan.h index d483a0c30..830d3a8dc 100644 --- a/src/ioc/db/dbScan.h +++ b/src/ioc/db/dbScan.h @@ -42,6 +42,13 @@ struct dbCommon; typedef void (*io_scan_complete)(void *usr, IOSCANPVT, int prio); typedef void (*once_complete)(void *usr, struct dbCommon*); +typedef struct scanOnceQueueStats { + int size; + int numUsed; + int maxUsed; + int numOverflow; +} scanOnceQueueStats; + epicsShareFunc long scanInit(void); epicsShareFunc void scanRun(void); epicsShareFunc void scanPause(void); @@ -57,6 +64,8 @@ epicsShareFunc double scanPeriod(int scan); epicsShareFunc int scanOnce(struct dbCommon *); epicsShareFunc int scanOnceCallback(struct dbCommon *, once_complete cb, void *usr); epicsShareFunc int scanOnceSetQueueSize(int size); +epicsShareFunc int scanOnceQueueStatus(const int reset, scanOnceQueueStats *result); +void scanOnceQueuePrintStatus(const int reset); /*print periodic lists*/ epicsShareFunc int scanppl(double rate); diff --git a/src/libCom/ring/epicsRingBytes.c b/src/libCom/ring/epicsRingBytes.c index cb7e52e83..ab048e467 100644 --- a/src/libCom/ring/epicsRingBytes.c +++ b/src/libCom/ring/epicsRingBytes.c @@ -38,6 +38,7 @@ typedef struct ringPvt { volatile int nextPut; volatile int nextGet; int size; + int highWaterMark; volatile char buffer[1]; /* actually larger */ }ringPvt; @@ -47,6 +48,7 @@ epicsShareFunc epicsRingBytesId epicsShareAPI epicsRingBytesCreate(int size) if(!pring) return NULL; pring->size = size + SLOP; + pring->highWaterMark = 0; pring->nextGet = 0; pring->nextPut = 0; pring->lock = 0; @@ -118,7 +120,7 @@ epicsShareFunc int epicsShareAPI epicsRingBytesPut( { ringPvt *pring = (ringPvt *)id; int nextGet, nextPut, size; - int freeCount, copyCount, topCount; + int freeCount, copyCount, topCount, used; if (pring->lock) epicsSpinLock(pring->lock); nextGet = pring->nextGet; @@ -131,8 +133,9 @@ epicsShareFunc int epicsShareAPI epicsRingBytesPut( if (pring->lock) epicsSpinUnlock(pring->lock); return 0; } - if (nbytes) + if (nbytes) { memcpy ((void *)&pring->buffer[nextPut], value, nbytes); + } nextPut += nbytes; } else { @@ -143,8 +146,9 @@ epicsShareFunc int epicsShareAPI epicsRingBytesPut( } topCount = size - nextPut; copyCount = (nbytes > topCount) ? topCount : nbytes; - if (copyCount) + if (copyCount) { memcpy ((void *)&pring->buffer[nextPut], value, copyCount); + } nextPut += copyCount; if (nextPut == size) { int nLeft = nbytes - copyCount; @@ -155,6 +159,10 @@ epicsShareFunc int epicsShareAPI epicsRingBytesPut( } pring->nextPut = nextPut; + used = nextPut - nextGet; + if (used < 0) used += pring->size; + if (used > pring->highWaterMark) pring->highWaterMark = used; + if (pring->lock) epicsSpinUnlock(pring->lock); return nbytes; } @@ -224,3 +232,20 @@ epicsShareFunc int epicsShareAPI epicsRingBytesIsFull(epicsRingBytesId id) { return (epicsRingBytesFreeBytes(id) <= 0); } + +epicsShareFunc int epicsShareAPI epicsRingBytesHighWaterMark(epicsRingBytesIdConst id) +{ + ringPvt *pring = (ringPvt *)id; + return pring->highWaterMark; +} + +epicsShareFunc void epicsShareAPI epicsRingBytesResetHighWaterMark(epicsRingBytesId id) +{ + ringPvt *pring = (ringPvt *)id; + int used; + if (pring->lock) epicsSpinLock(pring->lock); + used = pring->nextGet - pring->nextPut; + if (used < 0) used += pring->size; + pring->highWaterMark = used; + if (pring->lock) epicsSpinUnlock(pring->lock); +} diff --git a/src/libCom/ring/epicsRingBytes.h b/src/libCom/ring/epicsRingBytes.h index 011829bfe..3dc0081ad 100644 --- a/src/libCom/ring/epicsRingBytes.h +++ b/src/libCom/ring/epicsRingBytes.h @@ -24,6 +24,7 @@ extern "C" { #include "shareLib.h" typedef void *epicsRingBytesId; +typedef void const *epicsRingBytesIdConst; epicsShareFunc epicsRingBytesId epicsShareAPI epicsRingBytesCreate(int nbytes); /* Same, but secured by a spinlock */ @@ -39,6 +40,8 @@ epicsShareFunc int epicsShareAPI epicsRingBytesUsedBytes(epicsRingBytesId id); epicsShareFunc int epicsShareAPI epicsRingBytesSize(epicsRingBytesId id); epicsShareFunc int epicsShareAPI epicsRingBytesIsEmpty(epicsRingBytesId id); epicsShareFunc int epicsShareAPI epicsRingBytesIsFull(epicsRingBytesId id); +epicsShareFunc int epicsShareAPI epicsRingBytesHighWaterMark(epicsRingBytesIdConst id); +epicsShareFunc void epicsShareAPI epicsRingBytesResetHighWaterMark(epicsRingBytesId id); #ifdef __cplusplus } diff --git a/src/libCom/ring/epicsRingPointer.cpp b/src/libCom/ring/epicsRingPointer.cpp index 9c144cec1..709ab6509 100644 --- a/src/libCom/ring/epicsRingPointer.cpp +++ b/src/libCom/ring/epicsRingPointer.cpp @@ -90,3 +90,15 @@ epicsShareFunc int epicsShareAPI epicsRingPointerIsFull(epicsRingPointerId id) voidPointer *pvoidPointer = reinterpret_cast(id); return((pvoidPointer->isFull()) ? 1 : 0); } + +epicsShareFunc int epicsShareAPI epicsRingPointerGetHighWaterMark(epicsRingPointerIdConst id) +{ + voidPointer const *pvoidPointer = reinterpret_cast(id); + return(pvoidPointer->getHighWaterMark()); +} + +epicsShareFunc void epicsShareAPI epicsRingPointerResetHighWaterMark(epicsRingPointerId id) +{ + voidPointer *pvoidPointer = reinterpret_cast(id); + pvoidPointer->resetHighWaterMark(); +} diff --git a/src/libCom/ring/epicsRingPointer.h b/src/libCom/ring/epicsRingPointer.h index 48d62036d..68bf8f5a6 100644 --- a/src/libCom/ring/epicsRingPointer.h +++ b/src/libCom/ring/epicsRingPointer.h @@ -40,18 +40,22 @@ public: /* Functions */ int getSize() const; bool isEmpty() const; bool isFull() const; + int getHighWaterMark() const; + void resetHighWaterMark(); private: /* Prevent compiler-generated member functions */ /* default constructor, copy constructor, assignment operator */ epicsRingPointer(); epicsRingPointer(const epicsRingPointer &); epicsRingPointer& operator=(const epicsRingPointer &); + int getUsedNoLock() const; private: /* Data */ epicsSpinId lock; volatile int nextPush; volatile int nextPop; int size; + int highWaterMark; T * volatile * buffer; }; @@ -59,6 +63,7 @@ extern "C" { #endif /*__cplusplus */ typedef void *epicsRingPointerId; +typedef void const *epicsRingPointerIdConst; epicsShareFunc epicsRingPointerId epicsShareAPI epicsRingPointerCreate(int size); /* Same, but secured by a spinlock */ @@ -74,6 +79,8 @@ epicsShareFunc int epicsShareAPI epicsRingPointerGetUsed(epicsRingPointerId id) epicsShareFunc int epicsShareAPI epicsRingPointerGetSize(epicsRingPointerId id); epicsShareFunc int epicsShareAPI epicsRingPointerIsEmpty(epicsRingPointerId id); epicsShareFunc int epicsShareAPI epicsRingPointerIsFull(epicsRingPointerId id); +epicsShareFunc int epicsShareAPI epicsRingPointerGetHighWaterMark(epicsRingPointerIdConst id); +epicsShareFunc void epicsShareAPI epicsRingPointerResetHighWaterMark(epicsRingPointerId id); /* This routine was incorrectly named in previous releases */ #define epicsRingPointerSize epicsRingPointerGetSize @@ -95,7 +102,8 @@ epicsShareFunc int epicsShareAPI epicsRingPointerIsFull(epicsRingPointerId id); template inline epicsRingPointer::epicsRingPointer(int sz, bool locked) : - lock(0), nextPush(0), nextPop(0), size(sz+1), buffer(new T* [sz+1]) + lock(0), nextPush(0), nextPop(0), size(sz+1), highWaterMark(0), + buffer(new T* [sz+1]) { if (locked) lock = epicsSpinCreate(); @@ -121,6 +129,8 @@ inline bool epicsRingPointer::push(T *p) } buffer[next] = p; nextPush = newNext; + int used = getUsedNoLock(); + if (used > highWaterMark) highWaterMark = used; if (lock) epicsSpinUnlock(lock); return(true); } @@ -161,12 +171,19 @@ inline int epicsRingPointer::getFree() const return n; } +template +inline int epicsRingPointer::getUsedNoLock() const +{ + int n = nextPush - nextPop; + if (n < 0) n += size; + return n; +} + template inline int epicsRingPointer::getUsed() const { if (lock) epicsSpinLock(lock); - int n = nextPush - nextPop; - if (n < 0) n += size; + int n = getUsedNoLock(); if (lock) epicsSpinUnlock(lock); return n; } @@ -196,6 +213,20 @@ inline bool epicsRingPointer::isFull() const return((count == 0) || (count == size)); } +template +inline int epicsRingPointer::getHighWaterMark() const +{ + return highWaterMark; +} + +template +inline void epicsRingPointer::resetHighWaterMark() +{ + if (lock) epicsSpinLock(lock); + highWaterMark = getUsedNoLock(); + if (lock) epicsSpinUnlock(lock); +} + #endif /* __cplusplus */ #endif /* INCepicsRingPointerh */ diff --git a/src/libCom/test/ringBytesTest.c b/src/libCom/test/ringBytesTest.c index 6cef93334..bb91d0201 100644 --- a/src/libCom/test/ringBytesTest.c +++ b/src/libCom/test/ringBytesTest.c @@ -30,7 +30,8 @@ typedef struct info { epicsRingBytesId ring; }info; -static void check(epicsRingBytesId ring, int expectedFree) +static void check(epicsRingBytesId ring, int expectedFree, + int expectedHighWaterMark) { int expectedUsed = RINGSIZE - expectedFree; int expectedEmpty = (expectedUsed == 0); @@ -39,11 +40,14 @@ static void check(epicsRingBytesId ring, int expectedFree) int nUsed = epicsRingBytesUsedBytes(ring); int isEmpty = epicsRingBytesIsEmpty(ring); int isFull = epicsRingBytesIsFull(ring); + int highWaterMark = epicsRingBytesHighWaterMark(ring); testOk(nFree == expectedFree, "Free: %d == %d", nFree, expectedFree); testOk(nUsed == expectedUsed, "Used: %d == %d", nUsed, expectedUsed); testOk(isEmpty == expectedEmpty, "Empty: %d == %d", isEmpty, expectedEmpty); testOk(isFull == expectedFull, "Full: %d == %d", isFull, expectedFull); + testOk(highWaterMark == expectedHighWaterMark, "HighWaterMark: %d == %d", + highWaterMark, expectedHighWaterMark); } MAIN(ringBytesTest) @@ -55,7 +59,7 @@ MAIN(ringBytesTest) char get[RINGSIZE+1]; epicsRingBytesId ring; - testPlan(245); + testPlan(292); pinfo = calloc(1,sizeof(info)); if (!pinfo) { @@ -70,50 +74,54 @@ MAIN(ringBytesTest) if (!ring) { testAbort("epicsRingBytesCreate failed"); } - check(ring, RINGSIZE); + check(ring, RINGSIZE, 0); for (i = 0 ; i < sizeof(put) ; i++) put[i] = i; for(i = 0 ; i < RINGSIZE ; i++) { n = epicsRingBytesPut(ring, put, i); testOk(n==i, "ring put %d", i); - check(ring, RINGSIZE-i); + check(ring, RINGSIZE-i, i); n = epicsRingBytesGet(ring, get, i); testOk(n==i, "ring get %d", i); - check(ring, RINGSIZE); + check(ring, RINGSIZE, i); testOk(memcmp(put,get,i)==0, "get matches write"); } + epicsRingBytesResetHighWaterMark(ring); + for(i = 0 ; i < RINGSIZE ; i++) { n = epicsRingBytesPut(ring, put+i, 1); testOk(n==1, "ring put 1, %d", i); - check(ring, RINGSIZE-1-i); + check(ring, RINGSIZE-1-i, i + 1); } n = epicsRingBytesPut(ring, put+RINGSIZE, 1); testOk(n==0, "put to full ring"); - check(ring, 0); + check(ring, 0, RINGSIZE); for(i = 0 ; i < RINGSIZE ; i++) { n = epicsRingBytesGet(ring, get+i, 1); testOk(n==1, "ring get 1, %d", i); - check(ring, 1+i); + check(ring, 1+i, RINGSIZE); } testOk(memcmp(put,get,RINGSIZE)==0, "get matches write"); n = epicsRingBytesGet(ring, get+RINGSIZE, 1); testOk(n==0, "get from empty ring"); - check(ring, RINGSIZE); + check(ring, RINGSIZE, RINGSIZE); + + epicsRingBytesResetHighWaterMark(ring); n = epicsRingBytesPut(ring, put, RINGSIZE+1); testOk(n==0, "ring put beyond ring capacity (%d, expected 0)",n); - check(ring, RINGSIZE); + check(ring, RINGSIZE, 0); n = epicsRingBytesPut(ring, put, 1); testOk(n==1, "ring put %d", 1); - check(ring, RINGSIZE-1); + check(ring, RINGSIZE-1, 1); n = epicsRingBytesPut(ring, put, RINGSIZE); testOk(n==0, "ring put beyond ring capacity (%d, expected 0)",n); - check(ring, RINGSIZE-1); + check(ring, RINGSIZE-1, 1); n = epicsRingBytesGet(ring, get, 1); testOk(n==1, "ring get %d", 1); - check(ring, RINGSIZE); + check(ring, RINGSIZE, 1); epicsRingBytesDelete(ring); epicsEventDestroy(consumerEvent); diff --git a/src/libCom/test/ringPointerTest.c b/src/libCom/test/ringPointerTest.c index 65a349489..d351708b5 100644 --- a/src/libCom/test/ringPointerTest.c +++ b/src/libCom/test/ringPointerTest.c @@ -64,6 +64,7 @@ static void testSingle(void) testOk1(epicsRingPointerGetFree(ring)==rsize); testOk1(epicsRingPointerGetSize(ring)==rsize); testOk1(epicsRingPointerGetUsed(ring)==0); + testOk1(epicsRingPointerGetHighWaterMark(ring)==0); testOk1(epicsRingPointerPop(ring)==NULL); @@ -75,6 +76,10 @@ static void testSingle(void) testOk1(epicsRingPointerGetFree(ring)==rsize-1); testOk1(epicsRingPointerGetSize(ring)==rsize); testOk1(epicsRingPointerGetUsed(ring)==1); + testOk1(epicsRingPointerGetHighWaterMark(ring)==1); + + epicsRingPointerResetHighWaterMark(ring); + testOk1(epicsRingPointerGetHighWaterMark(ring)==1); testDiag("Fill it up"); for(i=2; i<2*rsize; i++) { @@ -92,6 +97,7 @@ static void testSingle(void) testOk1(epicsRingPointerGetFree(ring)==0); testOk1(epicsRingPointerGetSize(ring)==rsize); testOk1(epicsRingPointerGetUsed(ring)==rsize); + testOk1(epicsRingPointerGetHighWaterMark(ring)==rsize); testDiag("Drain it out"); for(i=1; i<2*rsize; i++) { @@ -108,6 +114,7 @@ static void testSingle(void) testOk1(epicsRingPointerGetFree(ring)==rsize); testOk1(epicsRingPointerGetSize(ring)==rsize); testOk1(epicsRingPointerGetUsed(ring)==0); + testOk1(epicsRingPointerGetHighWaterMark(ring)==rsize); testDiag("Fill it up again"); for(i=2; i<2*rsize; i++) { @@ -236,7 +243,7 @@ MAIN(ringPointerTest) { int prio = epicsThreadGetPrioritySelf(); - testPlan(37); + testPlan(42); testSingle(); if (prio) epicsThreadSetPriority(epicsThreadGetIdSelf(), epicsThreadPriorityScanLow);