Jump to content
News about the LabVIEW Wiki! Read more... ×

Recommended Posts

LV muParser


LV-muParser provides a simple LabVIEW API for muParser fast math expression parser.

A modified version of muParser v2.2.5 is included. It will be installed to your "<LabVIEW>\resource" directory. I have added support for the "!" (not) operator as well as added ":" as a valid character for variable names.

You will find the muParser API in the functions palette under "Addons > LAVA > muParser"

muParser: http://beltoforion.de/article.php?a=muparser

LV-muParser source on github: https://github.com/rfporter/LV-muParser


  • Submitter
  • Submitted
    08/25/2017
  • Category
  • LabVIEW Version

 

  • Like 2

Share this post


Link to post
Share on other sites

It appears that it might be straightforward to make this work on linux too. In fact, I found out that I had libmuparser2 2.2.3-3 already on my system, for I dunno which other dependency need. Would you consider to make provisions for cross platform? Usually I wire the CLN library path to a VI providing the OS relevant string through a conditional disable; LV should have it's own way like writing just the library name without extension, to resolve it as .dll or .so in standard locations, but there may be variants.

I just gave a quick try, replacing all dll paths to my /usr/lib/x86_64-linux-gnu/libmuparser.so.2 (LV2017 64b), I get white arrows and a majestic LV crash as I press them, subtleties. I could help debugging, later, though.

Also, to make your wrapper work with whatever version of muparser installed systemwise, how badly does your wrapper need 2.2.5.modified? How about a version check on opening?

Share this post


Link to post
Share on other sites

I'm opening some random subvi to check which one segfaults. All those I opened were saved with allow debugging off and separate compiled code off (despite your commit message on github). Any reason for that?

Share this post


Link to post
Share on other sites

Ok, I traced it down to that, for me, muParser Demo.vi crashes on its first call of DSDisposePtr in mupGetExprVars.vi. Just saying.

Share this post


Link to post
Share on other sites

Do you have a compiled 64 bit dll?

I thought everybody had migrated to LV-64 bit nowadays?!?

 

Share this post


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

I thought everybody had migrated to LV-64 bit nowadays?!?

Erm...no

Share this post


Link to post
Share on other sites

The most annoying thing we've had with going 64 bit, was with NI's Motion drivers that only has a 32 bit dll, so we made a LV-32 bit wrapper exe file acts as a server for that, so we can have all our code in LV-64bit.

There are some vendor's drivers that only have a 32 bit version for those we do the same thing, we have a small LV-32 bit server that handle that driver.

We have a few projects that can't build if we stay in 32 bit, (I guess the amount of classes we use makes the build require much more memory that a traditional LV application).

Also some of our projects requires more than 4G of ram when running.

 

Share this post


Link to post
Share on other sites

I need rt, I need fpga. Most of my systems have less than 2 GB of ram, the vast majority are at 256 or 512. 

Database access is valuable as well, although we now have alternatives for mysql, postgres, and sqlite. I only really need 64-bit for database access tasks.

Edited by smithd

Share this post


Link to post
Share on other sites

Sure for our RT/FPGA project we don't have a choice.

For DB, we don't use NI's tool, we use LabSQL ADO

Edited by MikaelH

Share this post


Link to post
Share on other sites

Ok, reporting progress:

  • compiled a 32bit .so of your modified library
sudo apt-get install g++-multilib

cd muparser-2.2.5

./configure --build=x86_64-pc-linux-gnu --host=i686-pc-linux CC="gcc -m32" CXX="g++ -m32" LDFLAGS="-L/lib32 -L/usr/lib32 -Lpwd/lib32 -Wl,-rpath,/lib32 -Wl,-rpath,/usr/lib32"

make clean
make
  • patched muParser.lvlib, to include a target and bitness dependent libmuparser path. Attached, with compiled code removed (orderly: I should submit a pull request on github). mupLib-path.zip

Testing on LV2017-32bit:

  • mupLib example.vi WORKS
  • all other examples crash when mupGetExprVars gets to DSDisposePtr, with trace like

*** Error in `labview': free(): invalid pointer: 0xf48c3a40 ***
Aborted (core dumped)


Testing on LV2017-64bit, with system libmuparser 2.2.3

  • Ditto. Only difference, longer pointer in

*** Error in `labview64': free(): invalid pointer: 0x00007f03aa6b78e0 ***

 

Share this post


Link to post
Share on other sites

Cracked it finally. You were passing the wrong pointer to DSDisposePtr. Here mupLib-path.zip is a corrected version of the whole lvlib.

Now all examples and benchmarks run for me in LV2017 32&64, 64bit being marginally faster with the default eq in the benchmark

  • Like 1

Share this post


Link to post
Share on other sites

Thanks ensegre!

I modified the muparser to include support for the not "!" operator (rather than writing another wrapper dll). I think that it is worth it. It was compiled for 32-bit and I'm using LV 2015 32-bit.

I didn't consider adding Linux support as I don't have access to a copy of LabVIEW for Linux.

I'll install LV 2017 today and take a look at your corrected version. I'm quite surprised about the DSDisposePtr crash. It was working on my system.

Share this post


Link to post
Share on other sites
On 8/27/2017 at 2:41 PM, ensegre said:

All those I opened were saved with allow debugging off and separate compiled code off (despite your commit message on github)

Debugging off, I realized that it is for inlining; compiled code, I downloaded your first commit on LAVA rather than the latest github.

1 hour ago, Porter said:

I'll install LV 2017 today and take a look at your corrected version

2015, please: mupLib.zip

If ever useful: libmuparser.zip compiled .so for X32 and 64 on ubuntu16. As they are dynamic, I doubt they may be themselves dependent on some other system lib, and hence particular of that distro.

I'd also think at a benchmark which iterates on repeated open/evaluate/close. I see it as a frequent use case, and suspect that muparser might do better than the formula parser there.

  • Like 1

Share this post


Link to post
Share on other sites

Thanks for the 2015 version. I haven't yet make the jump to 2017. Waiting for SP1.

I don't know why the pointer changed after passing through mupGetExprVar. I think that something is still wrong in the call setup for the varName parameter.

The libmuparser.so files you provided, are they compiled from the modified source? Wondering this because the names are 2.2.4 and not 2.2.5

Share this post


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

I don't know why the pointer changed after passing through mupGetExprVar. I think that something is still wrong in the call setup for the varName parameter.

Maybe that is an output only argument to mupGetExprVar? It would make little sense that the call sequence has a completely transparent argument. In any case, have you noted the shift register for that pointer? This should keep the case of N=0 exprs from crashing. Apropo which, mupGetExprVars still crashes if called with Parser in=0, that should perhaps be trapped in a production version.

1 hour ago, Porter said:

The libmuparser.so files you provided, are they compiled from the modified source? Wondering this because the names are 2.2.4 and not 2.2.5

yes. Probably sloppiness of the author who didn't push the version number everywhere (I added the X32 and X64 in the names on my own, though).

About the choice of the library, I'm still thinking at the best strategy for muLibPath.vi. If one puts more complex path logics into it, that affects very badly performance, as the VI is called for every single CLN. Probably the best is to make an inlined VI out of it, containing only a single path indicator, whose default value is assigned once for good by an installation script. I hope that the compiler is then able to optimize it as a hardwired constant.

Edited by ensegre
  • Like 1

Share this post


Link to post
Share on other sites
6 hours ago, ensegre said:

About the choice of the library, I'm still thinking at the best strategy for muLibPath.vi. If one puts more complex path logics into it, that affects very badly performance, as the VI is called for every single CLN. Probably the best is to make an inlined VI out of it, containing only a single path indicator, whose default value is assigned once for good by an installation script. I hope that the compiler is then able to optimize it as a hardwired constant.

Usually I would just build the library's path in a construct vi (this case it would be a mupCreate.vi) then pass it around in a cluster (or object) with the parser's handle.

Is there a significant hit to the performance vs having a constant wired to the CLN?

Share this post


Link to post
Share on other sites
7 hours ago, ensegre said:

In any case, have you noted the shift register for that pointer? This should keep the case of N=0 exprs from crashing.

Good catch. I missed that one. I was too distracted by my struggles with the getValueByPointer xnode (which does not work properly when built into an executable).

7 hours ago, ensegre said:

mupGetExprVars still crashes if called with Parser in=0, that should perhaps be trapped in a production version.

Indeed, LabVIEW does not like an uninitialized parser reference. Now is it worth checking for hParser=0 in every mup vi? My plan was to create a wrapper for the mup VIs (muExpr class) to protect the end user from inadvertently crashing LabVIEW. Within that wrapper I make sure that the parser handle is properly initialized and pointers to variables are properly created/released.

Share this post


Link to post
Share on other sites

Modified version with mupGetExprVar fixed, path wired to CLNs, muParser dll moved to mupLib directory: muParser.zip

Lets call it V0.0.2

Edited by Porter

Share this post


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

Is there a significant hit to the performance vs having a constant wired to the CLN?

About 600-800us if memory serves. For Linux I opted for a symlink to the *so if it's not on the search path. If you try to load a *so from the local directory and there is another elsewhere on the search path; you normally end up with crashes. Linux handles dynamic loading poorly which I suspect is why most people statically link.

Edited by ShaunR
  • Like 1

Share this post


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

Is there a significant hit to the performance vs having a constant wired to the CLN?

Yesterday I played a little around with constructing an absolute path inside muLibPath.vi, kind of how you did now in the windows case, and the benchmark started crawling. To keep the libraries in the same dir as muLibPath.vi may simplify matters in the IDE but right, you have to do something for the exe. So yes, either devising the path in Construct.vi and passing it along with the class data, or having an installation script fixing the return value of an inlined subvi and saving it, look to me ways to go.

Share this post


Link to post
Share on other sites

How about statically linking (not specifying path on diagram) and putting a conditional disable structure around each CLN? It is a pain to maintain but I think that it would give us the best performance. Also, when built to exe, the correct OS & bitness dll/so will be included automatically.

Share this post


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

It is a pain to maintain

A supreme one, but proper scripting might be able to alleviate it. Scripts for checking that each CLN is properly conditionally wrapped, and that each conditional disable has the relevant library in its cases.

10 minutes ago, Porter said:

it would give us the best performance

I understand that performant parsing was one of the main motivations of this exercise; however, maybe let's first benchmark precisely the impact of different solutions.

Share this post


Link to post
Share on other sites

This small experiment, if not flawed, would suggest that actually CLN with a name constant is a few tens of ns faster than CLN with name written into.

CLNbenchmark.vi

Share this post


Link to post
Share on other sites

what about a calculated path (eg build a path control -- set to empty -- with your lib path). I was surprised by the 600 usec benchmark above -- my recollection from a few years ago was that overhead of a constant name in the CLFN vs one on the diagram was only a small overhead, maybe 13 usec vs 15 usec for some stupidly simple dll call.

Edited by smithd

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×

Important Information

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