Porter 45 Report post Posted August 26, 2017 View File 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 Porter Submitted 08/25/2017 Category General LabVIEW Version 2015 License Type BSD (Most common) 2 Quote Share this post Link to post Share on other sites
smithd 148 Report post Posted August 26, 2017 awesome, thanks for sharing! Quote Share this post Link to post Share on other sites
ensegre 69 Report post Posted August 27, 2017 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? Quote Share this post Link to post Share on other sites
ensegre 69 Report post Posted August 27, 2017 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? Quote Share this post Link to post Share on other sites
ensegre 69 Report post Posted August 27, 2017 Ok, I traced it down to that, for me, muParser Demo.vi crashes on its first call of DSDisposePtr in mupGetExprVars.vi. Just saying. Quote Share this post Link to post Share on other sites
MikaelH 173 Report post Posted August 27, 2017 Do you have a compiled 64 bit dll? I thought everybody had migrated to LV-64 bit nowadays?!? Quote Share this post Link to post Share on other sites
smithd 148 Report post Posted August 27, 2017 3 minutes ago, MikaelH said: I thought everybody had migrated to LV-64 bit nowadays?!? Erm...no. Quote Share this post Link to post Share on other sites
MikaelH 173 Report post Posted August 27, 2017 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. Quote Share this post Link to post Share on other sites
smithd 148 Report post Posted August 27, 2017 (edited) 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 August 27, 2017 by smithd Quote Share this post Link to post Share on other sites
MikaelH 173 Report post Posted August 27, 2017 (edited) 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 August 27, 2017 by MikaelH Quote Share this post Link to post Share on other sites
ensegre 69 Report post Posted August 28, 2017 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 *** Quote Share this post Link to post Share on other sites
ensegre 69 Report post Posted August 28, 2017 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 1 Quote Share this post Link to post Share on other sites
Porter 45 Report post Posted August 28, 2017 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. Quote Share this post Link to post Share on other sites
ensegre 69 Report post Posted August 28, 2017 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. 1 Quote Share this post Link to post Share on other sites
Porter 45 Report post Posted August 28, 2017 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 Quote Share this post Link to post Share on other sites
ensegre 69 Report post Posted August 28, 2017 (edited) 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 August 28, 2017 by ensegre 1 Quote Share this post Link to post Share on other sites
Porter 45 Report post Posted August 29, 2017 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? Quote Share this post Link to post Share on other sites
Porter 45 Report post Posted August 29, 2017 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. Quote Share this post Link to post Share on other sites
Porter 45 Report post Posted August 29, 2017 (edited) Modified version with mupGetExprVar fixed, path wired to CLNs, muParser dll moved to mupLib directory: muParser.zip Lets call it V0.0.2 Edited August 29, 2017 by Porter Quote Share this post Link to post Share on other sites
ShaunR 821 Report post Posted August 29, 2017 (edited) 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 August 29, 2017 by ShaunR 1 Quote Share this post Link to post Share on other sites
ensegre 69 Report post Posted August 29, 2017 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. Quote Share this post Link to post Share on other sites
Porter 45 Report post Posted August 29, 2017 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. Quote Share this post Link to post Share on other sites
ensegre 69 Report post Posted August 29, 2017 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. Quote Share this post Link to post Share on other sites
ensegre 69 Report post Posted August 29, 2017 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 Quote Share this post Link to post Share on other sites
smithd 148 Report post Posted August 29, 2017 (edited) 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 August 29, 2017 by smithd Quote Share this post Link to post Share on other sites