Geo SCADA Knowledge Base
Access vast amounts of technical know-how and pro tips from our community of Geo SCADA experts.
Link copied. Please paste this link to share this article on your social media post.
Originally published on Geo SCADA Knowledge Base by Anonymous user | June 10, 2021 04:09 AM
The NOCACHE keyword instructs a structured text program (or function blocks too, but the rest of the article focuses on structured text) to not load the contents of the variable at request time but instead wait until execution time before reading this value. To understand this better, the simple operation of a structured text program is detailed below.
In the above order we see that in step 1 the variables are temporarily stored at a separate stage to the actual execution. Whilst the gap is usually measured in milliseconds it can be much larger depending on what other logic programs are queued, and so the variables that were already read in may have changed. The NOCACHE keyword simply forces those declared variables to be read from the database later at step 2 rather than at step 1.
In normal execution of structured text it doesn't, however there are two cases where when the value is read make significantly impact the results of the logic, and both those cases are when multiple instances of the same structured text program are called at once.
If you have a structured text program that is configured to run on input processed, looking at a point that receives point update in batches (PSTN is the popular example, but certain direct protocols that also support logged data will be affected), then it's possible that the logic may use an external counter to total up the new values (such as a daily totaliser). When the multiple point updates come in then multiple instances of the program, one for each update, are queued. If they all reference the same source counter then without NOCACHE they will all use the same starting value and create an incorrect output result. E.g.:
PROGRAM TotaliserWithError
VAR
NewValue AT %I(.PSTN Point.CurrentValue) : LREAL;
Count AT %M(.Count.CurrentValue) : LREAL;
END_VAR
Count := Count + NewValue;
END_PROGRAM
With a few point updates to the PSTN point coming into the system at once, for example four updates of values 1, 2, 3 and 4 and Count having previously been 0 the final result of the above logic program running four times will not be 10 as expected.
This is because the four times it ran the first time it ran Count's result was 1 (which is correct), the next time Count would be 2 (that is 0 + 2), the next time 3 (0 + 3) and after the final time Count will be 4 (0 + 4). If historic data is enabled on the Count point, all the outputs will be stored, however the CurrentValue will likely be 4 at the end of the processing.
Depending on how the queue updates happen, it is possible for executions 1 and 2 to complete before executions 3 and 4 get put on the queue, so the output to Count from execution 2 could be used at the Count input to executions 3 and 4, resulting in the final value of 6 (2 + 4).
The solution is to put the Count variable in a NOCACHE block, i.e.:
PROGRAM Totaliser
VAR
NewValue AT %I(.PSTN Point.CurrentValue) : LREAL;
END_VAR
VAR NOCACHE
Count AT %M(.Count.CurrentValue) : LREAL;
END_VAR
Count := Count + NewValue;
END_PROGRAM
So now, after execution 1 ends and updates the value of Count, when execution 2 starts (the logic thread is single threaded so only one program can execute at once) it will read in the current value of Count, with it's new value, and correctly add the next value to product an output of 3 This will then be repeated for executions 3 and 4 resulting in the correct result of 10.
Similar to the batched point updates above, a structured text program can be called many times from within another structured text program (note that calling the Execute method from VB or other remote sources may not be "immediate enough" to trigger this timing condition).
E.g. A calling program of:
PROGRAM CallingProgram
METHOD
Execute AT %M(.Totaliser.Execute) : SINT;
END_METHOD
FOR i:=1 TO 4 DO
Execute(i);
END_FOR;
END_PROGRAM
and Totaliser's code being similar to the above PSTN example:
PROGRAM Totaliser
VAR_INPUT
NewValue : SINT;
END_VAR
VAR NOCACHE
Count AT %M(.Count.CurrentValue) : SINT;
END_VAR
Count := Count + NewValue;
END_PROGRAM
Set both programs to execute on interval, but with the interval of 0. Setting Count to be 0 in the database will also help to show the effect.
When the calling program runs, it calls the totaliser four times in quick succession. Because the NOCACHE is used the resultant value in Count will be 10, however removing the NOCACHE keyword from the totaliser, setting Count manually back to 0 and re-running the calling program will now set Count instead to be 4. This can easily be used to show the difference.
The NOCACHE keyword can apply to database queries within Structured Text programs. NOCACHE will change the way queries work only for logic which is executed on point value change or triggered from another program. This is because those types of execution are started under a write lock, so the query to access data is also under a write lock. This is less efficient because only read locks can be parallelised. There is no benefit or penalty for NOCACHE for time-executed logic, or update/insert queries. Note also that NOCACHE will cause the query to be executed when the logic actually runs, which may be later in time to when it is queued, so there are situations where NOCACHE is inappropriate.
In summary, choose NOCACHE for a SQL SELECT query when the logic program is run on the change to input data and the results of the query do not vary between queue time and execution time.
Go: Home Back
Link copied. Please paste this link to share this article on your social media post.
Create your free account or log in to subscribe to the board - and gain access to more than 10,000+ support articles along with insights from experts and peers.