Argonne National Laboratory

Experimental Physics and
Industrial Control System

1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  <20142015  2016  2017  Index 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  <20142015  2016  2017 
<== Date ==> <== Thread ==>

Subject: Re: Increasing scan rate to 10 kHz
From: Andrew Johnson <anj@aps.anl.gov>
To: Evgeniy <tikh@triumf.ca>
Cc: EPICS Tech Talk <tech-talk@aps.anl.gov>
Date: Tue, 7 Jan 2014 16:19:25 -0600
Hi Evgeniy,

On 12/23/2013 05:46 PM, Evgeniy wrote:
> The question is: if Mark got processing time for bi record 150
> microseconds 20 years ago should I have 1.5 microseconds for the same
> record on 100 times faster CPU ?

I have just timed how long it takes to process a simple database; my
recent-model MacBook Pro took 3.005 seconds to process the calc and ai
records from the example template's dbExample1.db file a million times,
thus the ai+calc pair processed once every 3 microseconds.

To do that I wrote a special record type (attached) that repeatedly
processes its target link. It is quite flexible, you can set it to do a
specific number of repetitions (REPM="Count", the count can be read
through the INP link or just put it into the VAL field which triggers
processing), or have it read the INP input link before or after each
operation to determine whether to continue or not (REPM="While" or "Until").

There is also a limit field STOP which sets the maximum number of
repetitions for protection. The value of STOP defaults to a million, but
you can override it yourself if you wish, up to 2^32-1. Note that
running this for several seconds can cause CA clients to disconnect, so
be careful with it!

> The same arithmetic question for scan. If its minimum period was 0.01
> seconds 20 years ago should I expect minimum 0.0001 seconds nowadays?

Periodic scans are quite complicated, since they rely on the underlying
operating system to implement a delay timer and reschedule the scan
thread after the specific delay has elapsed. Most OSs don't provide high
accuracy delay scheduling, so I don't expect we will ever be able to run
periodic scan threads at 10KHz.

- Andrew
-- 
Advertising may be described as the science of arresting the human
intelligence long enough to get money from it. -- Stephen Leacock
/*************************************************************************\
* Copyright (c) 2013 UChicago Argonne LLC, as Operator of Argonne
*     National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution. 
\*************************************************************************/

/* $Revision-Id$ */
/*
 *      Author: Andrew Johnson
 *      Date: 2013-12-27
 */

#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#include "dbDefs.h"
#include "epicsPrint.h"
#include "alarm.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "dbFldTypes.h"
#include "errMdef.h"
#include "recSup.h"
#include "recGbl.h"
#include "dbCommon.h"

#define GEN_SIZE_OFFSET
#include "repeatRecord.h"
#undef  GEN_SIZE_OFFSET
#include "epicsExport.h"

static long init_record(repeatRecord *prec, int pass)
{
    if (pass && prec->repm == repeatREPM_Count) {
        recGblInitConstantLink(&prec->inp, DBF_ULONG, &prec->val);
        prec->udf = FALSE;
    }
    return 0;
}

static long process(repeatRecord *prec)
{
    epicsUInt32 rept = prec->val;
    epicsUInt32 i = 0;

    prec->pact = TRUE;

    prec->val = i;
    recGblGetTimeStamp(prec);
    db_post_events(prec, &prec->val, DBE_VALUE|DBE_LOG);

    switch (prec->repm) {
    case repeatREPM_None:
        break;

    case repeatREPM_Once:
        dbScanFwdLink(&prec->tgt);
        i++;
        break;

    case repeatREPM_Count:
        if (prec->inp.type != CONSTANT) {
            dbGetLink(&prec->inp, DBR_ULONG, &rept, 0, 0);
        }
        if (rept > prec->stop)
            rept = prec->stop;
        for (; i < rept; i++) {
            dbScanFwdLink(&prec->tgt);
        }
        break;

    case repeatREPM_While:
        if (prec->inp.type != CONSTANT) {
            dbGetLink(&prec->inp, DBR_ULONG, &rept, 0, 0);
        }
        while (rept) {
            dbScanFwdLink(&prec->tgt);
            if (++i >= prec->stop)
                break;
            if (prec->inp.type != CONSTANT) {
                dbGetLink(&prec->inp, DBR_ULONG, &rept, 0, 0);
            }
        }
        break;

    case repeatREPM_Until:
        do {
            dbScanFwdLink(&prec->tgt);
            if (++i >= prec->stop)
                break;
            if (prec->inp.type != CONSTANT) {
                dbGetLink(&prec->inp, DBR_ULONG, &rept, 0, 0);
            }
        } while (!rept);
        break;

    default:
        (void) recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
    }

    /* trigger alarm change monitors */
    recGblResetAlarms(prec);

    prec->udf = FALSE;
    prec->val = i;
    recGblGetTimeStamp(prec);
    db_post_events(prec, &prec->val, DBE_VALUE|DBE_LOG);

    /* process the forward link */
    recGblFwdLink(prec);
    prec->pact = FALSE;

    return 0;
}

/* Create and export the Record Support Entry Table */

rset repeatRSET = {
    RSETNUMBER, NULL, NULL, init_record, process
};
epicsExportAddress(rset, repeatRSET);

menu(repeatREPM) {
    choice(repeatREPM_None, "None")
    choice(repeatREPM_Once, "Once")
    choice(repeatREPM_Count, "Count")
    choice(repeatREPM_While, "While")
    choice(repeatREPM_Until, "Until")
}
recordtype(repeat) {
    include "dbCommon.dbd" 
    field(VAL, DBF_ULONG) {
        prompt("Repeat")
        asl(ASL0)
        pp(TRUE)
    }
    field(REPM, DBF_MENU) {
        prompt("Repeat Mode")
        promptgroup(GUI_INPUTS)
        interest(1)
        menu(repeatREPM)
    }
    field(INP, DBF_INLINK) {
        prompt("Input Link")
        promptgroup(GUI_INPUTS)
        interest(1)
    }
    field(TGT, DBF_FWDLINK) {
        prompt("Target Link")
        promptgroup(GUI_LINKS)
        interest(1)
    }
    field(STOP, DBF_ULONG) {
	prompt("Repeat limit")
        promptgroup(GUI_INPUTS)
        interest(1)
	initial(1000000)
    }
    field(MVAL, DBF_ULONG) {
        special(SPC_NOMOD)
	interest(2)
    }
}

Replies:
Re: Increasing scan rate to 10 kHz Keith Thorne
Re: Increasing scan rate to 10 kHz Till Straumann

Navigate by Date:
Prev: RE: Device support : TCP/IP packet Mark Rivers
Next: Re: Increasing scan rate to 10 kHz Keith Thorne
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  <20142015  2016  2017 
Navigate by Thread:
Prev: RE: Device support : TCP/IP packet Mark Rivers
Next: Re: Increasing scan rate to 10 kHz Keith Thorne
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  <20142015  2016  2017 
ANJ, 17 Dec 2015 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·