09-03-2013 01:27 PM
Hi,
We are required to produce an XML-like log-file on our controllers. The controller we currently use is a cRIO-9014. It is not an option to "upgrade" at this point.
The WITSML data input will vary in length and contents between each call of the VI posted below.
The code is currently working and producing output as expected, however, the string generation takes a lot of resources to complete. For our "worst case" data-sets, we see the below sub-vi taking 30-40 seconds to proces, during which time the CPU usage is 100%.
This is obviously less than ideal. Now, that being said, new data for the log-file is produced at a rate of "one set every 60+ seconds" and CPU usage between producing the string is ~7% to 10%, however, we see it as important to improve performance as much as possible.
LV2011 code snippet here:
Since we know the length of the data going in, and we fix the decimals to 1 position, perhaps a pre-allocation of some sort would help, but at the end of the day (or function call), we need the output to be "string" written to a file.. Now, if someone thinks it may be possible to acheive the same bit-stream output but using only U8's as the data, I'm all ears.. .. in fact, I will start doing a re-write that converts the single-line string from each iteration to a U8 array, then insert that U8 array to a pre-allocated array.. but I think the overhead comes from the conversion more than the shift-register data?.. guess we will see.
09-03-2013 01:51 PM
Never realized just how much processing the "format into string" function actual uses.. I have used it similar to scanf and printf in a text based language..
So, replacing the "format into string" with an eight-input "concatenate string" and 3 "number to fractional string" has reduced the call time to about 7 seconds.. WAY better than the original 30+ seconds.
Better performance would still be desireable. Adding a "wait 1 ms" inside the for-loop keeps the target responsive and able to service other threads at the cost of bumping the overall call-time to ~10 seconds (obviously dependent on the length of the input data arrays.) (Using 0 ms as the input does not apear to have the desired functionality seeing as the "waiting for target to respond" comes up and the NI system manager CPU plot "freezes".)
Further suggestions and strategies are encouraged and welcomed.
Thanks,
-Q
09-03-2013 03:27 PM
Okay, I think I have a workable solution.
I went with the idea I had in the opening post and replaced the shift register with a pre-initialized array of U8's. Since I don't know the number of digits in every data point coming in, I pre-initialize with a worst case scenario in mind.
After the for-loop runs, I return the valid sub-set from the buffer array.
I still convert the array of U8 to string at the end, that way I don't have to change downstream code, and that doesn't seem to hurt my performance overly much.
I added in a throttle. Since wait 0 ms doesn't seem to work as documented (forces CPU to switch thread) and 1 ms quickly adds up over 4000 iterations, I put in place a simple throttle that allows the loop to rest x ms every n'th iteration. Using n of 10 and x of 1 on my target with my default data input, results in ~76% CPU usage and ~ 805 ms average completion time. (100% CPU and ~470ms with 0ms wait).
The code for those interested is included in the zip file (2011) and the most interesting is also shown as a snippet below (2013). Obviously read-ability and maintainability has taken a (slight) hit.. To be honest, I think I could have kept the post/pre amble's and the per iteration elements as string operations without significant performance hit, but I figured I may as well go all the way. The structure of the output is not likely to change any time soon.
09-04-2013 08:12 AM
Quick speedup:
Replace the Q/R in the for loop with a counter that decrements with each iteration. When the counter is equal to zero, fire your throttle case and reset the couter to the "n'th iteration(10)" control input. Saved me 40ms on my machine.
09-04-2013 08:17 AM
Thanks!
QR was another function that I had on my "low overhead" list.. guess it all adds up.
Excellent suggestion! Kudo'ed