Jump to content

Help talk me into or out of this hack: a new conditional disable symbol


Recommended Posts

The TL;DR is in bold.

I want to add to the Conditional Disable structure a new built-in symbol that toggles when the VI's "Debug Enabled" setting is toggled.
I've wanted this for a long time, but I finally got around to opening up the code to see what's possible.

Let me take care of one question right away: I have no idea what version of LabVIEW this might or might not go into. So don't get excited. :-)

Anyway... it turns out, what I'd like to do isn't straightforward. All existing conditional disable symbols are global to the application instance. The three built-in symbols -- bitness, target, and run-time engine -- are universal to the running environment. The symbols that users can define are in the project and target. In other words, if I want to know the value of any symbol, I just need the reference to the application instance, not to a particular VI. And, guess what, all the C++ code is therefore oriented around application refnums not VI refnums. *sigh*

Now, it turns out that I can see a way to add the debug-enabled flag in a sort of sideways manner, and I would just hardcode that symbol as a special case in some parts of the code.

RED FLAG! Alert! Developer has used the phrase "special case"!

One of my colleagues likes to refer to the "0, 1, Infinity Rule". That is, there are either zero cases of something, one case of something, or an infinite cases of something. There's never just 2. Or 3. Or any other finite number. Basically, as soon as you are prepping the second special case, your code needs to be architected to accept an infinite number of such special cases because otherwise, you're going to build up a huge number of unmaintainable hacks over time. If there really is just one special case, then the code generally remains maintainable. One special case isn't a hack... it's just the special case of the problem you're code is solving. The second special case is a hack.

I try to avoid hacking up the LV code base and developing more stuff that needs refactoring in the long-term, so I'm hesitating about working on this feature. With this in mind, I went to a couple of other dev and asked a question, and I want to ask the LAVA community the same question:

Besides "enable debugging," are there any other VI-specific settings that would cause you to want to change the actual code compiled into the block diagram?

I honestly cannot think of any. Reentrancy? I don't typically change the reentrancy of a VI on a regular basis. A VI is either designed to be reentrant or not... flipping that switch usually changes how the node is used entirely. Thread affinity? I can't think of any VI where I have ever wanted to sometimes have the VI in UI thread and sometimes have it in Exec System One, and where I wanted different code in those cases. No one else I've asked has been able to come up with any scenarios for that sort of thing either. Oh, the hypothetical COULD exist, but hypothetically, I could want the font on all my numeric controls to become italic whenever the VI is set to "run when opened". It ain't a real use case. :-)

One person suggested that there might not be VI-property-related settings that would want to change out code on the diagram, but maybe there is a case for user-defined symbols at the VI level? Maybe. But, honestly, the Diagram Disable structure pretty much covers the "I want to change out the behavior of this VI". Yes, we all know cases where we have code on the left half of the screen and code on the right-half of the screen, and we need a separate disable structure around those regions... but that's just as probable as having that right-side of the screen dropped into a subVI. The setting then is not a per-VI setting, but it is either a per-project setting (which we have today) or a per-library setting... and that I can easily imagine a use case for. Having a per-VI user-defined setting just seems problematic if you dropped the code into a subVI and lost the link between those two VIs. I hate adding any feature that discourages people from creating subVIs as needed! So I'm rejecting that use case. And the library use case, while a good one, is outside the scope of what I'm asking about today. Go put it on the Idea Exchange if you want to promote it. :-)

Which brings me back to the "debug enabled" setting. That setting can be programmatically toggled when doing a build (if you go into the custom per-item settings because NI doesn't have an easy single-checkbox for you) and frequently we do things while debugging that would just slow down a release build. Which means it makes sense to write code into the VI that could be either compiled in or compiled out based on the VI's debug settting, unlike any of the other settings.

So... brainstorms anyone? And please be honest. Even if you want this specific feature, and you think, "Well, if I present this valid use case, it means he won't put in his hack, so I'm cutting my own throat," trust me... for the long-haul, you'd rather LV develop as cleanly as possible, for the sake of your own trust in it!

  • Like 1
Link to comment

Whats the original use case for this? Unless I missed it you start with "I want this" and move on from there. Maybe I'm in the minority but I don't see a use case for this at all. I definitely don't see a infinity use case.

If I were in charge of your time, and devoted it so a similar set of features, I'd instead prioritize:

  • Universal debugging checkbox which automatically turns on or off an app-level conditional symbol
  • Per-build conditional symbols
Edited by smithd
Link to comment

smithd:

I frequently have code in the block diagram to assert X is true or to log information to a file while running. I don't want any of that code in the final product. Right now, it's a major pain to turn it on or off. I toggle debugging on and off all the time.

A universal debugging symbol would not be useful for me most of the time. I don't want to turn on debugging for every VI I use in my own code -- at best it is a per-library setting when I need to debug into subsystem X. This crops up even in deployed code situations. For example, there's an existing conditional disable structure in the Actor Framework code. Just because I'm debugging a particular actor doesn't mean I want to debug the AF itself... most of the time, I wouldn't want all the AF stuff showing up in my logs or slowing down while it logged its own stuff.

In other words... even if we get a universal setting, or a per-module setting, I think a per-VI setting will still be useful. I don't think those are mutually exclusive ideas.

And I know I'm not alone in this request... it's come in to me from many different users over time, so I figured I'd look into the feasibility.

Link to comment

PS: There are also regions of the code base that I know and own and other regions that I don't. Getting into per-build config settings is one of those areas that goes beyond my typical domain. When the team as a whole makes a feature a priority and asks me to work on it, I generally get resources that help with changes that need to be made in far away sections of the code. When I just want to spend my own time to add to LabVIEW, I'm more limited in the options I have, and I try to scope accordingly (and I try not to let that distort the solutions that I come up with). Per-build symbols would require a much wider coordination than "just me"... that would require that feature becoming a priority for development overall. And it kind of is... LabVIEW NXG is being designed with that option in mind, but there aren't plans to do the same for LabVIEW 20xx.

Link to comment
29 minutes ago, Aristos Queue said:

I frequently have code in the block diagram to assert X is true or to log information to a file while running. I don't want any of that code in the final product. Right now, it's a major pain to turn it on or off. I toggle debugging on and off all the time.

 

23 minutes ago, Aristos Queue said:

PS: There are also regions of the code base that I know and own ...And it kind of is... LabVIEW NXG is being designed with that option in mind, but there aren't plans to do the same for LabVIEW 20xx.

Yeah I'm on board, I was just throwing out what I thought would be better. I suppose you're right about per function, but per module is handled fairly effectively with conditional symbols by just defining lib_blahblah_dbg. I understand vi_blah_dbg would be more annoying, but then again that depends on how many specific VIs you have to debug at a time. But yeah, I understand neither of those will come to pass in current labview.

So let me switch to the argument against your feature: The other concern I'd have more generally is that while you may turn debugging off in your builds, the difficulty in actually producing an optimized build using app builder means many clients of your code (or if not yours, then someone else using this feature) will fail to do so, leading to not just unoptimized code, but deliberately slower code which produces weird logging data they don't want. This structure seems like it could lead to many situations where people throw in code they expect not to be run by end users but it does because the end user isn't familiar with how to turn off debugging on all parts of their application. You might say that as a library developer you should ship code with debugging turned off, which I'd agree with if it weren't already a pain to turn debugging on or off...and in my experience a lot of people do exactly what I do, which is to package up code with debugging turned on for all VIs and then use app builder to turn off debugging for a final product. In contrast, while more of a pain in the ass for you, conditional tokens are already a more 'advanced' feature and require active effort to enable them, which makes it more end-user-friendly.

Edited by smithd
Link to comment

To me debugging enabled means the ability to attach a debugger to the code, and toggles and all the stuff that needs to be in place to push meaningful information to the debugger. Any other use of the setting seems to be an abuse. I appreciate the case you've presented but to me it's the wrong way to do it. Unless of course some magical API exists that could extend debug functionality. Just kidding. Maybe?

Seriously though, I get twitchy anytime a proposal is made to take something that already exists and use it to control something for which it wasn't intended.

Link to comment

> and toggles and all the stuff that needs to be in place to push meaningful information to the debugger.

mje:
Let me put it to you this way -- how is it any different from changing the inplaceness model or enabling the constant folding or any of the thousand other things that LabVIEW does when you toggle "Enable Debugging"? To me, it's just a way for a user (me or you) to add to the set of things that should be skipped in a VI when it is ready for release. As it stands today, we have no way of adding to that set. NI has added many of those over the years. A VI doesn't have separate checkboxes for "enable constant folding" and "enable loop invariant code motion". Why should the user-defined optimizations have to have a separate switch from the built-in ones? To me, that doesn't make any sense.

Link to comment
31 minutes ago, smithd said:

The other concern I'd have more generally is that while you may turn debugging off in your builds, the difficulty in actually producing an optimized build using app builder means many clients of your code (or if not yours, then someone else using this feature) will fail to do so, leading to not just unoptimized code, but deliberately slower code which produces weird logging data they don't want.

This is a valid concern, but I think it is already a concern. You can get a LOT of performance boost by turning off debugging today. As a LV user, I honestly don't have an answer for you other than, "When they complain, hopefully someone will tell them."  As part of LV R&D, my answer is nor much better: "I hope someday we change the default to turn off debugging during a build, including a source distribution made for deployment." But that's my personal call, and others on the team felt we should listen to the customers. A whole lot of people complained about the build times being long. "It doesn't take that long to mass compile VIs when I'm in the IDE, why does it take so long to build?" Easy: the build is doing more work. There wasn't a lot of wasted work in the app build process... the only way to make build times shorter was to do less optimization. So that's now the default. It really irks me. Not my call.

So, I'm not knocking your concern, and it might be a reason not to do the feature. I'll include it in the analysis if I decide to propose this to the team. But I think the concern is already there, so to me, that makes it not something that should restrain improving this aspect of LabVIEW. But, again, others may disagree. :-)

  • Like 1
Link to comment

I would definitely use this on reentrancy.  Yes I designed a set of code to function as reentrant (and some times inlined) and it works and is tested and is great.  Then comes a time when it behaves oddly on RT.  Since RT can't debug reentrant VIs in the typical way with probes and break points, I will then change all the VIs I feel I need to debug to non reentrant.  Make a set of test code that only uses one instance of that code, debug it, find the issue and fix it, then turn reentrancy back on.

Maybe another one might be something like turning on wires retain values on a VI, or multiple VIs.  Asbo had an idea on the Idea Exchange for improving this too.

But overall I don't feel strongly one way or another

Link to comment
3 hours ago, Aristos Queue said:

So, I'm not knocking your concern, and it might be a reason not to do the feature. I'll include it in the analysis if I decide to propose this to the team. But I think the concern is already there, so to me, that makes it not something that should restrain improving this aspect of LabVIEW. But, again, others may disagree. :-)

Fair enough...

3 hours ago, Aristos Queue said:

This is a valid concern, but I think it is already a concern. You can get a LOT of performance boost by turning off debugging today.

Getting off topic, but at least where I'm at lv most often is competing with python or matlab, so speed isn't a major concern for them ;) . I definitely see the speed gains on RT and the real benefit seems to be memory usage these days.

Link to comment
4 hours ago, Aristos Queue said:

> and toggles and all the stuff that needs to be in place to push meaningful information to the debugger.

mje:
Let me put it to you this way -- how is it any different from changing the inplaceness model or enabling the constant folding or any of the thousand other things that LabVIEW does when you toggle "Enable Debugging"? ... Why should the user-defined optimizations have to have a separate switch from the built-in ones?

Well, it's not different at all-- the beauty of naivety! That checkbox is voodoo as far as I'm concerned, and given what you've said I'd argue it's either grossly misnamed or misused. Literally. It says one thing and does a "thousand" of other things. You're already at the infinity point.

Your point about optimization is completely valid. I don't think user optimizations should be a different class than compiler ones for this context.

I'm on board with what you're trying to do: a VI scoped switch to allow code compilation. I'd still argue the debugging flag is the wrong place to go about it, just because that flag has been hacked before doesn't mean it's the right thing to do again. The argument for scaling comes to mind as well. What if I wanted to so similar things for unit testing, reentrancy, or general mischievousness?

Edited by mje
Link to comment

OK it's been mentioned a few times: "user optimisations".  Are we really naive enough to believe that's all this will be used for?  How about making non-debuggable VIs?  Broken wires as soon as debugging is enabled?

How does this tie in with code being marked as changed for source control?  I have BAD experiences with conditional disables (Bad meaning that project-wide changes can actually lead to many VIs being marked as changes just because a project-wide value has changed which will be re-evaluated every time the VI is re-loaded anyway.... :( ) I presume since this will be a per-VI setting it will have at least a smaller scope.  But what about VIs called from within the conditional structure?  They are then at the mercy of the debugging enable setting of the caller VI......  I mention this because we tra quite a lot of code reuse across platforms and this problem rears its ugly head again and again.

I have no problem introducing a vi-specific conditional disable structure, but linking it to a completely different setting seems just wrong.  Sure, "enable debugging" is a pandora's box anyway, but at least for a given LV version it's not a moving target.  Imaging "enable debugging" doing something different for each and every VI you enable it on..... That sounds like a maintainance nightmare.

Link to comment
On 10/6/2017 at 3:13 PM, hooovahh said:

I would definitely use this on reentrancy.  Yes I designed a set of code to function as reentrant (and some times inlined) and it works and is tested and is great.  Then comes a time when it behaves oddly on RT.  Since RT can't debug reentrant VIs in the typical way with probes and break points, I will then change all the VIs I feel I need to debug to non reentrant.  Make a set of test code that only uses one instance of that code, debug it, find the issue and fix it, then turn reentrancy back on.

That doesn't sound like you're editing the VI itself... it sounds like you're creating a test harness around the VI. Maybe what you need is a way to toggle reentrancy whenever debugging is enabled?

If you really are editing the VI's code when you disable reentrancy, can you describe the kinds of code that you add to the block diagram?

Link to comment
On 10/6/2017 at 7:22 PM, mje said:

What if I wanted to so similar things for unit testing, reentrancy, or general mischievousness?

That is *exactly* my initial question. Is there an other option in the VI for which you commonly wish you could change out the code in the block diagram? Hooovahh has put forth a possible use case (pending more details). Are there others?

Link to comment
6 hours ago, shoneill said:

OK it's been mentioned a few times: "user optimisations".  Are we really naive enough to believe that's all this will be used for?  How about making non-debuggable VIs?  Broken wires as soon as debugging is enabled?

 

G already has "RUN_TIME_ENGINE" as a setting. That already exists to do most of this task, and the world has not fallen. The problem with that setting is that it doesn't work with packed project libraries (because those have to be able to run back in the IDE or the RTE) and it doesn't allow for source libraries to be distributed with debugging disabled but available.

If that's what a user wants to use it for, there's no reason they couldn't. Why would you object to someone writing their own code that way?

If you have enough access to the VI to toggle enabled to disabled then you have full access to the block diagram. Go find any Cond Disable structs that they put broken code in, flip them to the other frame and then use Remove Structure. Putting broken code in the debugging frame isn't even a stumbling block.

6 hours ago, shoneill said:

But what about VIs called from within the conditional structure?  They are then at the mercy of the debugging enable setting of the caller VI......  I mention this because we tra quite a lot of code reuse across platforms and this problem rears its ugly head again and again.

There's no impact on the subVIs. They are compiled however they are compiled. The settings of the caller do not affect how subVIs are compiled. This is both LV's blessing and its curse when it comes to optimal compilation. Every VI is a silo. If you know of some impact on the subVIs from editing the caller, that's news to me.

Now, there could be subVIs that aren't called in release mode that are called in debug mode. Those subVIs would vary whether they are loaded or not, just like any other compiled-out subVI. Maybe that's the problem you're talking about? If so, ok, but how they compile isn't changed.

6 hours ago, shoneill said:

Imaging "enable debugging" doing something different for each and every VI you enable it on..... That sounds like a maintainance nightmare.

G code does have RUN_TIME_ENGINE, as I said, but that doesn't really go far enough when working with source in the IDE. G is literally the only language I've ever worked in which DOESN'T have this option to compile user code in differently for release versus debug, regardless of build target. To me, this is a massive hole to fill, not a maintenance nightmare. Indeed, the ability to have debug code compiled in optionally helps a lot with code maintenance. It does mean you need to do two nightly builds, one with debug enabled and one with it disabled, just to make sure the code stays useful, but it's a major godsend. I did a quick scan -- in the LV C++ code, there are 808 functions that change behavior between debug and release mode. Mass compile is about 20x slower in debug mode because of all the extra checking, but it is well worth it when trying to assert the correctness of VIs or untangle some sort of memory corruption. Trying to add all that instrumentation in every time a new bug report gets raised would be impossible. There are a lot of idealists in the world who will tell you, "Oh, you should have been able to put all of that in through mocks and other indirections, keeping with the O principle of S.O.L.I.D. programming," but that O idealism often has a serious impact on performance. ("Well, then you're doing it wrong," says the principle idealists. Maybe. I support code that works with SOLID as much as possible, but there are limits to how complex I'm willing to make code, and when everything hides behind three layers of dynamic programming, I find that the debugging code meant to help with debugging starts needing its own debugger.)

Link to comment

AQ, I'm not arguing against the idea of needing debug code per se (I put copious amounts of debug paths into my code), only on the coupling of the activation to the already nebulous "enable debugging".

I see a huge usability difference between RUN_TIME_ENGINE and toggling debugging on a VI.  It's my 2/100ths of whichever currency you prefer.

Link to comment
On 10/6/2017 at 7:22 PM, mje said:

 I'd still argue the debugging flag is the wrong place to go about it, just because that flag has been hacked before doesn't mean it's the right thing to do again.

This comment is really bugging me.

To me, toggling debugging is the same as moving from Desktop to FPGA. The entire code base is compiled differently for the new target. I cannot see anything about the existing Enable Debugging option that is an existing hack. That checkbox is the toggle used to change between two entirely different execution environments. The fact that that target is a bit amorphous (it doesn't have dedicated hardware/any platform might become a debugging target) doesn't change the fact that it is an entirely different environment. Your objection hits my ears like saying, "Dragging a VI from Desktop to FPGA is too easy. Users should have a whole list of checkboxes to enable VHDL compilation on a function-by-function basis."

Can you expand your thoughts for me here?

Link to comment
1 hour ago, Aristos Queue said:

If you really are editing the VI's code when you disable reentrancy, can you describe the kinds of code that you add to the block diagram?

I really am editing the VI.  It is fixing whatever bug or issue I found with the reentrant VI, that couldn't easily be troubleshot with debugging turned off (or no probing ability like on reentrant RT VIs).

Link to comment

AQ, what if I want (or need) my debugging code to run with optimisations enabled i.e. without the current "enable debugging"?  Think of unbundle-modify-bundle and possible memory allocation issues on RT without compiler optimisations......

This would require a seperate switch for "enable debugging" and my own debug code, no?

Link to comment
1 minute ago, hooovahh said:

I really am editing the VI.  It is fixing whatever bug or issue I found with the reentrant VI, that couldn't easily be troubleshot with debugging turned off (or no probing ability like on reentrant RT VIs).

A bug fix is something you change to the VI AFTER you've debugged it. I'm talking about code that you would include in the shipping VI that says, "Whenver reentrancy is turned off, compile this code in". Something like...

Untitled.png

Link to comment
9 minutes ago, shoneill said:

AQ, what if I want (or need) my debugging code to run with optimisations enabled i.e. without the current "enable debugging"?  Think of unbundle-modify-bundle and possible memory allocation issues on RT without compiler optimisations......

This would require a seperate switch for "enable debugging" and my own debug code, no?

I don't think I understand the question. "with i.e. without" is confusing me.

If you for some reason wanted to compile in your own code based on your own criteria, you would do exactly what you do today: define your own symbol. There would be no change to that. This is only for code changes that you want to enable/disable with the master debugging switch.

Link to comment
1 hour ago, Aristos Queue said:

A bug fix is something you change to the VI AFTER you've debugged it. I'm talking about code that you would include in the shipping VI that says, "Whenver reentrancy is turned off, compile this code in". Something like...

Thanks for making this clear.  I know you mentioned conditional disable in the title but for some reason I didn't see it like that (us LabVIEW people are quite visual).  I think I could see code like this.  It could make things more reusable, but honestly I would just read this as a property node on first call into the VI the keep it in a shift feedback node all other times the VI is called.  It isn't like reentrancy can change on a VI after entering run mode anyway, which is sorta the purpose of the conditional structure, things that can't change.  Would you see implementing all properties of a VI in this conditional structure?

Link to comment
2 hours ago, hooovahh said:

 Would you see implementing all properties of a VI in this conditional structure?

That's explicitly the question... "is there any use case for anything other than Enable Debugging?" My hope -- which this conversation is convincing me is true -- is that the answer is "no." There are people questioning whether "Enable Debugging" is itself a use case, but so far nothing beyond that.

2 hours ago, hooovahh said:

honestly I would just read this as a property node on first call into the VI the keep it in a shift feedback node all other times the VI is called.

You're leaving to run time a compile time decision? And you're compiling in a first-call dependency on a requires-UI-thread property node?

Ewww. Gross! That's exactly the kind of code smell the Cond Dis struct is there to prevent!

Exactly what code would you be guarding with that property node check? That's the use case I'm asking about.

Edited by Aristos Queue
Link to comment
41 minutes ago, Aristos Queue said:

You're leaving to run time a compile time decision? And you're compiling in a first-call dependency on a requires-UI-thread property node?

I was stating how I would do it now.  You speak as if there is an alternative, of which I'm not aware of one.  Also I'd prefer a first call state, rather than a thread swap to the UI every time I call the subVI.

But I do have something that I might use this for.  Is VI top level?  My actors can run independently of any central messenger structure, so that each can be unit tested and debuged on their own.  During the initialization state of the state machine within each actor I will detect if the VI is the top level, and if so it will behave slightly differently.  This information is kept in the private data of the actor in the forum of a cluster in a shift register.  They detect this by looking at the call chain, not a property as you mentioned but even this I heard can take enough systems resources that calling it over and over is less ideal than just calling it once on starting that actor.  Other things I check I can see changing at run time like if the actor is in a subpanel I may behave differently, or if the VI has its window showing.

Link to comment

There seems to be two aspects to this discussion.

1. An inbuilt conditional case activated for enabling/disabling user debugging code predicated on existing VI settings and finding other vi specific settings to bolster this one case.

2. An argument for adding one (or more) additional, built-in, conditional disable structure defines in the face of resistance to changing anything in the (probably fragile) codebase.

If you win #2, you can do #1 but #1 is a very specific case that I certainly have no need for.

However. I have another non vi specific one that I would like to see the conditional disable structure support (ammunition for #2).

I would like to see a case implemented for the "LabVIEW version" since I have several pieces of code that have to determine this at run-time and use a normal case structure to switch the code.The run-time gymnastics of this is disproportionate to the simplicity of a conditional disable for this purpose. In a couple of extreme cases it has required a post-process VI to be run on the target system and scripting to make modifications. This has meant that the VIs cannot be password protected and therefore a licence cannot be attached to them (I have had to ask for an NDA).

  • Like 2
Link to comment

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.