Jump to content

John Lokanis

  • Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by John Lokanis

  1. I am running into a very strange issue. I have a second dev machine that I want to use. I took all my code and zipped it up, then copied it to the new machine and unzipped it. Both machines have the same version of LabVIEW (2013) installed from the same DVDs. Both machines have the same VI packages installed. All files are in the same position on the drive on both machines. (EXACTLY the same). I *should* be able to open the project on the new machine and get no dirty dots. I assume it will want to compile all the code once since I have separated source from BD. Instead, one of the projects opens but want to save 108 VIs because it claims a typedef moved on disk (it did not). The other project opens and then as soon as the project window finally appears, LabVIEW crashes. Every time. So, I started opening individual classes one by one to see if I could find the issue. On just the second class I opened, I found that some of the accessor VIs were missing. They were on the disk and the .lvclass file was identical to the one on my main machine (I double checked) but when it was opened, LabVIEW claimed it had no knowledge of the accessors. The control was in the class, just not the accessors. And since that was missing, everywhere this class was used in a property node, it claimed that I had no element by that name to access. I have never seen this before. I assumed that all the information about what was in a class was in the lvclass file. And if the files were the same, and the required VIs where still there at the exact same paths, then everything would work. But it does not. Has anyone run across this before? Is there a fix? I am guessing this might be due to class mutation data (a feature I could really do without) but I am not sure. thanks for any tips that lead to a solution... -John
  2. Thanks for the input. I decided to create a object cache FGV. This seems to alleviate the speed issues. There is still a blocking issue since it is a singleton implementation but that is unavoidable. I suppose I could store the cache in a DVR or SEQ and 'peek' it to check for a hit, but I am not sure it is worth the added complexity. Has anyone timed these options for performance? Anyways, attached is my simple object cache VI if you are interested. -John Class Object Cache.vi ps. I prefer this implementation to a 'load at startup' option because it allows the cache to change based on user interaction or by data driven actions. In my case, the user loads a script that defines what object classes will be needed. This can change at any time. I only incur the load penalty once per class that is actually needed, instead of loading every plugin class possible at startup. This also allows for new classes to be added while the application is running without a restart. Of course, if your application is time critical on every run, pre-loading will avoid the first run penalty.
  3. I have an application where I am loading plugins from disk and executing them. Each plugin is a child class of my plugin class. I am using the factory pattern. During development, I started out by having a static plugin class object for testing purposes and then later switched to loading the plugin class default value from disk. My architecture works by dynamically launching a generic plugin handler that then loads the required plugin class and dynamically launches a method in that class. So, the handler and the plugin are disconnected from the main application. They communicate using messages. I am launching many of these plugins at the same time. A common use case would be in the 100's (this is a test system) When I switched from the static object to loading the classes, I noticed a significant slowdown, especially with higher #s of plugins (100+) loading at once. I did an experiment to make all the plugins being loaded be the same so it should only incur the disk load of the class a single time. When I compare this to the static plugin version, there is a 4x reduction in execution speed. So, it seems that the function that gets the default value of a class is much slower and more resource intensive than using a static object, even if the class is already loaded into memory. I also suspect that this function runs in the root loop, causing blocking issues. Does anyone know of a way to speed this up or mitigate the slowdown? In the past I used to cache refs of dynamically loaded plugins (before LVOOP) so I would not incur the load penalty. There does not seem to be a way to do this here that I am seeing. thanks for any ideas. -John
  4. Solved it with a variant. I changed the system class DVR input in the handler to a variant and then cast it to the proper type within the handler. Now the system class is happy to have the strictly typed vi ref of the handler in its private data. I also added a test to the handler launcher that checks the stored ref and creates a new one if it is invalid. I wrapped this in an IPE structure to prevent multiple callers from updating this ref at the same time. I suppose that is not absolutely necessary since the ref is to the same VI type, but this prevents me from leaking references if two get opened at the same time and I only store (and clean up) the last one. I see that AF does something similar except there the launcher is non-reentrant and the ref is stored in an uninitialized shift register. Personally, I am not a big fan of non-reentrant code. I only use that setting in specific cases (like FGVs) and tend to make all my other VIs shared clones. I wish I could set that to be the default when creating a new VI... Now, for each concrete instance of my system class that uses dynamic process (actor) launching, I get a separate VI ref to the handler. I wonder if this creates a separate pool of shared clones? And if so, I wonder if this improves or degrades performance?
  5. My handler VI is not in a class, but it is in a library. I have already made some child classes of my system that enable additional features, like networked messaging. I suppose I could add a new child for dynamic launching, but that would mean that the networked enabled system class would need to inherit from the dynamic launching system class. Should would be nice to have multiple inheritance for this situation. Also, I consider the dynamic launching feature to be a core feature of the system so I would prefer to have it in the top parent. I don't like adding complexity if I can avoid it. But, this might be the only solution. So far, it does not look like I can cast a generic DVR ref to a specific DVR ref.
  6. Figured it out. My 'handler' VI has an input of type 'system class' and I was trying to add the strictly typed refnum of the handler to that 'system class'. Looks like I will have to find an acceptable hack to fix this. I am thinking of passing the class to the handler as a generic reference and then casting it in the handler to the proper type. Any better ideas?
  7. Well, either way, I still want to encapsulate the reference. I just don't see why I cannot use a strict type VI ref in class data. I can use other type def'd data types in class data. What is special about this case?
  8. I have a system class wrapped in a DVR that I pass to all processes in my application. This allows me to create communication channels between these processes (ie: a message system) and limit it to only the processes that I pass this DVR to. If I want to have two parallel systems, I just create two instances of the system class and wrap each of them in a DVR and pass it to the proper processes. This allows me to segment my system into multiple independent systems within one application instance. If I was to use a functional global as you suggest, I would be limited to a single 'system' within the application instance. (same as the current 'global' I am using) Now, this does not matter as much if all the 'hander' VIs are based on the same reentrant VI, but it does come into play when I call my system cleanup code. I cannot put the close reference in there if I have multiple 'systems' within a single application instance with different lifetimes. Otherwise, I would 'clean up' the reference when one system was shutdown, even though the other system was still running. I also wonder about the pool of shared clones. It might be more efficient to have each system create its own reference to use when dynamically launching processes because it might mean LabVIEW creates a separate pool of clones for each reference. But that is getting a bit more under the hood and we will need to hear from AQ or others about the reality of that situation.
  9. I am trying to solve a performance problem with my application and I have run into an issue I do not understand. For some reason, I cannot create a class data element that is a strictly typed vi reference. I can create a generic one just fine, but if I try to make it strict, I get an error. The reason I am trying to do this is to avoid the overhead and 'root loop' issues with the Open VI Reference call. In my application I am dynamically launching multiple child objects using a more generic 'handler' VI. I simply open a reentrant instance of this 'handler' vi, pass in the child class and the 'handler' calls my 'run' method in the child class via dynamic dispatch. The problem I ran into was the Open VI Reference was bogging down the system. So, I decided to use the Start Asynchronous Call with options 0x40 and 0x80. The idea was to open a single reference to my 'handler' when my application starts and then store this in the class data of an object that I pass to all my VIs (for data sharing). I would then use this reference to call the Start Asynchronous Call function (it requires a strictly typed vi reference). But, I was stopped when I tried to add the strictly typed vi reference to the class data. As a workaround to prove my fix would solve my speed issue, I created a global variable (horror!) and stored the strictly typed vi reference in that. I then used this global when calling the Start Asynchronous Call function. This worked fine and my performance issues are gone. But I would really like to put that reference in a class instead of in a global. I even tried using a generic vi refnum, thinking I could cast it to the strictly type refnum before sending it to the Start Asynchronous Call but I found that you cannot cast a generic VI refnum to a strictly typed vi refnum. So, any ideas? This does not seem like a strange thing to want to do. Perhaps there is some reasoning behind it that I am not aware of. Any thoughts on a way to accomplish my goal via a different route? thanks for any feedback, -John
  10. Here is a new idea I have been meaning to post: http://forums.ni.com/t5/LabVIEW-Idea-Exchange/Allow-comments-to-point-to-more-than-one-object/idi-p/2692537 Please take a look and Kudo!
  11. Went to post on the exchange and found that the same basic idea already existed. So I am linking to it here. Please give this your Kudos... http://forums.ni.com/t5/LabVIEW-Idea-Exchange/Dot-convention-for-accessing-nested-LVCLASS-properties/idc-p/2692469#M26234 Basically, I am looking for the property node to have consistent behavior when working with classes. For those of you who use property node access to your class data and use composition, this will lead to much cleaner code.
  12. This topic is one of the reasons I gave up on source code control for the early stages of a project. I have reverted to the 'zip and copy to server once a day' method for backups. Once the project is stable and working, I will put the whole thing into Perforce for future maintenance. But at this point, I seem to rename 50% of my classes as I code them and decide they need to do something different or need to be split into multiple classes. And don't get me started on how I should have designed it on paper first so I didn't have to rename so many things. I went into this project with exactly those intentions and I now believe that anybody who says they actually do this successfully is lying to you.
  13. The class hierarchy window contains none of this information. It only shows you what classes are children of other classes. Messages are not children of the processes that execute them. The VI hierarchy window is just a mess, showing every single VI connection from a VI perspective, but again, not the information I am looking for. The node map is intended to show links between processes/actors via the messages they send/receive. This only works for messages systems where the message is a class. The idea is the process appears as a central node with the messages it can receive surrounding it. If one of those messages in turn sends a message to another process when it is executed, then a link is shown from the sending message to the receiving message. The idea is you can see all the messages a process can be sent and you can see what other processes are sending what messages to each process. So, you can then trace the propagation of an action through the application. For example: The user presses button X. The UI code sends a message to the UI message process that button X was pressed. The UI process then executes this message, causing it to send another message to the main controller process to execute action X. The main controller process then executes this message, causing it to send another message to the external comm process to send command X to some external device/application. The node map would show all those links so you could visualize what was happening and see the message flow. Ideally, you would be able to click on each node and view the underlying code in LabVIEW, but, I have not developed it to the point where that is possible. I have not seen another method to help visualize the message flow of an application. I have looked at sequence diagrams but those show specific intra-process communication for specific conditions. They do not expose all the potential links in the system. Command pattern message based system are tightly coupled but it is not easy to visualize that coupling. I think we need a way to do this to help us understand complex system implemented with these type of architectures.
  14. I am thinking of expanding on this for a CLA Summit presentation. But before I invest a lot of time, I am wondering how many others think a tool like this would be useful. If you are interested, please reply or 'like' this post so I have an idea of the level of interest in this subject. thanks, -John
  15. Yes, always from inside the project. I cannot reproduce the 330x result. This is what I get running outside the project from the desktop: Of course, now I get the same results from all locations. Must have been something weird about my machine at the time. (Also running Win7 and LV2013)
  16. This is a very strange problem. I have put together a demo project to demonstrate the speed differences in array vs variant attribute storage methods. I also included a test of different variant database designs to show some pitfalls. I first built this project in the following folder on my machine: C:DevelopmentSourcesandboxVariant Attributes It seemed to be working well and demonstrating the effects I was after. I then moved the folder to my desktop: C:UserslokanisDesktopVariant Attributes When I opened the project from here, and tested it, the demo ran 1000x faster and no longer demonstrated the effect I was after. Next I tried moving it to here: C:tempVariant Attributes And I got a result closer to the original location but still not the same. Here is the code: Variant Attributes.zip Run the VI: "Compare Class Database Storage Methods.vi" Any ideas what is going on? BTW: the point of the demo is to show that storing large elements in a variant database is faster if you store DVRs of the elements. This should avoid large data copies.
  17. Cool. Now what other speed improvements are lurking under the hood that we don't know of yet? It would be nice to have a list so we could re-factor our code to take advantage of them.
  18. Interesting. I just tried removing the indicators outside the frame and turning off debug and error handling. I saw no difference in the absolute speeds or the relative speed factor between the methods. I wonder why you see a difference.
  19. LV 2013 added a new function (or just exposed it) that gets the name of a class. I wanted to see if this would be faster than the old method I used before based on the path of the class. So I created a little experiment. It turns out the new functions is MUCH faster. I am concerned that what I am seeing is real, however, and not due to some compiler optimization with the way I created the experiment. So, please if you have a moment, take a look and tell me what you think. (I added code to strip the file extension because that is the use case in my application, but removing that makes little difference.) thanks, -John get class name speed test.vi ps. If you are wondering, I am using this in a logging operation of message system, so improving speed is important since every single message sent will cause this code to execute.
  20. I have that but it does not work for some reason. Still does not address my issue. (even if it did work).
  21. I have looked at that but don't see a function that does what I am trying to do. Maybe I am missing something?
  22. Does the clone class function rename the new class FP controls correctly in this version (when cloning native LVOOP classes)? I have also seen a lot of LV2013 crashes when cloning a class. Seems (anecdotally) related to having additional VIs open (not in the source class) that have broken arrows. It also does not like it if I switch to my mail program while the cloning is being performed.
  23. Has anyone come up with a way to auto-update the accessors for a control in the class private data when you change it's type or rename it? I find myself doing this a lot as I re-factor code. It means removing VIs from the project and then deleting them on disk, then building new accessors. Or, I could manually edit the accessors but that is even slower. I am just curious if anyone has created a scripting VI to automate this. thanks for any tips. -John
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.