LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

To More Specific Class vs Dynamic Dispatch

So I've read that Dynamic Dispatch is "much faster than" recasting to a specific class. IIRC someone mentioned "10x as fast".

 

Are there any rules of thumb for how fast "much faster" is? I would try a benchmark, but I'd assume this has to do with the size of each class, the size of the class hierarchy, whether or not the new class is loaded into memory, etc and I don't feel like I'm capable of writing a good benchmark for this specific application.

 

I have a program that has some To More Specific Class's doing some work that can't be replaced with Dynamic Dispatch, but that could be refactored to use a vim acting sort of like an OOP "interface". I'd like to know if it's worth the trouble to refactor. Would I gain a few microseconds? Milliseconds? Tens of milliseconds?

 

Any thoughts would be appreciated.

0 Kudos
Message 1 of 10
(3,091 Views)

Dynamic Dispatch would certainly be faster than iterating through all the possible child classes and attempting to cast it "To More Specific Class" (and speed is not the only advantage), but there are certainly scenarios where you need to do the casting to one specific child class (an example is a tree where you have nested instances of the same class).  I don't think the speed penalty is so severe in those situations.  Each has their use-case - you would not want to use casting in place of Dynamic Dispatch.  Can you be more specific about the code?

0 Kudos
Message 2 of 10
(3,035 Views)

This type of optimization is usually only useful for tight loops, so apart from the intellectual curiosity (i'd like to know the difference) i have a hard time imagining when you'd have a for loop where you'd need to convert the object each iteration and that would be a big factor compared to the methods time.

/Y

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 3 of 10
(2,994 Views)

So in this instance, I know which class I'm working with, I just need to cast it so I can call the child method I want to use. It's not a try-everything-until-I-get-the-right-one situation.

 

It's similar to paul's comment with a tree of parent classes casting each element to a child class. I basically have an array of different, mixed data types, each of which inherit from a parent "generic datatype". There's a little more to it than this, but each datatype can basically be a String, a U32, a Float, a Double, etc. The array represents a big grid of data, definable and reconfigurable by the user at runtime. When it comes time to actually do something with the values (in this case, it's writing them to a piece of hardware being developed in-house), I need to actually get the individual values of each element.

 

Since each element returns a different datatype, I can't use Dynamic Dispatch. What I *can* do is have a Get Value method for each subtype, but just make it a static method. I am storing the type of the cell elsewhere so I don't have to look it up each time.

 

At the moment, I cast the object to the correct type and read the value from the Child's "get value" accessor, then write that value to my device. I am in need of some small performance gains, as I'd ideally like to write to the device around 500 times a second. The actual device write takes ~1ms, and I'm tracking down potential slowdowns in my code. I can refactor to have each object include its own "write me to device" method, but the data storage grid is a separate library that's used for several similar applications and I don't want to couple it to the hardware code.

 

If I could use multiple inheritance I could make it work, and I think I can get there with a vim but I'm hoping to gain some insight into potential speed gains before I get started refactoring stuff.

 

I understand that To More Generic Class is a no-op, and I've heard that To More Specific Class has some overheads, but if I know the conversion will work, is that function still pretty slow?

 

I'd like to be able to do this operation roughly 100 times in a millisecond, so this definitely qualifies as a "tight loop" IMHO 🙂 @Yamaeda, your last sentence "I have a hard time imagining... and that would be a big factor compared to the methods time."

 

Are you saying you have a hard time imagining when that would be a big factor compared to the methods time, or are you having a hard time imaging when I'd need to do this, and that you know it WOULD be a big factor?

 

Thanks for the input all.

0 Kudos
Message 4 of 10
(2,963 Views)

@BertMcMahan wrote:

Since each element returns a different datatype, I can't use Dynamic Dispatch. What I *can* do is have a Get Value method for each subtype, but just make it a static method. I am storing the type of the cell elsewhere so I don't have to look it up each time.

 

At the moment, I cast the object to the correct type and read the value from the Child's "get value" accessor, then write that value to my device. I am in need of some small performance gains, as I'd ideally like to write to the device around 500 times a second. The actual device write takes ~1ms, and I'm tracking down potential slowdowns in my code. I can refactor to have each object include its own "write me to device" method, but the data storage grid is a separate library that's used for several similar applications and I don't want to couple it to the hardware code.

 

I'd like to be able to do this operation roughly 100 times in a millisecond, so this definitely qualifies as a "tight loop" IMHO 🙂 @Yamaeda, your last sentence "I have a hard time imagining... and that would be a big factor compared to the methods time."

 

Are you saying you have a hard time imagining when that would be a big factor compared to the methods time, or are you having a hard time imaging when I'd need to do this, and that you know it WOULD be a big factor?


100x / ms is pretty tight, yes. 🙂 I referred to "a big factor compared to the methods time". If you're only getting a scalar it's a much smaller operation than i imagined in such a scenario and your mentioned static method might be a good solution. Alternatively you could have the methods give a Variant as result, but i have no info on how performance is for To more specific class compared to Variant to data (though the latter i imagine is faster). I guess you'll have to measure the performance as tell us. 🙂

/Y

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 5 of 10
(2,946 Views)

@Yamaeda wrote:
Alternatively you could have the methods give a Variant as result, but i have no info on how performance is for To more specific class compared to Variant to data (though the latter i imagine is faster). I guess you'll have to measure the performance as tell us. 🙂

I have been told that converting to/from a variant is pretty expensive.  Maybe a better option would be to use a flattened string.  No data to say what method would be the fastest.  But the more I think about it, the more I think using the To More Specific Class might be slightly faster.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
0 Kudos
Message 6 of 10
(2,941 Views)

OK, got a very low-fidelity "benchmark" here, but wanted to post the results. The benchmark is tailored to my application, and doesn't effectively isolate all of the different variables, but I can at least say that at the moment I saw no difference performance-wise between writing to:

-A generic Value method that accepts a Variant as an input, which each child class overrides, converting the Variant to its own data type. I tried this both with auto-coercing the values to a Variant and explicit conversion.

-To More Specific Class with the correct class wired, calling the Write value

 

My test case (which again has a bit more to it than JUST writing these objects) writes 501 batches of 12 values in ~2.4 seconds, or about 0.4 ms per write. Each write is replacing an array element and doing a few other things. This still seems a little slow to me, but at least I can say it's not my To More Specific Class acting up.

 

In short, for at least this application (TSC writing scalars), there isn't a measurable performance difference between TSC and From Variant. I would imagine that there is considerably more difference if you use more complicated classes or data.

 

I'll post back here if I can get the whole process a little quicker, but as for the title of the thread I suppose this one isn't the smoking gun.

Message 7 of 10
(2,926 Views)

OK, one more benchmark, and a piece of info I hadn't mentioned as I didn't think it was relevant, but might be.

 

The whole array is stored in a DVR. I mentioned I was writing batches of 12 elements at a time. If I update the DVR 12 times per batch (one write per element) it took around 2.5 seconds to do 501 batches.

 

If I switch to modifying the DVR once per batch, pulling the array out, modifying 12 elements, then rewriting, then I can write 501 batches in 200 ms- a 10x improvement, which *should be* enough for my needs right now.

 

I'm not certain it's the DVR overhead that makes it take so much longer, but right now it's either reading and writing the DVR or some small issue with an IPE somewhere.

 

Not super relevant to the topic of the thread, but wanted to mention it anyways in case it might help others, or could spur an aha moment for someone.

Message 8 of 10
(2,917 Views)

@crossrulz wrote: I have been told that converting to/from a variant is pretty expensive.  Maybe a better option would be to use a flattened string.  No data to say what method would be the fastest.  But the more I think about it, the more I think using the To More Specific Class might be slightly fast

I assume there's been some optimizations. I did some test a couple of years ago and the difference was very small, but i might set up a new test to compare. Wasn't there a big job on Variants in ~LV2014?

/Y

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 9 of 10
(2,866 Views)

Ah, yes an IPE can cause delays due to mutex locking, LV's internal memory manager is actually quite good so forcing execution can often slow things down.

Can you post the write VI (and a picture) and we might be able to optimize it further.

/Y

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 10 of 10
(2,858 Views)