Jump to content

LAVA 1.0 Content

Members
  • Posts

    2,739
  • Joined

  • Last visited

  • Days Won

    1

Everything posted by LAVA 1.0 Content

  1. Related to the topic. Does anyone know if someone has written a subversion API for LabVIEW. Subversion has a C API which allows directly integrating your application to SVN repository. I'd like to use a LabVIEW application to directly communicate with SVN and I wonder if I have to write the LabVIEW version of the API myself...
  2. Next time say, "Yeah... Sweeeeet! it's my DAD's card... I'm with the Spazmatics"
  3. Action Engine, Action Engine, Action Engine ... Whoo Whoooo! (Read "I Think I Can, I Think I Can, I Think I Can,")
  4. I tried the suggested implementation and ran some tests this morning. I placed a case statement around my enqueue code, and used a boolean to select the case. I start three instances of this receiver, as well as three instances of my logger and three of my UI (receives the Notifier data) What I observed is that the CPU utilization was higher when using the Get Queue Status method you suggested. For three channels, my implementation runs ~ 24%. The Get Queue Status method averaged 32%+. It appears that the Get Queue Status function requires more CPU resources than forking the data does. The data (TCP string) never leaves the loop; it is passed unmodified to the Queue and Notifier. My Queue is grossly oversized (72,000 elements), so I should never get a "full queue" at this point. The data messages are 128 bytes long. The logger flushes the queue once a second, and the data is arriving at the TCP port @ ~ 1kHz right now. The Notifier is sent at 1000/20 or ~20 Hz. The thing that bothered me the most was that while using the Get Queue Status technique, I saw the strip chart in my UI plot Nulls for a second (as designed). That is, the Notifier did not fire (waits 200 ms for timeout) for multiple data points. I'm playing back a binary file, and part of my validation is to check that the original and logged binary files are identical. The Log file was missing data! (the first time I've seen this in months). I moved the Get Queue Status outside the case statements and placed it inside the same loop as the TCP Receive, hoping that LabVIEW could "clump" the operations better. My CPU utilization raised to an average of almost 50%, but I did not experience data loss. What could have caused the queue to "block" or "freeze"? Could the Get Queue Status function have blocked during a Flush Queue Operation in my Logger? The delay was long enough that the Windows TCP buffer overfilled by the time I came around to read again...
  5. I think functional globals is a very poor term, because functional in context of programming languages refers to functional programming. If we will call these globals functional, it will cause problems in the future as functional programming will probably be adopted to main stream programming languages.
  6. Ok. This is however smaller of the two performance issues I brought up. The issue related to loading all related classes and methods to memory is the most serious problem. More serious than anything I have complained this far.
  7. I never look at the terminal names, I ALWAYS use the icon... It FLOORS me every time I do look at the names
  8. 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-
  9. 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.
  10. 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?
  11. 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.
  12. I just found out that these diagrams are called "UML state machine diagrams" in UML 2. //Lars-G
  13. 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.
  14. 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 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)
  15. :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. 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.....
  16. 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. 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.
  17. I suggest that we move this discussion to a new topic that I created. This discussion is not related Invoke node problems but to large scale application design using LVOOP.
  18. 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.
  19. 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? Good 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!
  20. 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" This is about making the queues easy and fast, not about " ways to skin the cat".... 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... 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:
  21. Hi all! Does anyone have experience of using UML Statechart Diagrams? It seems to me (haven't used it though) that it has the potential of really helping you structure your code. Perhaps we could ask NI for a tool that automates the translation of UML Statechart Diagrams into G code. //Lars-G
  22. 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:
  23. 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.
  24. 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:
  25. 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.
×
×
  • Create New...

Important Information

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