Jump to content

LAVA 1.0 Content

Members
  • Posts

    2,739
  • Joined

  • Last visited

  • Days Won

    1

Posts posted by LAVA 1.0 Content

  1. Hi,

    I've project for subVI library in user.lib directory which is written with LabVIEW 8.0. I'd like to keep LabVIEW 8.0 as the main development environment for this toolkit but I'd also like to use the toolkit with LabVIEW 8.2. The problem I have is that if I just copy all the project files to user.lib directory under LabVIEW 8.2 directory and recomplie VIs, the recompilation also recompiles some files under my LabVIEW 8.0 user.lib and the project won't work under LabVIEW 8.0 any more.

    My project contains several libraries (lvlib), several hundreds of VIs within these libraries, some tools for internal use outside these libraries, some DLLs, multiple mnu files, help files, html files, build specifications etc. All of the files are managed using LabVIEW project.

    Any help how to properly move a project under user.lib to newer LabVIEW version...

    -jimi-

  2. I give you some numeric background of the problems I have encountered. I have a project that contains two libraries. Each library contains six classes and about 500 methods. I have one top-level VI that uses about ten methods, the rest of the methods are not currently used. Theoretically about 20 methods are required at run-time to be able to run the main VI and call correct dynamically dispatchable methods.

    Whe I open the project containing the main VI and the two libraries on my laptop (Pentium M 1.6 Ghz with 1GB memory running Windows XP SP 2) it takes five minutes to open the project. After having opened the project LabVIEW consumes a little over 100MB memory according to task manager. This means that if I would add a few more libraries to my project, I would reach the limits of the system.

    If one considers a normal OOP project on mainstream programming languages, a common project may use several dozens of modules corresponding to LabVIEW libraries. Each module may contain up to several hundreds of classes and easily several thousand of VIs. From these modules developer perhaps really uses up to several hundred different classes and several thousand methods. To open such a project on LabVIEW 8.20 would require loading about 100 000 methods to memory. This would require system resources exceeding those available on personal workstations in next five years. I really think this is a huge problem. Something really needs to be done to fix the issue.

    Edit: More statistics. I moved support for unnecessary data types and reduced the time to load my project to 2 minutes and 50 seconds. I however noticed another annoying thing. It takes 30 seconds after I press run button for my main VI to start actually running. According to profiler it actually runs for 0.01 seconds, so the rest of the time LabVIEW is doing some internal tasks... I verified that this is actually the case by placing some probes on the diagram to follow the execution. The first class constant was initialized after thirty seconds.

  3. I have not be able to create a (simple) VI to generate the error, but sometimes I have an error 91 or -1967362020 when I try to read a shared variable from inside a LVOOP class method.

    I don't think that the bus is in my code because the error 91 description is "The data type of the variant is not compatible with the data type wired to the type input." and I do not use "variant to data", just read from a shared variable. And the error -1967362020 description is "The provided refnum is invalid." and I do not know what it has to do with shared variables.

    The erros appear just after the shared variable node.

    Just curious, do you store an object or any structure containing an object to the shared variable, read the variable and try to call dynamic method to this object stored in shared variable?

  4. I need to create a LV app that will talk with other LV apps on several machines in our network.

    I think the best option is to Open Application Reference from LabVIEW instance that needs to make a request to remote LabVIEW instance that servers the request. Then you can use open VI reference to open reference to remote VI. After this you can call this remote VI using call by reference node . You can practically use remote LabVIEW almost as if it was local. Simple and clever. Shared variables are not appropriate for this kind of request-respond type communication. All your other alternatives are just much more complicated than directly calling remote VIs.

    When LabVIEW starts, it starts a LabVIEW application server. This server listens to certain TCP port on the computer. The above mentioned requests are sent to this TCP port. When you build your LabVIEW application to executable or dll, a INI file is created. You can modify this INI file to define which TCP port the application server for that specific executable listens. The INI file is expected to be at the same directory as the executable. You can also modify the LabVIEW application server default TCP port somewhere from the LabVIEW options.

    To be able to access the remote application, you must open the application server TCP port from you remote machine to accept remote connections. You must also allow remote connections from you local machine to this TCP port, although I this normally allowed by default at least if you use Windows XP built-in firewall.

    Edit: BTW, you specify the application instance with IP-address and TCP port of the application server. You should therefore get fixed IP-address for each of your LabVIEW servers.

  5. Hey everyone,

    I am building a software application with a bunch of different classes. One class is entitiled 'File Settings', it handles all of the path information. Another class is called 'Communications'. In the inheritance tree Communications has two classes below it (one of which is 'File Settings'). In a method of 'Communications' I am trying to unbundle the 'File Settings' data to use in writing a configuration file for communicatins. When I try to wire the 'File Settings' object to the unbundle by name function, it says "Neither bundle or unbundle of this Labview class is allowed on this VI".

    Any reasons as to why?? I thought any classes below the 'Communcations' class would be able to share their private data and methods!

    You can only bundle the wire in a method of a class that owns the private data (that's why it's called private data cluster in LabVIEW). Decendents can access the private data only trough ancestor protected or public class methods. All other VIs and other classes can access the private data only trough owning class public methods. So you need to write protected or public methods like getSomething and setSomething to modify the private data of the class outside the class. However it's often more convenient to include the required logic to the class methods instead of just getting and setting the data and using logic outside the class. But it's always case dependent.

  6. I was thinking about whether replacing this approach with queues would be beneficial, and here's what I'm still not sure about:

    From what I can tell, you can only dequeue the same datatype that you enqueue. I would have assumed that if I enqueue a scalar in the form of an array of length = 1, then dequeue the array, it would have given me the whole contents of the queue, but this wasn't the case. I also don't see any sort of way of saying "dequeue the last N queued elements".

    Therefore, ff I wanted to use queues for this type of data transfer, I would have to put the Dequeue, along with Get Queue status, in a while loop and run it until the queue is empty. Is that correct? If so, can that really be more efficient than what I'm doing now?

    Well, after professing to having spent the last year learning these things, I'll try to answer.

    "From what I can tell, you can only dequeue the same datatype that you enqueue."

    In a strict sense, the answer is "True". In order to create a queue (Obtain Queue) you must provide a data type. This can be as basic as a scalar, our a as complex as a cluster of clusters. You may have noticed my :angry: emoticon when I mentioned variants. I actually answered a question in another thread about the ADVANTAGES of using variants (here). So, you catually can enqueue different data types, but you have to know what to do with it when you dequeue it.

    "Therefore, ff I wanted to use queues for this type of data transfer, I would have to put the Dequeue, along with Get Queue status, in a while loop and run it until the queue is empty."

    There is a nice function called "Flush Queue" This will return all of the available elements from the Queue, and empty it. This is how I log my data to disk. I take the array of TCP strings and write them to a binary file.

    The real gain in using a Queue over a LV2 (Functional) Global is that in order for the Functional Global to store data, it must 'block'. That is, while you are replacing elements in the global, the reader must wait. If it wasn't 'blocking' (if the Functional Global was re-entrant) it couldn't store data in it's internal shift registers.

    The underlying LabVIEW implimentation of the queue is a circular buffer with multiple pointers. Enqueue Element can be writing to one position in the internal array while Dequeue Element function can be extracting a different element, and the Queue management code updates the pointers.

    The discussion about 'lossy queues' doesn't really matter much as long as you can dequeue data faster than you can enqueue it. You might say How? Disk I/O is a slow operation. Bulk writes of 1000 strings is more effecient than 1000 individual writes.

    There is one issue where you can only Dequeue Element or Flush Queue. There is no provision for dequeueing N elements; you must put that in a loop. I may be wrong, but I think the Enqueue Element function is actually polymorphic; you can provide a single element, or an array of elements of the type specified when the Queue was obtained.

    As Ben stated and I have observed, the Queues should prove to be faster than any LV2 Functional Global you can wire up.

    Hope I answered your question(s) :)

  7. The Queue Status primitive generates no code for any terminal that is unwired. So if you do not wire the "Elements Out" it will not duplicate the contents of the queue, nor will it take the time to evaluate any of the unwired terminals. Fetching the current element count is very fast, and this avoids ever forking your data wire. Forking the wire is a big deal since if the wire is forked it prevents the Enqueue from taking advantage of one of its biggest speed optimizations and it guarantees a copy of the data will be made at the fork.

    :thumbup: Generates no code for unwired terminals is great news! This is something I was unaware of; I've generally avoided using "Get Queue Status" (think polling :( ). I'll definitely look at and test your suggestion.

    Just a thought... I'm downplaying the possibilities (of using the LabVIEW classes) here since I've lately been accused of suggesting LV classes as *the* silver bullet for all of LV's problems.

    You know LVOOP and it's possibliities as well or better than anyone. If it offers a better, faster or more robust solution to a problem, then let us know! As that old Texan sayin' goes: "It ain't Braggin'"--if it's true!

    I haven't seriously played with classes yet, but I enjoy reading the 'spirited' discussions on LAVA and Info-LABVIEW. I've spent the last year digging into multithreading, queues, notifiers and Preferred Exection Thread. I look forward to learing LVOOP and adding it to my programming arsenal. I think LVOOP needs a first "real world" example that people could use. Most of the discussions seem more academic to me. I don't care where it might be a problem, show me what it can do!

    I've been thinking of a twist on the "Getting Started" example. How about adapting it to be a Toolbar class that could be reused by every-day LabVIEW users (like me); maybe placed in their own UI as a subpanel or in a pane? Just thinking.....

  8. The discussion under topic AddItem method doesn't work if class belongs were going too much off topic so I decided to start a new topic here. I first refer the previous discussion here and the go on the discussion in my next post.

    Opening a project simply opens a file listing. It does not load all the VIs into memory (the project is designed to be a manager for very large projects where you might not want all the VIs in memory simultaneously). The same is true for a library -- .lvlib files do not load all their VIs into memory.
    This distinction between class and library explains why my library of hundreds of subVIs worked very well as a conventional subVI library. Now I have encapsulated the same behaviour into a class hierarchy which also includes several hundreds VIs and LabVIEW seems to freeze when I open the project containing the class structure. If I understand you correctly opening the project should not open the classes within the project, but... it still takes a very long time to load the project.
    Actually, I think Aristos was a little ambiguous. loading projects do load some "referenced files". They will load their libraries. For regular project libraries, this means it will not load any of their VIs, but for classes and XControls, it will load VIs/CTLs/sublibraries/parent classes/etc. that belong to them. That is why probably why loading your project takes a such a long time. Those VIs are all being brought into memory.

    Unfortunately, this behavior actually is expected, though we realize it is not ideal. Aristos can explain better than I why this is necessary.

    I'm quite worried about the issue that arise from the previous discussion. It seems that there may be some serious problems related to large scale projects using LabVOOP. As far as I understood correctly, all of the class methods are loaded into memory when a project containing the class is loaded.

    In modular software development, classes are often packed together into libraries and also LabVIEW encourages this behaviour. Libraries are then used as modules to include some needed functionality to the project. This is done by including the library to the project. One may need functionality present in several libraries. As a result developer may need to include quite many libraries to his project. Including all the module doesn't mean that all the methods are actually used in the project. It's quite often the case that only a few methods are actually used from each class library. Now it seems that LabVIEW loads all the methods of all the classes of all the libraries to memory when the project is opened. It also loads all the methods and subVIs referenced in these methods.

    As a result, even quite simple projects may require loading several thousands of VIs to memory before the project explorer can even open. I see this as a extremely severe problem that will plenty of difficulties for most LAVA users in the future if the behaviour is not fixed.

    Currently I have a project that doesn't open at all any more. Well it could open if I waited long enough, currently I have got tired of waiting after two hours of LabVIEW loading project components. This behaviour was a result of including a polymorphic VI containing several hundreds of reentrant VIs to several hundreds of dynamic methods. Each dynamic methods was used by static method. Several hundred of these static methods were then added to polymorphic VI. Well, this is a dead-end because it requires probably creating thousands of copies of the reentrant subVIs to memory even before the project containing the class can even open.

  9. That's correct. Opening a project simply opens a file listing. It does not load all the VIs into memory (the project is designed to be a manager for very large projects where you might not want all the VIs in memory simultaneously). The same is true for a library -- .lvlib files do not load all their VIs into memory. .xctrl and .lvclass files do load all their member VIs into memory.

    This distinction between class and library explains why my library of hundreds of subVIs worked very well as a conventional subVI library. Now I have encapsulated the same behaviour into a class hierarchy which also includes several hundreds VIs and LabVIEW seems to freeze when I open the project containing the class structure. If I understand you correctly opening the project should not open the classes within the project, but... it still takes a very long time to load the project. Well, I figure out something.

    So as a summary I can create huge projects containing conventional VIs, but the same is not (currently) true for OOP projects.

  10. If you don't have one or two top level VIs that will load everything, you can write a quick VI Server routine to load all the VIs in a directory. Once everyone is in memory, use the ctrl+shift+click on run arrow that I mentioned before.

    Thanks a lot for your help! I'll try the trick after my mass compile finnishes, LV has been compiling my project for a little over four hours now. I still verify that aren't the VIs in memory when I open a project containing them? So I still explicitly need to open a reference for each VI, method VI, control, polymorphic VI, library, class and VI template in my project and after that do the ctrl+shift+click trick?

    None of this, by the way, is correct expected behavior.

    Good :D I eagerly wait for the maintenance release 8.2.1... and most probably also for the maintenance release 8.2.2 ;)

    Honestly Aristos, I very much appreciate your active presence here at LAVA forums and your ever lasting strength to help us with problems related to these new LabVIEW 8.20 features!

  11. The trouble with writing little wrappers that accomplish something similar using queues is the need to keep re-writing them for different datatypes as the need arises. Besides, the code to retrieve the most recent 1024 samples in a size 16384 buffer seems pretty clunky using queues.

    Exactly! :thumbup: Lossy Queues would eliminate this. How much extra code and CPU overhead does the current solution involve (enqueue, timeout, eval timeout, dequeue element, enqueue element)? If the Queue was defined as lossy, then it would only need to move the pointer internally +1 and store the data. The Queue must have pointers defined internally that determine the Start and End of data indexes to perform a flush; so the Late? flag would be true when End and Start are adjacent.

    A "# of Elements" input to Dequeue Element would make 1 call to the underlying Queue, rather than 1024 dequeues while trying to simultaneously load the queue at a high rate.

    How about a block size input to Obtain Queue with a corresponding Notifier output? The Notifier would be triggered from within the queue each time a complete block was available. The Notifier would contain the index to the block. A Dequeue Block function would return the requested block.

    And please, don't bring up "Use a variant data type, then you can write generic wrappers" :angry: This is about making the queues easy and fast, not about " ways to skin the cat"....

    I’m betting on the queue to win. Ever since the queue data type could be defined, it has blown away any LV2 I can develop,

    Queues are proven to be more efficient, I'm just hoping to get the most out of them. I feel as if I'm tacking CB antennas, bumper protectors, and deer whistles onto a Ferrari... :P

    If you go over 50% or show spikes or data drop after a reasonable test run time, then you may want to think about architectural changes.

    As a quick note, I did see some serious CPU spikes (> 80%) while monitoring CPU load for multiple channels at higher rates. Using Windows Performance Monitor I determined that the spikes coincided with disk I/O. It appears that Windows was buffering large amounts of data before flushing it.

    I added a LabVIEW "Flush File" after every 8th "Flush Queue / Write to Binary File" loop. My CPU load went almost flat, even for three channels. The interval may need to change as my data rates or message size increase...

    It might have something to do with the RAID disk controller, or some Windows "Delayed Write" setting somewhere, but I was able to manage it from LabVIEW directly, and the problem wasn't related to queues.... :thumbup:

  12. Jimi: Try loading your project into memory, get all your VIs into memory (by opening the FP of all your top-level VIs) and then do ctrl+shift+click on the run arrow. This will force a recompile of all VIs in memory. I'm tracking a bug where you make an edit to the class' private data control and save the change. We recompile all the VIs that bundle/unbundle the class. Then you exit LV without saving all the VIs. When you next load, we don't seem to be noticing that the types are out of date and so we aren't recompiling the bundle/unbundle VIs automatically. So they have stale memory addresses and may crash when run. Forcing a recompile of all the VIs in memory catches these guys and brings them up-to-date.

    This was reported to R&D (# 40667H1W) for further investigation.

    About your proposal, I'm writing currently a toolkit which doesn't have any main level VIs. It only contains classes and subVIs used by the classes. There are hundreds of methods and hundreds of subVIs used or referenced in the project. Is there any easy way to force updating the links with no main VIs?

    I manually forced LabVIEW to mass compile the project a few hours ago, before your proposal. It's still mass compiling although I think it's close to the end now (592 VIs loaded). There are between 500-1000 VIs referenced in the project so compiling process seems to be quite sticky.

    I ended up mass compiling since I couldn't start LabVIEW anymore. One of the class probes, Icon Probe of my Class Iconizer project also published here at LAVA, located under user.lib started to load all of the VIs of all other projects under user.lib to memory at LabVIEW startup. I got tired of waiting more than 30 min to get LabVIEW even started. I don't know why this happened. The reason must be realted to the fact that yesterday I added hundres of method VIs for operating different data types to my main project which was also located under user.lib. The Icon Probe was not part of this project, the only relation was that both projects were under user.lib. This Icon Probe doesn't in any way reference any of the classes or VIs it was loading at LabVIEW start up. So I moved all my projects to another directory, and LabVIEW started with normal speed. However the links to actual files in the moved projects were now broken. I fixed the links by manually browsing each and every file that wasn't contained in a library or a class. Libraries and classes seemed to have stayed intact. Because I wasn't very trusting in LabVIEWs ability to update links, I decided to mass compile all the files in my most important project. So slow and frustrating. :headbang:

  13. Also, another person implied that variants are an alternative to passing data by wire. How?

    I think the idea was that variants allow you to create a general purpose messaging system.

    You define a Queue or Notifier using a typdef cluster consisting of an string or enum that represents a command and a variant as the data. You bundle your command and data and Enqueue Element or Send Notification in your originating vi. Your receiving vi has a loop that performs Dequeue Element or Wait on Notifier.

    The nice thing is that you can unbundle and evaluate the string or enum to determine how to convert the included variant data back to it's native type; typically using the string/enum as an input to a Case structure. You can do this with a single queue or notifier because the data is a variant type. The use of Queues or Notifiers is the "alternative to passing by wire" part.

    You can use this technique to send a message from a low level vi up to your UI. A single Queue/Notifier can set a boolean from one sub-vi that sets a front panel LED, while another sub-vi can use the same Queue/Notifier to pass a Double used as a value of a gauge.

  14. I guess I'd suggest starting as simply as possible, like I did, get it working, and then build it up, checking to make sure it still works with each addition.

    The error is not generated by LVClass.Open but by LVClassLibrary.AddItem - therefore the error code is also related to this. The reference returned by open seems to be valid at least according to built-in probe. The error occurs only if the class is part of a library, for example MyLib.lvlib:MyClass.lvclass. If you create a class that is not part of library, then there is no error. I also tried to get the reference interactively from an active project browser, by checking the which items were selected and getting reference to these items. The same error occurs.

    Edit: Robbie Gehbauer, I noticed it's your first post. Welcome to LAVA! :)

    Edit 2: I created a dummy project and was unable to repeat the problem in this project. So it seems the error is somehow related to my real work project. I cannot post my project here since it is non-public. I have got LabVIEW 8.2 to crash so many times that I may very well be that the project is somehow corrupted, even though it seems to be functional. Any ideas how to fix a corrupted project. I cannot go back to non-corrupted backup since I have no idea when the corruption has occurred. I also have no wish to code everything again. I cannot use "Save as" for my libraries since this is the easiest way to get everything meshed up and to get LabVIEW to crash. This is a problem that never occurs in text based programming languages.... :question:

  15. You use the phrase "dynamically creating instances of a class."

    Do you mean

    B) "Are there any other possibilities for dynamically loading a class definition into memory and then creating data of that class type?"

    If the answer is B:

    Yes, there is another way to achieve dynamic loading of classes into memory, without the enum suggestion.

    Any VI that uses a class will load that class into memory. You can use VI Server to load a VI into memory even in a built application. SO....

    1. Create your classes. Let's call them Alpha, Beta and Gamma. These classes do not have to be related.
    2. Add a method named DefaultValue.vi to each of these three. This VI should have no inputs and its only output should be of type LabVIEW Object (or, if there is an inheritance relationship among your classes, any class that is a common parent to all three classes).
    3. On the block diagram of these classes, drop a constant of the class type and connect it to the output FP Terminal.
    4. Your Factory code should be changed now to use Open VI Reference. Instead of loading a class directly, it will load any of the DefaultValue.vi versions. Use a Call By Reference node to invoke the VI and get the data instance of the newly loaded class.

    I don't think there is much idea in just creating this kind of dynamic factory for general LabVIEW objects since general LabVIEW objects cannot share any methods. You end up in a wire of LabVIEW object but you cannot call any methods since general LabVIEW object doesn't have any methods. So the wire only passes private data you cannot access. The only thing you can do is really flatten it to string and store the flattened object to a file or send it to network.

    There is much more logic if you create a parent class for all your possible classes which defines at least some dynamic methods and are dispatched to the correct class when called. You probably want a getType method to retrieve the type (class) of the object. Then depending on your application you probably want also some other methods; your application must use the objects somehow and you must write common interface (i.e. parent class dynamic methods) for all your classes so that your application can use these objects at all.

    I also think it's better idea to dynamically (call by reference node) call a VI that not only returns an object but also initializes the object so that the object really represents something (of course your objects may not need initialization, but often they do). You pass same initialization parameters for all of these dynamically called VIs and each of these VIs takes care of initializating one class type based on the parameters you pass to it.

    To create different types of objects, you must select at runtime which of these VIs you call. You pass this VI information required for the VI to initialize your class object. The VI takes care of the object initialization and returns an object of your parent object type. The parent object is ancestor of all your possible objects and which defines the method interface that all your objects share (i.e. all your objects have common methods with same name and same connector pane but different functionality). Then you use the created object by calling these inteface methods. Each interface method is dynamically dispatched to the correct class type method automatically.

    p.s. I didn't read all of the thread, so I'm sorry if I misunderstood your coding problematics.

  16. I kept PJM's original code, adding the following:

    Attaching generated instances to the new polymorphic VI

    If selected control is an array, the element data is replaced (not the entire array)

    Download File:post-1519-1156806400.llb

    Nice work :worship: Polymorphism over array dimensions (from scalars to N-dimensional arrays) combined with different data types is still on my wish list. As an example:

    DBL scalar, SGL scalar, Bool scalar

    DBL 1d, SGL 1d, Bool 1d

    DBL 2d, SGL 2d, Bool 2d

    ...

    DBL Nd, SGL Nd, Bool Nd

    If I ever have extra time, I'll modify to code or write a tool to include polymorphism over both type and dimension.

    Tip: Today I needed to create polymorphic dynamic LVOOP methods. This requires to create first a number of dynamic methods (one for each polymorphic type), then create for each dynamic method a static method that calls the dynamic method. In the end the static methods can be added to polymorphic VI. When the polymorphic VI is called, it first calls static VI of correct type, which then calls dynamic VI of the same type which is dynamically dispatched to the correct decendent class. Complicated but it works...

  17. This has occurred to me a few times. If I add an empty polymorphic VI template (.vit) to a class that belongs to a library, everything seems to be fine at first glance. Later on it may occur, that LabVIEW spontanously decides that the class is broken, because it includes a polymorphic VI (the .vit template) that is not executable due to the fact that it contains no VIs (it's empty). LabVIEW behaviour is not consistent here, since it allows adding the template without breaking the class.

  18. Hi,

    I've the following problem, can does anybody know a way around. I try to programmatically add an empty folder to LabVIEW class and then fill the folder with a number of methods.

    I open a class by path to lvclass file using LVClass.Open method of Application class. I then try to create an empty folder to the class using LVClassLibrary.AddItem method. I wire "Folder" as a type, empty path as a path and some name as a name. Everything works fine if the class I'm operating isn't inside another library. However, if the class belongs to a containing library, then I get an error message: Error 1055 occurred at invoke node, "LabVIEW: Object reference is invalid." The error is generated by the LVClassLibrary.AddItem invoke node. What do I do wrong?

    post-4014-1158147870.png?width=400

    p.s. Please do not move this topic to scripting, at least not before LV developers have had some time to answer... :rolleyes:

×
×
  • Create New...

Important Information

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