04-24-2023 10:26 AM
LabVIEW 2020 SP1 64-bit
I've got a plug-in system. Everything is Asynchronous. The catch is that I might need to create up to 12 instances of the same instrument. So as I instantiate the plug-ins, who are going to all access the same class, I notice the readback times increase at a factor of X where X is the number of plug-ins I've instantiated. So either I've missed something important with asynchronous calls - or I've missed a key detail/property about lvlibps that I need to set that allows them to have re-entrant behavior. Any thoughts? My asynchronous calls are 0x80 - btw.
As a band-aid, I'm considering making up to 12 versions of the lvlibps and just putting a number 1-12 on it so the plug-ins know which one to access instead of all accessing the same one.
Solved! Go to Solution.
04-24-2023 11:14 AM
Without seeing any code or how you have things configured we really can't provide any advise to you.
In the past we encountered something similar in our code. Turned out that the NI Database Toolkit was single threaded and that serialized all of our asynchronous DB code. Perhaps you have some common library/toolkit that is single threaded in our coded.
04-24-2023 11:15 AM
Do I need to make every VI within the class a reentrant VI? But the more I think about that, the more that doesn't make a lot of sense. Does the class internally need to be designed to be what instantiates and controls the multiple instances? I've clearly missed something in the design practice of this.
04-24-2023 11:17 AM
@Mark_Yedinak wrote:
Without seeing any code or how you have things configured we really can't provide any advise to you.
In the past we encountered something similar in our code. Turned out that the NI Database Toolkit was single threaded and that serialized all of our asynchronous DB code. Perhaps you have some common library/toolkit that is single threaded in our coded.
The only NI toolkit they use is the VISA Read. Could that be the culprit? If so, is there any realistic fix to that?
04-24-2023 11:21 AM
Again, show some code. It doesn't have to be your actual production code but scaled down version which lets us look at how things are configured and what you are actually doing now. Also, when posting code it is a good practice to save it for an older version of LabVIEW since not everyone on the forums is using the latest version.
Not everything has to be marked as reentrant code. For example, there is no reason to mark a simple accessor as reentrant because the operation itself happens almost instantly. Communication methods or any method that will require significant time should be marked as reentrant.
04-24-2023 11:33 AM
@Mark_Yedinak wrote:
Again, show some code. It doesn't have to be your actual production code but scaled down version which lets us look at how things are configured and what you are actually doing now. Also, when posting code it is a good practice to save it for an older version of LabVIEW since not everyone on the forums is using the latest version.
Not everything has to be marked as reentrant code. For example, there is no reason to mark a simple accessor as reentrant because the operation itself happens almost instantly. Communication methods or any method that will require significant time should be marked as reentrant.
I can definitely make some example code of what's going on. But I always like to ask if there was a setting that someone knows about that is easily forgotten. Cuz I've personally dug through my code quite extensively and tested it and continue to prove as I increase the instances, the read time is multiplied by that those number of instances. Which of course suggests something is causing it to behave synchronously. And I have wondered if the VISA Read was the culprit, but I've also got different instruments that access that VISA Read, but access different classes and they don't see to be interfering with each other's read timing.
To be more specific, if I make a single instance of a power supply, it takes about 250ms for a read back of voltage, current, and enabled. Then I add an instance a DMM (which also uses VISA Read) and the PS continues at 250ms for a read where the DMM is also about 250ms. Add another PS, and now both PS read at 500ms, but the DMM is reading at 250ms.
So, before I go through making shareable code, this should all work the way I think it should with a single lvlibp for the Power Supplies and one for the DMM, yes? I don't need to make one for each PS and DMM?
04-24-2023 12:25 PM
@DailyDose wrote:
Do I need to make every VI within the class a reentrant VI? But the more I think about that, the more that doesn't make a lot of sense. Does the class internally need to be designed to be what instantiates and controls the multiple instances? I've clearly missed something in the design practice of this.
I would start by marking everything as reentrant and see if it fixes the problem. Some of the stuff you're posting makes me think you think each "instance" of the class causes its methods to run in parallel; this isn't the case and reentrancy is defined in the properties for each specific VI.
Creating a different packed libraries for each instance may in fact help because doing so could incidentally cause "cloning" behavior as the same VI may get namespaced into each lvlibp, eg "x.lvlibp:read.vi" and "y.lvlibp:read.vi" may run in parallel even if neither is reentrant. Note the different qualified names of the VIs. If you want to run multiple clones of a VI with the same qualified name it must be marked as reentrant.
04-24-2023 12:57 PM - edited 04-24-2023 12:59 PM
@avogadro5 wrote:
I would start by marking everything as reentrant and see if it fixes the problem. Some of the stuff you're posting makes me think you think each "instance" of the class causes its methods to run in parallel; this isn't the case and reentrancy is defined in the properties for each specific VI.
Creating a different packed libraries for each instance may in fact help because doing so could incidentally cause "cloning" behavior as the same VI may get namespaced into each lvlibp, eg "x.lvlibp:read.vi" and "y.lvlibp:read.vi" may run in parallel even if neither is reentrant. Note the different qualified names of the VIs. If you want to run multiple clones of a VI with the same qualified name it must be marked as reentrant.
Yes, that is exactly what I was thinking. That the packaged lvlibp by nature was reentrant due to the likely use case. Sounds like that is not how that works after all. That it just acts like single VI and can only be accessed by a single instance at a time thus causing everything to be serialized.
Do both the parent and child classes need to be reentrant or just one of them?
04-24-2023 01:35 PM
Blocking behavior is
@DailyDose wrote:
@avogadro5 wrote:
I would start by marking everything as reentrant and see if it fixes the problem. Some of the stuff you're posting makes me think you think each "instance" of the class causes its methods to run in parallel; this isn't the case and reentrancy is defined in the properties for each specific VI.
Creating a different packed libraries for each instance may in fact help because doing so could incidentally cause "cloning" behavior as the same VI may get namespaced into each lvlibp, eg "x.lvlibp:read.vi" and "y.lvlibp:read.vi" may run in parallel even if neither is reentrant. Note the different qualified names of the VIs. If you want to run multiple clones of a VI with the same qualified name it must be marked as reentrant.
Yes, that is exactly what I was thinking. That the packaged lvlibp by nature was reentrant due to the likely use case. Sounds like that is not how that works after all. That it just acts like single VI and can only be accessed by a single instance at a time thus causing everything to be serialized.
Do both the parent and child classes need to be reentrant or just one of them?
For the most part blocking behavior isn't related to the class hierarchy: there is no way to make a "non-reentrant class," it's all defined by the VIs in the class. What is probably happening is that one or more non-reentrant VIs are being called by (or are) members of both classes causing them to block each other. One other way to test this would be to try running the different parallel instances in different projects: each project gets its own "clones" of the VI hierarchy.
04-24-2023 01:36 PM
Okay, I changed all methods within both Parent and Child classes to Shared Reentrant and now every instance of the plug-in is churning at the 250ms - so there ya go.
Your help was greatly appreciated! Thank you!