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  <20192020  2021  2022  2023  2024  Index 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  <20192020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: Re: Strange change in behavior from 7.0.1 to 7.0.2
From: "Johnson, Andrew N. via Core-talk" <[email protected]>
To: "Rivers, Mark L." <[email protected]>, "[email protected]" <[email protected]>
Date: Thu, 24 Jan 2019 17:56:50 +0000

On 1/23/19 5:50 PM, Mark Rivers via Core-talk wrote:

_pos is an absolute drive field.  We write to that from CA clients.  It writes to the _rel record with PP.

So that will trigger some kind of RPRO behaviour.

_rel is a transform record that computes the relative move amount.  It forward links to the _lim field, and sends the computed relative move to the _trunc record, which eventually sends it to the device.

_lim is a limit checking record.  It compares _pos to software limit values and sets high and low limit flags if they are exceeded.
grecord(ao,"$(P)$(S):$(D):pM$(M)_pos") {
    field(DESC,"PicoMotor Position in EGUs")
    field(DTYP,"Soft Channel")
    field(SDIS,"$(P)$(S):$(D):pM$(M)_movn.VAL  NPP NMS")
    field(FLNK,"0")
    field(OUT,"$(P)$(S):$(D):pM$(M)_rel.A  PP MS")
    field(PREC,"3")
}

grecord(transform,"$(P)$(S):$(D):pM$(M)_rel") {
    field(DESC,"Convert EGUs to rel steps")
    field(FLNK,"$(P)$(S):$(D):pM$(M)_lim.PROC")
    field(CLCD,"(A>B)?(A-B):(A<B)?(-1*(B-A)):0")
    field(CLCE,"NINT((1/C)*D)")
    field(CLCF,"A")
    field(CLCH,"G=0?E:G=1?((-1)*E):E")
    field(INPA,"0")
    field(INPB,"$(P)$(S):$(D):pM$(M)_prev.VAL  NPP MS")
    field(INPC,"$(P)$(S):$(D):pM$(M)_res.VAL  NPP MS")
    field(INPG,"$(P)$(S):$(D):pM$(M)_dir.VAL  NPP MS")
    field(OUTC,"0")
    field(OUTD,"0")
    field(OUTE,"0")
    field(OUTF,"$(P)$(S):$(D):pM$(M)_prev.VAL  PP MS")
    field(OUTG,"0")
    field(OUTH,"$(P)$(S):$(D):pM$(M)_trunc.A  PP MS")
    field(PREC,"6")
    field(CMTC,"user input EGUs/step")
    field(CMTD,"rel change in EGUs")
    field(CMTE,"rel change in steps")
}

grecord(transform,"$(P)$(S):$(D):pM$(M)_lim") {
    field(CLCD,"A>=C?1:0")
    field(CLCE,"A<=B?1:0")
    field(INPA,"$(P)$(S):$(D):pM$(M)_pos.VAL  PP MS")
    field(INPB,"$(P)$(S):$(D):pM$(M)_pos.DRVL PP MS")
    field(INPC,"$(P)$(S):$(D):pM$(M)_pos.DRVH  PP MS")
    field(OUTD,"$(P)$(S):$(D):pM$(M)_hi.VAL  PP MS")
    field(OUTE,"$(P)$(S):$(D):pM$(M)_lo.VAL  PP MS")
}

Note that the _lim record appears to contain a serious logic error.  The INPA, INPB, and INPC links to the _pos record are PP.  This is almost certainly not what was intended.  They should probably be CP so the record processes whenever those POS fields change.

I wouldn't have called this a serious logic error at first glance, because in the original design _lim gets processed by a recursive call from the ao::process() routine while triggering its OUT PP link through _rel.FLNK. Since the _pos record is still active at that point (_pos.PACT is TRUE) the PP flags on the _lim.OUTx links would be ignored, and are thus harmless.

However if the _lim record ever gets processed by some other means (i.e. not by the _pos.OUT PP → _rel.FLNK → lim path) it will result in the _pos record being processed 3 times in succession and triggering the _rel record from its OUT link, which is obviously unnecessary and probably undesirable given the calculation that _rel is doing.

However, with this logic error the database has worked fine, including with 7.0.1.

However, with 7.0.2 it no longer works.  What happens now is that the _pos and _rel records process twice in rapid succession.  _pos -> _rel -> _lim -> _pos ->_rel

The second processing of _rel computes a relative distance of 0 counts, because _prev now equals _pos.  This calculation happens before the previous relative move command is sent to the controller, with the net result being that every move command sent to the controller is now for 0 counts and it never moves.

I am able to fix the problem by changing the PP links in _lim to CP links, as I think was intended.

My question is why did it ever work, and what has changed in 7.0.2 that caused it to stop working?

So writing to _pos over CA temporarily sets the _pos.PUTF field, indicating that the processing going on was caused by a request from outside the IOC. This is old behaviour, PUTF is cleared unconditionally at the end of recGblFwdLink() when the procesing has completed.

What's new in 7.0.2 is that the OUT PP and FLNK links now cause that PUTF state to be propagated to the _rel and _lim records as well. Now when the _lim.INP links are read with PP causing them to attempt to process _pos again, they set _pos.RPRO. When the processing chain completes and recGblFwdLink() gets called for the _pos record, it will put the record onto the scanOnce queue resulting in the second processing that you're seeing.

I can simplify your database to this using base-only record types:
record(ao,"_pos") {
    field(OUT,"_rel.A PP")
    field(TPRO, 1)
}

record(calc,"_rel") {
    field(FLNK,"_lim")
}

record(calc,"_lim") {
    field(INPA,"_pos PP")
    field(INPB,"_pos.DRVL PP")
    field(INPC,"_pos.DRVH PP")
}
Which generates this output from 7.0.2:
ca:anj@tux: dbProcess of '_pos' ca:anj@tux: dbProcess of '_rel' ca:anj@tux: dbProcess of '_lim' ca:anj@tux: dbProcess of Active '_pos' with RPRO=1 ca:anj@tux: dbProcess of Active '_pos' with RPRO=1 ca:anj@tux: dbProcess of Active '_pos' with RPRO=1 scanOnce: dbProcess of '_pos' scanOnce: dbProcess of '_rel' scanOnce: dbProcess of '_lim' scanOnce: dbProcess of Active '_pos' with RPRO=0 scanOnce: dbProcess of Active '_pos' with RPRO=0 scanOnce: dbProcess of Active '_pos' with RPRO=0
but this from 3.15:
ca:anj@tux: Process _pos
ca:anj@tux: Process _rel
ca:anj@tux: Process _lim
ca:anj@tux: Active _pos
ca:anj@tux: Active _pos
ca:anj@tux: Active _pos
If there's a fix for this I suspect it belongs in dbDbLink.c's processTarget() routine. In the actions for the case 'else if (psrc->putf)' we know that pdst->pact is true so the destination record is busy, but maybe if pdst->putf is also true we should *not* set pdst->rpro, since it might be in our calling chain. Unfortunately pdst->putf might be true because it's in someone else's calling chain (in which case we probably *should* set pdst->rpro), but we currently have no way of distinguishing those two cases.

I could see of a way around this by storing an identifier in the PUTF and RPRO fields which would let us see that (I'd make the PUTF and RPRO fields into DBF_LONG and use an atomic counter to generate a unique ID for each source put).

Michael, what do you think?

- Andrew
-- 
Arguing for surveillance because you have nothing to hide is no
different than making the claim, "I don't care about freedom of
speech because I have nothing to say." -- Edward Snowdon

Replies:
Re: Strange change in behavior from 7.0.1 to 7.0.2 Michael Davidsaver via Core-talk
Re: Strange change in behavior from 7.0.1 to 7.0.2 Michael Davidsaver via Core-talk
References:
Strange change in behavior from 7.0.1 to 7.0.2 Mark Rivers via Core-talk

Navigate by Date:
Prev: Re: Strange change in behavior from 7.0.1 to 7.0.2 Michael Davidsaver via Core-talk
Next: Re: Strange change in behavior from 7.0.1 to 7.0.2 Michael Davidsaver via Core-talk
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  <20192020  2021  2022  2023  2024 
Navigate by Thread:
Prev: Re: Strange change in behavior from 7.0.1 to 7.0.2 Michael Davidsaver via Core-talk
Next: Re: Strange change in behavior from 7.0.1 to 7.0.2 Michael Davidsaver via Core-talk
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  <20192020  2021  2022  2023  2024 
ANJ, 25 Jan 2019 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·