Ignition parameters firing multiple times with intermediate values and random order

I see we came to a common point, can we get back to the original topic?

  • webpage loading two times and thus firing whatever potentially intensive tasks two times (notice the webpage is loaded with the correct parameter's value so it cannot be filtered away).
  • custom variables firing out of order, this cannot be dealt with any check for null values and it has both a performance impact and a final result impact (in the small SSCCE above the final result is always correct but if the chain of binding dependencies increases it can happen sometimes the final value is updated before all previous custom variables have completed).

While you do log these three values, the actual order is not guaranteed; bindings resolve in an non-deterministic order unless they are dependent on some other binding (like how counter is dependent on value). Beyond that, you have to remember that a binding will re-evaluate and re-execute its transforms whenever the QUALITY of the value changes; this is what you're encountering.

I've modified the logging to include the pageId (to eliminate any potential repeat logging from other open pages of the same session) and the quality of the value being transformed.

  1. Initial load of the Embedded View ( startval ).
  2. Bindings in Embedded View begin evaluating ( custom.value ). They have default values, so that's what they start at (60 as an initial value).
  3. Embedded View ( startval ) updates its quality to specify it is now a generic good value (I'm not quite sure why it doesn't stay as Good_Initial).
  4. The counter prop now evaluates with its value because it was dependent on value having completed.
  5. The value prop now actually receives the param value.
  6. The counter prop must now resolve again because of the binding against value.

Side note: Your counter prop is not a true counter, as it will only ever be the passed-in param + 1. Consider adding a change script to value which increments counter instead of binding against the value of value.

1 Like

Are you saying an expression binding with runScript('some_script', 0, some_value) would have worse performances than a property/expression binding that would return some_value plus a transform script like some_script(value) ?
How ? Why ? A difference in how the interpreter is called, maybe ?

I seem to remember Phil stating the opposite, so I'm not sure what to believe now ! Or maybe I'm remembering it wrong.

All I'm saying is both cases end up running a Python script.

You didn't invent a sneaky optimization by punting your script off to a runScript expression instead of using a transform. There's still a script that has to execute.

Expressions are faster than scripting... until you use the runScript escape hatch and end up in scripting anyway.

You can use my toolkit's nanoTime() in various combinations to explore the various overhead penalties. IIRC, a transform added a noticeable but noisy delay, versus using runScript or objectScript. You'd probably have to collect stats to really characterize it.

runScript itself had slightly less overhead than objectScript, except when objectScript's variable lookup short-circuit was used.

Ah, found where I reported my detailed timing tests on this topic:

Scroll up a few comments, too.

1 Like

I wasn't arguing that runScript removes the overhead of running a python script, I was just very surprised to read that it would have "same or worst" performances compared to a transform.
I would expect the runScript version to have same or better performances.

Yes, better than a transform.

no, but the original post I replied to about it sort of sounded that way, though I'm probably missing some context in this conversation and misunderstood.

I just wanted to make sure it was clear that while expressions are faster than scripting, once you call runScript all bets are off.

1 Like

I could have definitely worded that better. Definitely meant the additional overhead from the transform. As Phil shows, it's roughly in the hundreds of microseconds per execution compared to runScript which is not much if you have one transform that runs every 50 ms but would presumably add up over multiple Perspective sessions full of transforms.

Hi Cody,
thank you for your insight, I'm starting to understand a little more but there are still some odd cases:

the one above is obtained with "persistent" value and counter variables:
1,2,3,4 same sequence as usual, 5 the counter refreshes with quality GOOD before the value which changes after with quality GOOD. Then finally 7.
The above case breaks the dependency which should guarantee the counter always fires after the value because of their dependency.

the one above is obtained with "non-persistent" value and counter variables:
here the dependency between value and counter is preserved (value always triggers before counter).
Still it's not clear why 3 and 4 steps happen at all given the variables should be non persistent (they should either not fire, or fire with null values).

PS: another thing which confuses me is if I put a parameter as "non persistent" the icon of non persistency appears but If I close the view and reopen it, the parameters has disappeared. Apart from this little glitch I don't understand the meaning of a persistent vs a non persistent option for the parameter if this disappears once set to non persistent.
Animazione

sorry for asking so many things together but I think the persistency and the firing of variables are related topics I am still not grasping.

Persistent: Populate the schema of this View with this property and value. Intended to guarantee two things: that a prop always has a value in the schema, and that other references to this property (both in bindings AND scripts) can continue to refer to the property without faulting.

Non-persistent: Do NOT store this property in the schema. Script references to this property result in errors if the reference is encountered before the binding has resolved as the property is not "persisting" within the schema.

So when your bindings are persistent, that really just means that they exist in the schema, and that references to them will succeed. I don't think persistence has anything to do with the value from the Designer; I think that value is stored regardless. I'll try to replicate your problem again later today, but the environment I was using yesterday has been blown away and I'l have to start over.

Edit: The docs say otherwise, so I'll have to wait to replicate.

Oh, it's because your PARAM value has a default of 60. Your bindings will immediately start up using that value, then update again when the value is passed in from the main page.

Said another way: your value binding isn't starting up with a "default" value, it is evaluating based on the default value of startval. Your counter prop is then evaluating as value + 1. The 60 and 61 aren't being stored for value and counter, but 60 IS being stored for startval, which is what value is bound to.
Screenshot 2023-12-21 at 8.53.28 AM

Ok I see, I was confused because the "non persistent" option for the parameter had me thinking it was possible to make also the startval parameter non persistent.

Can you give me a feedback on the issue of the persistency option for the parameter (animated gif of previous post)?

And the out of order execution of the dependency steps 5 and 6 of previous post (I copy pasted the image below):

Could it be a problem with the logger logging out of order? I tried printing with the time but it goes up to the millisecond and cannot get microseconds.
thank you

If you use the java System.nanoTime() in your print statement you can get the nano seconds from java. That should help show the sequence of things.

2 Likes

Thank you @bschroeder , I didn't realize you could use the java nanoTime().
according to timestamps it seems logging might give out of order logs so apparently I wasn't experiencing an out of order firing of dependencies but it was a problem of the logger.

Below a screenshot of bindings firing with their nanotime.

When I make the startval param non-persistent I see different logging than you. Are you confident you saved your changes and opened a new session?

  1. startval on the Embedded View component receives param from page/url.
  2. startval swap to generic Good (still unsure why it's no longer considered an Initial value any longer).
  3. The value prop attempts to resolve, but the property it is bound to does not exist at startup. This leaves you open to a potential race condition as sometimes the param may be in place before a binding resolves, and sometimes it may not. It's also worth noting that counter does NOT yet resolve, because it knows it is waiting on value to have some quality other than Bad_NotFound.
  4. The startval param of the View receives a value, so value now successfully resolves.
  5. counter now resolves as the quality of value is a "good" quality type.

5 and 6 do not appear to be out-of-order. The counter prop receives an initial value (entry 4), then that value becomes something akin to confirmed in step 5. Entry 6 is the value prop actually resolving after the startval param of the View has received a value. Don't confuse your startval entries as belonging to the View - they belong to the Embedded View component.

3 Likes

It looks like Good_Initial is always a temporary quality, and Good_Unspecified is indeed a quality which means the value has been confirmed. It's not clear to me yet what "confirms" the value.

Thank you @cmallonee I think I have understood how things work, to summarize I see a series of things:

  • logging: it can log out of order in certain conditions, I will use the nanotime to be sure of the actual order when seeing weird things.
  • double loading of the page with Good Initial and Good unspecified, now I will always check the quality to have code = 0 (Good unspecified) and exit immediately otherwise or return a None value
  • non persistent param: as by my animated gif what currently happens is the param disappears when non persistent. I think I will not use this functionality as long as the usability won't be fixed. Probably it is not that important because bindings fire anyway.

Overall I think I have now a way of fixing certain behaviours by using the quality.

1 Like