* 3.15: (28 commits) update RELEASE_NOTES add option EPICS_NO_CALLBACK replace CALLBACK -> epicsCallback Update dbTest.c Remove links to wiki-ext Add POD annotations from Wiki to subArrayRecord and menuAlarmStat Rename subArrayRecord.dbd and menuAlarmStat.dbd to .pod Add POD annotations to longoutRecord from Wiki Rename longoutRecord.dbd longoutRecord.dbd.pod Add POD annotations to longinRecord from Wiki Rename longinRecord.dbd longinRecord.dbd.pod Add POD annotations to subRecord from Wiki Rename subRecord.dbd subRecord.dbd.pod Add POD annotations to selRecord from Wiki Rename selRecord.dbd selRecord.dbd.pod Add POD annotations to seqRecord from Wiki Rename seqRecord.dbd seqRecord.dbd.pod Fix menu declaration test too Add redefinition guard to menu-generated typedefs Updates to existing .dbd.pod texts, add event and fanout from wiki ... # Conflicts: # documentation/README.1st # documentation/README.html # modules/database/src/ioc/db/callback.h # modules/database/src/ioc/db/dbNotify.c # modules/database/src/ioc/db/menuAlarmStat.dbd # modules/database/src/ioc/db/menuFtype.dbd # modules/database/src/std/rec/compressRecord.dbd.pod # modules/database/src/std/rec/eventRecord.dbd # modules/database/src/std/rec/fanoutRecord.dbd # modules/database/src/std/rec/longinRecord.dbd # modules/database/src/std/rec/longoutRecord.dbd # modules/database/src/std/rec/selRecord.dbd # modules/database/src/std/rec/seqRecord.dbd # modules/database/src/std/rec/subArrayRecord.dbd # modules/database/src/std/rec/subRecord.dbd # modules/libcom/src/iocsh/menuAlarmStat.dbd.pod # modules/libcom/src/iocsh/menuFtype.dbd.pod # src/ioc/db/menuAlarmStat.dbd # src/ioc/db/menuFtype.dbd Manually fix some move+rename Make additional CALLBACK -> epicsCallback preserve INT64 in menuFtype preserve OLDSIM et al
210 lines
6.3 KiB
C
210 lines
6.3 KiB
C
/*************************************************************************\
|
|
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
|
|
* National Laboratory.
|
|
* Copyright (c) 2002 The Regents of the University of California, as
|
|
* Operator of Los Alamos National Laboratory.
|
|
* Copyright (c) 2013 ITER Organization.
|
|
* EPICS BASE is distributed subject to a Software License Agreement found
|
|
* in file LICENSE that is included with this distribution.
|
|
\*************************************************************************/
|
|
|
|
/* Author: Marty Kraimer Date: 26JAN2000 */
|
|
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
|
|
#include "callback.h"
|
|
#include "cantProceed.h"
|
|
#include "epicsThread.h"
|
|
#include "epicsEvent.h"
|
|
#include "epicsTime.h"
|
|
#include "epicsUnitTest.h"
|
|
#include "testMain.h"
|
|
|
|
/*
|
|
* This test checks both immediate and delayed callbacks in two steps.
|
|
* In the first step (pass1) NCALLBACKS immediate callbacks are queued.
|
|
* As each is run it starts a second delayed callback (pass2).
|
|
* The last delayed callback which runs signals an epicsEvent
|
|
* to the main thread.
|
|
*
|
|
* Two time intervals are measured. The time to queue and run each of
|
|
* the immediate callbacks, and the actual delay of the delayed callback.
|
|
*
|
|
* Slow callbacks no longer fail the test, they just emit a diagnostic.
|
|
*/
|
|
|
|
#define NCALLBACKS 169
|
|
#define DELAY_QUANTUM 0.25
|
|
|
|
#define TEST_DELAY(i) ((i / NUM_CALLBACK_PRIORITIES) * DELAY_QUANTUM)
|
|
|
|
typedef struct myPvt {
|
|
epicsCallback cb1;
|
|
epicsCallback cb2;
|
|
epicsTimeStamp pass1Time;
|
|
epicsTimeStamp pass2Time;
|
|
double delay;
|
|
int pass;
|
|
int resultFail;
|
|
} myPvt;
|
|
|
|
epicsEventId finished;
|
|
|
|
static void myCallback(epicsCallback *pCallback)
|
|
{
|
|
myPvt *pmyPvt;
|
|
|
|
callbackGetUser(pmyPvt, pCallback);
|
|
|
|
pmyPvt->pass++;
|
|
|
|
if (pmyPvt->pass == 1) {
|
|
epicsTimeGetCurrent(&pmyPvt->pass1Time);
|
|
callbackRequestDelayed(&pmyPvt->cb2, pmyPvt->delay);
|
|
} else if (pmyPvt->pass == 2) {
|
|
epicsTimeGetCurrent(&pmyPvt->pass2Time);
|
|
} else {
|
|
pmyPvt->resultFail = 1;
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void finalCallback(epicsCallback *pCallback)
|
|
{
|
|
myCallback(pCallback);
|
|
epicsEventSignal(finished);
|
|
}
|
|
|
|
static void updateStats(double *stats, double val)
|
|
{
|
|
if (stats[0] > val) stats[0] = val;
|
|
if (stats[1] < val) stats[1] = val;
|
|
stats[2] += val;
|
|
stats[3] += pow(val, 2.0);
|
|
stats[4] += 1.;
|
|
}
|
|
|
|
static void printStats(double *stats, const char* tag) {
|
|
testDiag("Priority %4s min/avg/max/sigma = %f / %f / %f / %f",
|
|
tag, stats[0], stats[2]/stats[4], stats[1],
|
|
sqrt(stats[4]*stats[3]-pow(stats[2], 2.0))/stats[4]);
|
|
}
|
|
|
|
MAIN(callbackParallelTest)
|
|
{
|
|
myPvt *pcbt[NCALLBACKS];
|
|
epicsTimeStamp start;
|
|
int noCpus = epicsThreadGetCPUs();
|
|
int i, j, slowups, faults;
|
|
/* Statistics: min/max/sum/sum^2/n for each priority */
|
|
double setupError[NUM_CALLBACK_PRIORITIES][5];
|
|
double timeError[NUM_CALLBACK_PRIORITIES][5];
|
|
double defaultError[5] = {1,-1,0,0,0};
|
|
|
|
for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++)
|
|
for (j = 0; j < 5; j++)
|
|
setupError[i][j] = timeError[i][j] = defaultError[j];
|
|
|
|
testPlan(2);
|
|
|
|
testDiag("Starting %d parallel callback threads", noCpus);
|
|
|
|
callbackParallelThreads(noCpus, "");
|
|
callbackInit();
|
|
epicsThreadSleep(1.0);
|
|
|
|
finished = epicsEventMustCreate(epicsEventEmpty);
|
|
|
|
for (i = 0; i < NCALLBACKS ; i++) {
|
|
pcbt[i] = callocMustSucceed(1, sizeof(myPvt), "pcbt");
|
|
callbackSetCallback(myCallback, &pcbt[i]->cb1);
|
|
callbackSetCallback(myCallback, &pcbt[i]->cb2);
|
|
callbackSetUser(pcbt[i], &pcbt[i]->cb1);
|
|
callbackSetUser(pcbt[i], &pcbt[i]->cb2);
|
|
callbackSetPriority(i % NUM_CALLBACK_PRIORITIES, &pcbt[i]->cb1);
|
|
callbackSetPriority(i % NUM_CALLBACK_PRIORITIES, &pcbt[i]->cb2);
|
|
pcbt[i]->delay = TEST_DELAY(i);
|
|
pcbt[i]->pass = 0;
|
|
}
|
|
|
|
/* Last callback is special */
|
|
callbackSetCallback(finalCallback, &pcbt[NCALLBACKS-1]->cb2);
|
|
callbackSetPriority(0, &pcbt[NCALLBACKS-1]->cb1);
|
|
callbackSetPriority(0, &pcbt[NCALLBACKS-1]->cb2);
|
|
pcbt[NCALLBACKS-1]->delay = TEST_DELAY(NCALLBACKS) + 1.0;
|
|
pcbt[NCALLBACKS-1]->pass = 0;
|
|
|
|
testOk(epicsTimeGetCurrent(&start)==epicsTimeOK, "Time-of-day clock Ok");
|
|
|
|
for (i = 0; i < NCALLBACKS ; i++) {
|
|
callbackRequest(&pcbt[i]->cb1);
|
|
}
|
|
|
|
testDiag("Waiting %.02f sec", pcbt[NCALLBACKS-1]->delay);
|
|
|
|
epicsEventWait(finished);
|
|
slowups = 0;
|
|
faults = 0;
|
|
|
|
for (i = 0; i < NCALLBACKS ; i++) {
|
|
if(pcbt[i]->resultFail || pcbt[i]->pass!=2)
|
|
testDiag("callback setup fault #%d: pass = %d for delay = %.02f",
|
|
++faults, pcbt[i]->pass, pcbt[i]->delay);
|
|
else {
|
|
double delta = epicsTimeDiffInSeconds(&pcbt[i]->pass1Time, &start);
|
|
|
|
if (fabs(delta) >= 0.05) {
|
|
slowups++;
|
|
testDiag("callback %.02f setup time |%f| >= 0.05 seconds",
|
|
pcbt[i]->delay, delta);
|
|
}
|
|
updateStats(setupError[i%NUM_CALLBACK_PRIORITIES], delta);
|
|
}
|
|
}
|
|
testOk(faults == 0, "%d faults during callback setup", faults);
|
|
if (slowups)
|
|
testDiag("%d slowups during callback setup", slowups);
|
|
|
|
slowups = 0;
|
|
for (i = 0; i < NCALLBACKS ; i++) {
|
|
double delta, error;
|
|
|
|
if(pcbt[i]->resultFail || pcbt[i]->pass!=2)
|
|
continue;
|
|
delta = epicsTimeDiffInSeconds(&pcbt[i]->pass2Time, &pcbt[i]->pass1Time);
|
|
error = delta - pcbt[i]->delay;
|
|
if (fabs(error) >= 0.05) {
|
|
slowups++;
|
|
testDiag("delay %.02f seconds, delay error |%.04f| >= 0.05",
|
|
pcbt[i]->delay, error);
|
|
}
|
|
updateStats(timeError[i%NUM_CALLBACK_PRIORITIES], error);
|
|
}
|
|
if (slowups)
|
|
testDiag("%d slowups during callback setup", slowups);
|
|
|
|
testDiag("Setup time statistics");
|
|
printStats(setupError[0], "LOW");
|
|
printStats(setupError[1], "MID");
|
|
printStats(setupError[2], "HIGH");
|
|
|
|
testDiag("Delay time statistics");
|
|
printStats(timeError[0], "LOW");
|
|
printStats(timeError[1], "MID");
|
|
printStats(timeError[2], "HIGH");
|
|
|
|
for (i = 0; i < NCALLBACKS ; i++) {
|
|
free(pcbt[i]);
|
|
}
|
|
|
|
callbackStop();
|
|
callbackCleanup();
|
|
|
|
return testDone();
|
|
}
|