Ben Franksen has proposed merging ~bfrk/epics-base:scalar-get-optimization into epics-base:7.0.
Commit message:
rebased to current 7.0 and removed the dependency on the (already merged) remove-dbfl_type_rec
Requested reviews:
EPICS Core Developers (epics-core)
Ben Franksen (bfrk)
For more details, see:
https://code.launchpad.net/~bfrk/epics-base/+git/epics-base/+merge/399344
The idea here is to make the special optimization for one-element get requests without options available to all code that calls dbChannelGet. It started out as an attempt to disentangle this logic from dbDbGetValue (this goal is indeed achieved) and then moved on from that point.
--
Your team EPICS Core Developers is requested to review the proposed merge of ~bfrk/epics-base:scalar-get-optimization into epics-base:7.0.
diff --git a/modules/database/src/ioc/db/dbChannel.c b/modules/database/src/ioc/db/dbChannel.c
index c71d842..a3667bb 100644
--- a/modules/database/src/ioc/db/dbChannel.c
+++ b/modules/database/src/ioc/db/dbChannel.c
@@ -34,6 +34,7 @@
#include "dbBase.h"
#include "dbChannel.h"
#include "dbCommon.h"
+#include "dbConvertFast.h"
#include "dbEvent.h"
#include "dbLock.h"
#include "dbStaticLib.h"
@@ -630,14 +631,54 @@ long dbChannelOpen(dbChannel *chan)
}
/* Only use dbChannelGet() if the record is already locked. */
-long dbChannelGet(dbChannel *chan, short type, void *pbuffer,
- long *options, long *nRequest, void *pfl)
+long dbChannelGet(dbChannel *chan, short dbrType, void *pbuffer,
+ long *options, long *nRequest, db_field_log *pfl)
{
- return dbGet(&chan->addr, type, pbuffer, options, nRequest, pfl);
+ dbAddr addr = chan->addr; /* structure copy */
+
+ if (pfl) {
+ addr.field_size = pfl->field_size;
+ addr.field_type = pfl->field_type;
+ addr.no_elements = pfl->no_elements;
+ addr.pfield = dbfl_pfield(pfl);
+ }
+
+ /*
+ * Try to optimize scalar requests by caching (just) the conversion
+ * routine. This is possible only if we have no options, the field and the
+ * request have exactly one element, and we have no special processing to
+ * do. Note that if the db_field_log has already copied the data, dbGet
+ * does not call get_array_info.
+ */
+ if (!(options && *options)
+ && addr.no_elements == 1
+ && (!nRequest || *nRequest == 1)
+ && (dbfl_has_copy(pfl) || addr.special != SPC_DBADDR)
+ && addr.special != SPC_ATTRIBUTE)
+ {
+ if (chan->getCvt && chan->lastGetdbrType == dbrType) {
+ return chan->getCvt(addr.pfield, pbuffer, &addr);
+ } else {
+ unsigned short dbfType = addr.field_type;
+
+ if (dbrType < 0 || dbrType > DBR_ENUM || dbfType > DBF_DEVICE)
+ return S_db_badDbrtype;
+
+ chan->getCvt = dbFastGetConvertRoutine[dbfType][dbrType];
+ chan->lastGetdbrType = dbrType;
+ if (nRequest)
+ *nRequest = addr.no_elements;
+ return chan->getCvt(addr.pfield, pbuffer, &addr);
+ }
+ } else {
+ /* non-optimized case */
+ chan->getCvt = NULL;
+ return dbGet(&addr, dbrType, pbuffer, options, nRequest, pfl);
+ }
}
long dbChannelGetField(dbChannel *chan, short dbrType, void *pbuffer,
- long *options, long *nRequest, void *pfl)
+ long *options, long *nRequest, db_field_log *pfl)
{
dbCommon *precord = chan->addr.precord;
long status = 0;
diff --git a/modules/database/src/ioc/db/dbChannel.h b/modules/database/src/ioc/db/dbChannel.h
index ec86e9e..dc6240f 100644
--- a/modules/database/src/ioc/db/dbChannel.h
+++ b/modules/database/src/ioc/db/dbChannel.h
@@ -50,6 +50,8 @@ typedef struct evSubscrip {
typedef struct chFilter chFilter;
+typedef long fastConvert(void *from, void *to, const dbAddr *paddr);
+
/* A dbChannel points to a record field, and can have multiple filters */
typedef struct dbChannel {
const char *name;
@@ -60,6 +62,9 @@ typedef struct dbChannel {
ELLLIST filters; /* list of filters as created from JSON */
ELLLIST pre_chain; /* list of filters to be called pre-event-queue */
ELLLIST post_chain; /* list of filters to be called post-event-queue */
+ /* Support for optimizing scalar requests */
+ fastConvert *getCvt; /* fast get conversion function */
+ short lastGetdbrType; /* last dbChannelGet dbrType */
} dbChannel;
/* Prototype for the channel event function that is called in filter stacks
@@ -208,9 +213,9 @@ DBCORE_API extern unsigned short dbDBRnewToDBRold[];
DBCORE_API long dbChannelGet(dbChannel *chan, short type,
- void *pbuffer, long *options, long *nRequest, void *pfl);
+ void *pbuffer, long *options, long *nRequest, db_field_log *pfl);
DBCORE_API long dbChannelGetField(dbChannel *chan, short type,
- void *pbuffer, long *options, long *nRequest, void *pfl);
+ void *pbuffer, long *options, long *nRequest, db_field_log *pfl);
DBCORE_API long dbChannelPut(dbChannel *chan, short type,
const void *pbuffer, long nRequest);
DBCORE_API long dbChannelPutField(dbChannel *chan, short type,
diff --git a/modules/database/src/ioc/db/dbDbLink.c b/modules/database/src/ioc/db/dbDbLink.c
index b281314..399d36d 100644
--- a/modules/database/src/ioc/db/dbDbLink.c
+++ b/modules/database/src/ioc/db/dbDbLink.c
@@ -58,7 +58,6 @@
#include "dbBase.h"
#include "dbBkpt.h"
#include "dbCommonPvt.h"
-#include "dbConvertFast.h"
#include "dbConvert.h"
#include "db_field_log.h"
#include "db_access_routines.h"
@@ -135,9 +134,7 @@ static void dbDbRemoveLink(struct dbLocker *locker, struct link *plink)
/* locker is NULL when an isolated IOC is closing its links */
if (locker) {
plink->value.pv_link.pvt = 0;
- plink->value.pv_link.getCvt = 0;
plink->value.pv_link.pvlMask = 0;
- plink->value.pv_link.lastGetdbrType = 0;
ellDelete(&precord->bklnk, &plink->value.pv_link.backlinknode);
dbLockSetSplit(locker, plink->precord, precord);
}
@@ -167,7 +164,6 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
{
struct pv_link *ppv_link = &plink->value.pv_link;
dbChannel *chan = linkChannel(plink);
- DBADDR *paddr = &chan->addr;
dbCommon *precord = plink->precord;
db_field_log *pfl = NULL;
long status;
@@ -179,49 +175,19 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
return status;
}
- if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType)
- {
- /* shortcut: scalar with known conversion, no filter */
- status = ppv_link->getCvt(dbChannelField(chan), pbuffer, paddr);
- }
- else if (dbChannelFinalElements(chan) == 1 && (!pnRequest || *pnRequest == 1)
- && dbChannelSpecial(chan) != SPC_DBADDR
- && dbChannelSpecial(chan) != SPC_ATTRIBUTE
- && ellCount(&chan->filters) == 0)
- {
- /* simple scalar: set up shortcut */
- unsigned short dbfType = dbChannelFinalFieldType(chan);
-
- if (dbrType < 0 || dbrType > DBR_ENUM || dbfType > DBF_DEVICE)
- return S_db_badDbrtype;
-
- ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType];
- ppv_link->lastGetdbrType = dbrType;
- status = ppv_link->getCvt(dbChannelField(chan), pbuffer, paddr);
- }
- else
- {
- /* filter, array, or special */
- ppv_link->getCvt = NULL;
-
- if (ellCount(&chan->filters)) {
- /* If filters are involved in a read, create field log and run filters */
- pfl = db_create_read_log(chan);
- if (!pfl)
- return S_db_noMemory;
-
- pfl = dbChannelRunPreChain(chan, pfl);
- pfl = dbChannelRunPostChain(chan, pfl);
- }
-
- status = dbChannelGet(chan, dbrType, pbuffer, NULL, pnRequest, pfl);
-
- if (pfl)
- db_delete_field_log(pfl);
-
- if (status)
- return status;
+ /* If filters are involved in a read, create field log and run filters */
+ if (ellCount(&chan->filters)) {
+ pfl = db_create_read_log(chan);
+ if (!pfl)
+ return S_db_noMemory;
+ pfl = dbChannelRunPreChain(chan, pfl);
+ pfl = dbChannelRunPostChain(chan, pfl);
}
+ status = dbChannelGet(chan, dbrType, pbuffer, NULL, pnRequest, pfl);
+ if (pfl)
+ db_delete_field_log(pfl);
+ if (status)
+ return status;
if (!status && precord != dbChannelRecord(chan))
recGblInheritSevr(plink->value.pv_link.pvlMask & pvlOptMsMode,
diff --git a/modules/database/src/ioc/dbStatic/link.h b/modules/database/src/ioc/dbStatic/link.h
index c3c0045..d212395 100644
--- a/modules/database/src/ioc/dbStatic/link.h
+++ b/modules/database/src/ioc/dbStatic/link.h
@@ -78,15 +78,12 @@ struct macro_link {
};
struct dbCommon;
-typedef long (*LINKCVT)();
struct pv_link {
ELLNODE backlinknode;
char *pvname; /* pvname link points to */
void *pvt; /* CA or DB private */
- LINKCVT getCvt; /* input conversion function */
short pvlMask; /* Options mask */
- short lastGetdbrType; /* last dbrType for DB or CA get */
};
struct jlink;
- Navigate by Date:
- Prev:
[Merge] ~bfrk/epics-base:scalar-get-optimization into epics-base:7.0 Ben Franksen via Core-talk
- Next:
[Bug 1182091] Re: Make TIME field directly accessible Jure Varlec via Core-talk
- Index:
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
<2021>
2022
2023
2024
- Navigate by Thread:
- Prev:
[Merge] ~bfrk/epics-base:scalar-get-optimization into epics-base:7.0 Ben Franksen via Core-talk
- Next:
Build completed: EPICS Base 7 base-7.0-123 AppVeyor via Core-talk
- Index:
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
<2021>
2022
2023
2024
|