EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  <20212022  2023  2024  Index 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  <20212022  2023  2024 
<== Date ==> <== Thread ==>

Subject: [Merge] ~bfrk/epics-base:scalar-get-optimization into epics-base:7.0
From: Ben Franksen via Core-talk <core-talk at aps.anl.gov>
To: mp+399344 at code.launchpad.net
Date: Tue, 09 Mar 2021 09:35:38 -0000
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  <20212022  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  <20212022  2023  2024 
ANJ, 09 Mar 2021 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·