Jump to content

Recommended Posts

Here are my results (Windows 7, LabVIEW 2015 32-bit):

path constant average: 13.515us
no path constant average: 13.437us
path from control on front panel average: 13.958us (an attempt to simulate the V0.0.2 implementation)

CLNbenchmark.vi

 

 

  • Like 1

Share this post


Link to post
Share on other sites

Well, let's be pedantic:

CLNbenchmark.vi

mupLibPath2.vi (change the library names according to bitness and OS)

  1. there is a huge jitter in this benchmarking, to get ~1% variance I need to iterate 1M times, so results are not entirely conclusive
  2. testing in parallel like I did earlier was probably not a good idea, suppose libmuparser is single-threaded - indeed running 2 or 3 loops in parallel changes the picture.
  3. Testing individually each loop, static library name wins, by perhaps 1% (100ns on 10us)
  4. Testing in parallel, each timing is larger (~60%), and jitter is even larger, no clear winner in few attempts
  5. I wouldn't be surprised if YMMV in other machines, OS, bitnesses and LV versions
  6. I tested on linux LV2015 64bit, 2016 64bit and 2017 32 and 64 bit, results were similar and similarly scattered. On LV2017 32bit I got timings ~25% higher.
  7. don't even mention boundary conditions like FP activity

Moral, even considering that some time is spent in the libmuparser routines themselves, and some is LV calling overhead, and that the ratio may change from function to function, this overhead is minute, and imho it pays much more to go for the most maintainable solution [hint: inlined subvi with indicator whose default value is set by an install script]. YMMV...

Edited by ensegre

Share this post


Link to post
Share on other sites

I would guess in parallel you incur locking overhead either inside labview or the kernel. The problem with a constant set on install is it would be problematic for rt. I would suggest a subroutine priority fgv with caching. Would that not be the best of both worlds (except path-in-node)?

Share this post


Link to post
Share on other sites
3 minutes ago, smithd said:

The problem with a constant set on install is it would be problematic for rt

pre-build VI?

4 minutes ago, smithd said:

I would suggest a subroutine priority fgv with caching

Possibly... instinctively I'd say the less code the better, but have not benchmarked that.

Share this post


Link to post
Share on other sites
1 hour ago, ensegre said:

pre-build VI?

I dont know how much of a use case there is for this toolkit on RT, but I absolutely would branch it and make my own copy if you asked me to use a pre-build VI to script a different path into an RT exe in order to safe a few usec per call :P

 

Share this post


Link to post
Share on other sites

To simplify the path logic to a constant, we could reference the shared library by name rather than full path. To do this, we need to place the library in the search path. For LV windows, linux and OSX development environment the search path includes "<LabVIEW>\resource". For a LV-built application in windows, the directory of the executable seems to also be included in the search path. Not sure about LV-built applications for Linux though.

See: http://digital.ni.com/public.nsf/websearch/EBAE870D564CBBE78625788B004E76D3

Benchmark shows very little difference (<100ns) in performance between static, constant (full path) and in-line VI (providing library name).

Benchmark_CLN.zip

Edited by Porter

Share this post


Link to post
Share on other sites

So I unzip that on my desktop. This means  "/home/owner/Desktop/LabVIEW 2015/Projects/LV-muParser" and "/home/owner/Desktop/LabVIEW 2015/resource/" :rolleyes:.  Go figure,  "/<resource>/libmuparserX32.so.2.2.5" not found... :oops:

Share this post


Link to post
Share on other sites

For the record I obstinately still tried this, following smithd.

p.png

Because of "current VI's path" this cannot be inlined, at most given subroutine priority. The result with the previous benchmarks is ~600ns overhead (on ~12us, 5%) on 32bit and ~200ns (on 10.4us, 2%) on 64 bit. Results obviously degrade for less than subroutine priority.

mupLibPath.vi

  • Like 1

Share this post


Link to post
Share on other sites

I would guess the extra time penalty for using a Path input to the CLN, is the first call LV does to the dll, when it need to load it into memory. After that it already has it in memory so it will be as quick as the normal option.

I prefer to have the dll inside the node so I know it gets loaded in memory when the application starts and also that I know that the right dll will be included in my exe-build.
We use the conditional structure node for this.
It’s lots of extra work to put a conditional structure around every DLL call, but we have a scripting VI that helps us with that task.

Cond1.png

Share this post


Link to post
Share on other sites

I also prefer the statically linked dll because I can imagine that no one will remember to include the correct DLL or even know where to find the DLL when they build their exe.

However, since this library is under development, I think that it is wise to stick with the in-lined mupLibPath vi for now.

When we get closer to V1.0 perhaps it will be worth putting in the extra effort to setup a conditional disable structure around each CLN.

  • Like 1

Share this post


Link to post
Share on other sites
5 hours ago, Porter said:

I can imagine that no one will remember to include the correct DLL

I get the point. Dynamically referenced will not be visible by the builder as dependency.

If I may forgiven for being so stubborn, as a workaround one could still put just one conditional disable structure with the different statically linked CLNs within a false if frame in just one mandatory, but called once, ancillary, and leave all the rest with mupLibPath.

  • Like 2

Share this post


Link to post
Share on other sites
9 hours ago, Porter said:

I also prefer the statically linked dll because I can imagine that no one will remember to include the correct DLL or even know where to find the DLL when they build their exe.

However, since this library is under development, I think that it is wise to stick with the in-lined mupLibPath vi for now.

When we get closer to V1.0 perhaps it will be worth putting in the extra effort to setup a conditional disable structure around each CLN.

The issue is not much to do with LabVIEW and very much depends on the distro and versions already present. Your next issue may be that Linux will load another DLL with the same name if it is present in the general locations and everything will crash. The DLL should also be compiled with "-soname" so that ld and ld_config are aware of what it should do with it-dlls need to be installed, as such

The easiest way is to just put it in the appropriate lib/lib64, for that distro run ld_config. Then use a symlink to point to it and hope it works. LabVIEW sees through symlinks so as long as you name the symlink the same as the library, in the CLN path, it will work on all platforms - you can just have the DLL itself in the app directory on Windows so it's business as usual. It's then demonstrably the users distro/configuration that is the problem if things don't work.

If it doesn't work then you have conflicts with other, already loaded version and since the LabVIEW CLN function cannot be set to " RTLD_DEEPBIND "; you are stuck This is what -soname is supposed to alleviate but I've had mixed success. If this is the case, you can point the symlink to the version already loaded (if you can figure it out) which will work as long as the binary interface (ABI) is the same - they don't think twice about breaking it between versions, though (yes I'm looking at you Python!).You will end up spending most of your time answering Linux support with a myriad of configurations as everyone has all sorts of favourite crud installed.

My advice is to get it all production ready and installation proof on windows and think about Linux for version 2. Linux devs can still try the symlink method if they are aching to use it, but you can avoid all the Linux rabbit holes while you concentrate on the library itself.

Edited by ShaunR
  • Like 1

Share this post


Link to post
Share on other sites

you make it sound more impossible than it reasonably is in this case.

2 hours ago, ShaunR said:

distro and versions already present

libmuparser is at least not unknown to ubuntu, I apparently brought it on 14 and 16 as dependency of meshlib or of some FEM package. Now Porter's toolbox is apparently using a patched version of it to add some syntactical feature, but the toolbox would also work with the off the box version of it. Even with an earlier version, if the ABI didn't change. If, I concede. But LV-muParser could say: requires x.x.x<libmuparser<y.y.y

2 hours ago, ShaunR said:

Linux will load another DLL with the same name

If a locally patched version of the library is so important, to avoid conflicts just give it an insanely improbable name - like libmuparser-with-added-esclamation.so

2 hours ago, ShaunR said:

dlls need to be installed, as such

Dump the responsibility to the author of the original library: ./configure; make; make install. If it can be built for the target distro (or if someone bothered to distribute it), ok; if it can't, just don't claim it is supported.

I haven't thoroughly looked into, and I'm just a script-kiddy at it anyway, but FWIW nm -C libmuparserX64.so.2.2.4 | grep @ tells me only of GLIBC_2.0, GLIBC_2.3.4, GCC_3.0, CXXABI_1.3, GLIBCXX_3.4 - standard stuff, hopefully not dramatically changing across distros.

Anyway - I agree that the effort is best invested in developing the toolbox. I never suggested that the toolbox should provide also compiled .so, and see the reasons why. I was perhaps carried along by the academic discussion, which in my view was in general about the best LV strategy to support different shared libraries for different platforms.

  • Like 1

Share this post


Link to post
Share on other sites

How about these names:

libmuparser-x32-ascii-lv.dll
libmuparser-x64-ascii-lv.dll
libmuparser-x32-ascii-lv.so.2.2.5
libmuparser-x64-ascii-lv.so.2.2.5

I will assume that they will be located in the "<LabVIEW>\resource" directory.

Note that a major difference between the modified version and a possible standard version of libmuparser is the character encoding. By default, Visual studio 2013 compiles muparser with _UNICODE preprocessor macro. This does not play nice with LabVIEW's strings.

Share this post


Link to post
Share on other sites
11 hours ago, Porter said:

compiles muparser with _UNICODE preprocessor macro. This does not play nice with LabVIEW's strings

Didn't think at it. [NXG claims to support unicode. Didn't try. The issue might exist for extended ascii chars, like latin1 accented chars, as they are coded as 1byte in LV-windows and as UTF8 in LV-linux]. But why passing anything else than basic 7bit ascii to libmuparser at all? I quickly tried /usr/lib/x86_64-linux-gnu/libmuparser.so.2 with muParser demo.vi, accented chars in variables seem illegal.

Edited by ensegre
shorten

Share this post


Link to post
Share on other sites
Quote

MUP_STRING_TYPE

This definition determines the string type used by muParser. This can either be std::string or std::wstring. This definition shouldn't be set directly. It is defined to std::wstring if there is a preprocessor macro _UNICODE present. (This definition is set by VS2008 accoring to the project settings.

But it sounds like your "/usr/lib/x86_64-linux-gnu/libmuparser.so.2" is using std::string.

Share this post


Link to post
Share on other sites

V0.0.4 is up. I've named the muparser shared libraries as "libmuparser-[bitness]-lv.dll". For now, you need to manually copy them over to your "<LabVIEW>\resource" directory (or somewhere else in the search path).

Now to concentrate on features...

- Bulk mode
- Multiple return values
- Multiple type support (MUP_BASETYPE)?

Share this post


Link to post
Share on other sites

I keep an eye on you :P. mupEvalMulti.vi dies on DSDisposePtr. Shouldn't there be a DSNewPtr somewhere, like in other VIs using LabVIEW:MoveBlock?

Besides, your .so doesn't load on my system, and I have to use the one I compiled locally, but that is expected, as said above. Only confirming that it is vane to target all possible linux distros at once.

Edited by ensegre
  • Like 1

Share this post


Link to post
Share on other sites
On 9/10/2017 at 2:58 AM, ensegre said:

mupEvalMulti.vi dies on DSDisposePtr. Shouldn't there be a DSNewPtr somewhere, like in other VIs using LabVIEW:MoveBlock?

mupEvalMulti returns a pointer to an array of doubles. I'm using that as the source for MoveBlock. Then I initialize an array of doubles to the correct size and pass its array data pointer as the destination for MoveBlock. The destination pointer, I'm assuming, is allocated and disposed of internally by LabVIEW. The source pointer should be allocated and disposed of by muParser. So I should not use the DSDisposePtr at all in this case... ?

On 9/10/2017 at 2:58 AM, ensegre said:

Besides, your .so doesn't load on my system, and I have to use the one I compiled locally, but that is expected, as said above. Only confirming that it is vane to target all possible linux distros at once.

The .so files included in the zip are the ones that you posted earlier. Maybe I messed them up when I renamed them? Or perhaps they break if loaded from "<LabVIEW>/resource" directory? Sorry I can't test any of this; I don't have access to LabVIEW for Linux.

Share this post


Link to post
Share on other sites
25 minutes ago, Porter said:

The .so files included in the zip are the ones that you posted earlier.

My mistake :oops:. The ones I posted were compiled on Ubuntu 16, and I then tested them as not working on Ubuntu 14. Same conclusion on interoperability, probably.

Share this post


Link to post
Share on other sites
2 hours ago, Porter said:

So I should not use the DSDisposePtr at all in this case... ?

It doesn't seem safe to me either, but if I remove it outright I have no crash, and running continuously the example with 450 formulas I don't observe a growth of process memory.

Share this post


Link to post
Share on other sites

I might incorporate the toolbox in a project (because it does booleans), and I found out that I would use the evaluation of multiple expressions within a single parser. mupLib/mupEvalMulti does it, but there is no equivalent mupExpr Eval function. What do you think about adding these two to the lvclass? (LV17 but I can backconvert)

Besides, you named one Eval_MuliVar.vi, probably a typo.

Eval_MulVarMulRes.vi

MultiEval.vi

mupExpr MultiMulti example.vi

Edited by ensegre
added example

Share this post


Link to post
Share on other sites

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.