Jump to content

Splash screens and dynamic loading


mje

Recommended Posts

I think Rammer's question is more detailed ... he asks LabVIEW to load a top-level Vi. Can he get any sort of progress information about where LV is in the load process and display a progress bar? Rammer, the answer is no, not in general.

<snip>

the last thing LabVIEW needs is to *add* load time in the dev environment when we've made good strides these last couple releases with *subtracting* it!

All you need is an "onVILoad" event that can be hooked (callback or maybe the event structure). Granted. LV may not know how many vis there are in the hierarchy before it begins. But it will be a fixed number that the developer can type in once he has stuck a counter on it.

Link to comment
AQ, most people will be making their splash screen for their own application, where the idea is to put the waiting time to the beginning rather than during the application running (loading a dynamic VI for instance).
You seem to be implying that I said otherwise. One of us misunderstood something.
As long as the end user can see that something is happening, they are usually satisfied. We do not need to make this problem more complicated than it is.
For that, all you need is a pulsing bar that never moves, and you can build that on your own. What we're talking about is a progress bar that moves forward, and that *does* need to reflect a percent to some degree. Here is what I have heard from various user experience (UX) researchers:

1) If you have a progress bar, it must move along with some reflection of the process underneath. It doesn't have to move in time, but it should strive to and it should avoid the 99%-and-hang problem, as that invalidates the whole reason for having a progress bar.

2) Progress bars only move forward. They never backup unless it is clear to the user that something is being undone (i.e. an error occurred during installation and we're backing out the previous part of the install).

3) If you cannot provide a percent progress, you should not have a progress bar. Something like the pulsing bar is better to avoid creating more frustration among users.

4) If the activity is more than a couple seconds, provide a Cancel button and make that Cancel snappy (i.e. don't take forever to cancel the operation).

LabVIEW does not follow these guidelines in many areas, but we're trying to fix some of that. If you're writing a new application, those are the guidelines I'd suggest you follow.

Link to comment

There was a progress bar question on the NI forums a couple of years ago related to the FTP functions in the Internet Toolkit.

In that case, the file to be loaded was of an exact known size, but the function that transferred the file did not expose the bytes transmitted. Brute force suggestion to the poster was to use a global. A better solution would be to add a notifier that could be monitored for each file transfer session.

Vote for it if you use FTP, but what I'm really looking for is a total rewrite of the toolkit and native support for SSH/sFTP.

For a loader, the percent progress for loading a VI hierarchy could be approximated by knowing the number of VIs to be loaded and the current number in memory. As Aristos pointed out, the 99% issue exists when the last VI to be loaded happens to be the biggest (code size or data/memory allocation size).

Link to comment

All you need is an "onVILoad" event that can be hooked (callback or maybe the event structure). Granted. LV may not know how many vis there are in the hierarchy before it begins. But it will be a fixed number that the developer can type in once he has stuck a counter on it.

Shaun, the problem with this is that events are processed in the UI thread and the Open VI Reference blocks the UI thread very effectively. The reason for that is that it needs to update various global tables frequently during the load and can't have any other part of LabVIEW potentially messing with these tables while it is busy. And unlocking the UI thread for the duration of the event is a bad idea as it would inevitably add a significant overhead to the load operation that would be without doubt noticable.

For that, all you need is a pulsing bar that never moves, and you can build that on your own.

What I do is placing an animated GIF on the Splash screen. It runs even when the VI is not executing :rolleyes: , but a user of the application doesn't notice that. However it is only a partly satisfactury solution since the GIF does animate properly in the IDE during the Open VI Reference call, but seems to stop in a built executable anyhow momentarily. I solve it by making the Main VI itself loading various components dynamically so that the load operation is really divided in several Open VI Reference operations. The Splash Screen simply has a string control that the main can send messages too, for status information, and waits until the main is deciding to open its Front Panel, indicating that it is ready to take over from now.

Vote for it if you use FTP, but what I'm really looking for is a total rewrite of the toolkit and native support for SSH/sFTP.

I don't think that suggestion is thought out well. A separate SSH protocol library is of very little use, as it only implements the SSH protocol itself but wouldn't proliferate on the used SSL capabilities for other protocols. I would rather see a SSL support for TCP sockets that can be configured transparently. I tried to start with something like this in the network library that I posted quite some time ago here on lavag. The idea is that it is possible to setup SSL parameters and register them for a network socket, so it uses them automatically. This is because SSL really is meant to be transparent in terms of protocol handling to higher located protocols like HTTPS, which is really just the HTTP protocol transferred through a SSL secured socket.

Link to comment

Shaun, the problem with this is that events are processed in the UI thread and the Open VI Reference blocks the UI thread very effectively. The reason for that is that it needs to update various global tables frequently during the load and can't have any other part of LabVIEW potentially messing with these tables while it is busy. And unlocking the UI thread for the duration of the event is a bad idea as it would inevitably add a significant overhead to the load operation that would be without doubt noticable.

User events aren't processed in the UI thread so the event case structure is capable of processing events without this limitation. I'm not sure where the "Open VI Ref" comes into it since the callback (event) would be internally generated by the LVRT and would appear as one of the default cases under <Application>. If the run-time uses the Open VI Ref internally when loading a hierarchy from disc (I high highly doubt it) then this would be moot anyway since it would mean the whole load process is already in the UI thread.

Link to comment

Like Shaun said, if you have some kind of application, once you have a callback you can slap a counter on it, then use that knowledge from then on

I'm sure you guys have thought of all of this already, but I have to ask. So events won't work. How about some sort of synchronous method, like an object that calls a virtual method, or a strict VI refnum? Granted both of those would add some overhead after each call, but I can't imagine VI hierarchies getting too big, maybe 10,000 items? What's the overhead in a dynamic dispatch call or by reference call in a loop with that many iterations? A second?

My largest app is about 2000 VIs and takes just under a minute to load. I'd gladly add a second to that for an easy to use method that allows me to track progress.

Link to comment

User events aren't processed in the UI thread so the event case structure is capable of processing events without this limitation. I'm not sure where the "Open VI Ref" comes into it since the callback (event) would be internally generated by the LVRT and would appear as one of the default cases under <Application>. If the run-time uses the Open VI Ref internally when loading a hierarchy from disc (I high highly doubt it) then this would be moot anyway since it would mean the whole load process is already in the UI thread.

It's not the Open VI Reference Node in itself that blocks out the UI thread but the load operation of a VI hierarchy. This piece of code is very delicate as it needs to update large amounts of global tables that keep track of all loaded VIs, their relationship to each other, linking information and what else that I couldn't even dream up. So yes I'm sure the Open VI Reference and the application load operation do use the same LoadVIHierarchy() function and that this function is the UI blocking culprit.

And I'm afraid calling a user VI as callback during this operation could be fairly costly. LabVIEW doesn't lock the UI thread for fun during this operation and invoking VIs may likely have a possible impact on the resources that this locking tries to protect, so that the locking may have to be released for the duration of the VI invoke. This could add up to quite a bit more than a few 100 us for each call.

Anyhow even if you get this callback that tells you about the operation, be it a user event or a specific VI invoke operation, how do you suppose to give any feedback to the user if the UI thread is blocked?

Link to comment

True that events don't occur in the UI thread, but processing them to display information would involve a context switch to the UI thread if you want to show that info.

However with a synchronous method called from a context already running in the UI thread, can that context switch be avoided?

Link to comment
It's not the Open VI Reference Node in itself that blocks out the UI thread but the load operation of a VI hierarchy. This piece of code is very delicate as it needs to update large amounts of global tables that keep track of all loaded VIs, their relationship to each other, linking information and what else that I couldn't even dream up. So yes I'm sure the Open VI Reference and the application load operation do use the same LoadVIHierarchy() function and that this function is the UI blocking culprit. And I'm afraid calling a user VI as callback during this operation could be fairly costly. LabVIEW doesn't lock the UI thread for fun during this operation and invoking VIs may likely have a possible impact on the resources that this locking tries to protect, so that the locking may have to be released for the duration of the VI invoke. This could add up to quite a bit more than a few 100 us for each call. Anyhow even if you get this callback that tells you about the operation, be it a user event or a specific VI invoke operation, how do you suppose to give any feedback to the user if the UI thread is blocked?

Send me the LabVIEW source and I'll propose something ;)

<crusade starts here>

Since, by our own admissions, we are both guessing as to what and how LabVIEW does what it does. It's a bit fruitless to put forward solutions and, to be frank, it's not our issue. All we can do is put forward "requirements" and let NI find the solutions-such is the nature of closed source!. Very difficult is not an excuse not to do something though. IF this was enabled by whatever means was required it would (I think) open up a whole host of other events that the event structure could handle and maybe we could get the overhaul that events have been crying out for for several years.

Wouldn't it be lovely.to have OnLoad, OnLoaded, OnUnload, OnPanelOpen, OnBringToFront et. al that all the other languages have? Or how about VISA events that can be wired directly to the event structure for proper event driven comms :)

<crusade ends here>

True that events don't occur in the UI thread, but processing them to display information would involve a context switch to the UI thread if you want to show that info. However with a synchronous method called from a context already running in the UI thread, can that context switch be avoided?

Indeed. There are lots of functions that have the proviso that it runs in the UI thread, not in run-time or loads panel into memory. If it is stated in the help what the limitations are, then it is up to the developer whether to utilise it or not.

Edited by ShaunR
  • Like 1
Link to comment

Wow, sorry didn't mean to generate so much chatter. I like the concept of the VI Server Splash Screen. It is easy to communicate back and forth using notifiers and message queues but if you have a large main application it seems most of the start up time is loading into memory. This leads me to two comments:

1. It would be nice to show this loading progress. This seems to be bit of a mystery. As Aristos pointed out as soon as I open the reference I see most the VI's in memory using

post-11089-0-31929900-1339773593.png

Digging in more I found:

post-11089-0-39349100-1339773435.png

So I thought, could I setup a progress bar to make sure all the main application dependencies are loaded by first checking against the loaded VI’s and if not there open a reference to it:

post-11089-0-65211300-1339773477_thumb.p

Then show the main VI:

post-11089-0-98693300-1339773417_thumb.p

This seems to pseudo work in that the splash comes up right away and the user is not left waiting and wondering what is going on. But:

2. The build process is much more complicated. If I want to keep my splash main “lean” I have to tell all the dependency VI’s to be built into the support or some other directory. Since many of these VI’s are shared amongst applications it would be nice to stuff them into a central location not in the install or build path. This is very cumbersome. So if the main VI is small this is seamless, if the main VI is more complex it seems like this becomes a pain. It would also be nice if I could specify in the build to keep the hierarchy just for certain libraries – notably classes. Right now you can keep the hierarchy for particular “Destination”. Then when you create your installer you end of having to redo all the installations because it does not seem to have a concept of the “central location” if it is not in the build path.

Link to comment

For the record, when you get a chance to look at LV 2012, there's a big shipping example that I wrote included with it that is every trick I know for putting together "a full LV application", with the exception of hooking a custom Tools >> Options dialog and a custom runtime menu (gotta give you some reason for upgrading to 2013, right?). Included in that is a splash screen that loads and starts running instantly regardless of how large the VI hierarchy gets. In that, I use an animation (it's pretty simple -- just a sequence of boolean LEDs that cycle repeatedly, meant as a placeholder for more splashy graphics you might design for your app) on the splash screen that just repeats over and over while the rest of the app loads in the background. That loading is done just by setting one of the subVIs to be "Load On First Call". For most LV developers, there aren't any surprises, but I figured it was high time there was a single reference implementation that put all the interesting tricks in one place for a "generic application X".

Once everyone gets a look at it, I expect a substantial amount of feedback (positive and negative, I hope) that can feedback into it for future development. I'll post more about it when LV 2012 is public.

  • Like 2
Link to comment

Once everyone gets a look at it, I expect a substantial amount of feedback

Do we have to wait until we see it to give feedback?

One thing I *hope* it does is identify what lessons people should take from the example. There appears to be a common perception that examples show the "right" way to do a particular task instead of "a" way to do the task.

  • Like 2
Link to comment

Is there ever a "right way"?

Sure, and there may even be multiple right ways, but knowing whether a solution is right or not depends on a whole host of application and business requirements that are not specified in the example. I run into this problem any time I use examples to learn a new api or software technology. Sometimes I can easily see how to correctly apply the example to my project; other times I can't. Perhaps a better way to phrase my request is:

Include comments explaining why a particular implementation is used, where it is applicable (and not applicable,) and what the tradeoffs are versus other solutions.

That's a tall order and complete documentation could probably fill a book, but I hope there is at least an attempt to include that information.

I learned from my wife years ago that there is "her way" and the "wrong way".

My favorite is when I'm starting to pull into a parking space and my wife will say, "there's a spot over there." She doesn't do it anymore--we've been married 20 years--but the first 10 years or so she would do that all the time. Now we joke about it.

Another one she used to do is tell me how to load the dishwasher. She learned when she gets too critical of how I do things I quit doing them. Her solution was to stop telling me how to do it and just rearrange the dishes after I'm done. :rolleyes:

  • Like 1
Link to comment

Any comments on the property that I am using to get the dependencies? Is it valid?

Well it's not invalid, but doesn't really do what you want directly. In order for the method to be executed on a VI you have to open a VI reference to it, so the entire VI hierarchy is already loaded and iterating through the list to open a VI reference to it does not really do anything useful anymore as the VI is already in memory.

What you would have to do, is at built time, determine your hierarchy, sort that hierarchy in ascending order from lowest level VI to higher VI, possibly suppressing some of the lowest level VIs altogether and then save that information to a configuration file that your executable reads and starts doing the loading of the VIs from bottom up.After each Open VI Reference VI you would get more VI's loaded into memory and could use the percentage of already loaded VIs to the total amount of VIs for your progress bar. But executing your Get VI Hierarchy method node in your executable will cause the progress bar to stall while LabVIEW opens the Top level VI and then VERY quickly go through the Open VI References since it doesn't really need to do much anymore, but find the already loaded VI somewhere in memory.

Link to comment

Rammer: I already posted the description of what I did earlier -- there's really nothing more to it than that. Because load time is completely unknowable, I went with a "I'm still alive" animation instead of a progress bar.

Rolfk is spot on when he describes the problem with your proposed approach.

Link to comment

Rammer: I already posted the description of what I did earlier -- there's really nothing more to it than that. Because load time is completely unknowable, I went with a "I'm still alive" animation instead of a progress bar.

Rolfk is spot on when he describes the problem with your proposed approach.

The load time is only unknown the first time you launch the application... if you store the load time you will display a proper progress bar the next time ;-)

Link to comment

The load time is only unknown the first time you launch the application... if you store the load time you will display a proper progress bar the next time ;-)

Unless your system changed in the meantime. :D Windows Update anyone? A new driver installation? A harddisk cleanup or replacement?

I mean a solution like that is probably ok for your specific private application, but definitely not an option for an NI supplied example, which is supposed to do the "right"TM thing.

Link to comment

Unless your system changed in the meantime. :D Windows Update anyone? A new driver installation? A harddisk cleanup or replacement?

I mean a solution like that is probably ok for your specific private application, but definitely not an option for an NI supplied example, which is supposed to do the "right"TM thing.

Can't really understand why this solution should be uniuqe for my private application? If the "splash screen" measures the time to load the main application and stores it every time, it will be quite accurate, even after driver/windows updates. The problem, which have been stated before, is to update the progress during loading.

Link to comment

Load time is most definitely NOT consistent time over time. We have an entire bank of machines to judge LabVIEW launch time every night. 30 identical Windows machines. They do not have consistent launch times between the machines. Launch times change radically on the same machine between the first launch after reboot and the second. Over several nights, they change depending upon how Windows has decided to optimize the caching behind the scenes (there's some sort of most recently used algorithm). Running a disk optimizer can radically change launch time. We take the average of these launch times for judging whether we have made any changes that impact launch time.

I don't believe your solution is viable based on LV's empiric experience. This applies not just to LV and things written in LV but to all EXEs on a modern non-deterministic operating system.

Link to comment

Load time is most definitely NOT consistent time over time. We have an entire bank of machines to judge LabVIEW launch time every night. 30 identical Windows machines. They do not have consistent launch times between the machines. Launch times change radically on the same machine between the first launch after reboot and the second. Over several nights, they change depending upon how Windows has decided to optimize the caching behind the scenes (there's some sort of most recently used algorithm). Running a disk optimizer can radically change launch time. We take the average of these launch times for judging whether we have made any changes that impact launch time.

I don't believe your solution is viable based on LV's empiric experience. This applies not just to LV and things written in LV but to all EXEs on a modern non-deterministic operating system.

I didn't think of that ;-)

Measuring the launch time is probably a bad idea as you said. Seemed like a simple solution in the beginning though...

Link to comment
  • 2 weeks later...
Seemed like a simple solution in the beginning though...
I know. Lots of things in the "load progress bar" project seemed like a simple, obvious solution. After six months of brainstorming and prototypes from members of the LV team, I'm now in the "there is no good solution so stop trying to force one" camp. :-)
Link to comment
  • 5 months later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

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