FastOp vs. alternatives
thomas_braun
I recently was faced with the easy sounding task of setting an existing wave to zero. And doing it really fast.
I played around a bit and got some, at least for me, surprising results using the following code:
Function doStuff()
variable i, timer, numRuns, waveSize
numRuns = 10
waveSize = 2^24
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
WaveClear data
endfor
printf "Plain creation: %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data = 0
WaveClear data
endfor
printf "Init with value: %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
FastOp data = 0
WaveClear data
endfor
printf "FastOp: %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
data[] = 0
WaveClear data
endfor
printf "Plain assignment: %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
// not sure how to set the complete wave just to zero
MatrixOP/FREE data = data - data
WaveClear data
endfor
printf "MatrixOP (single thread): %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
// not sure how to set the complete wave just to zero
MatrixOP/FREE/NTHR=0 data = data - data
WaveClear data
endfor
printf "MatrixOP (multithreaded): %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
Multithread data[] = 0
WaveClear data
endfor
printf "Multithread assignment: %g\r", stopmstimer(timer)/1e6/numRuns
End
variable i, timer, numRuns, waveSize
numRuns = 10
waveSize = 2^24
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
WaveClear data
endfor
printf "Plain creation: %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data = 0
WaveClear data
endfor
printf "Init with value: %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
FastOp data = 0
WaveClear data
endfor
printf "FastOp: %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
data[] = 0
WaveClear data
endfor
printf "Plain assignment: %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
// not sure how to set the complete wave just to zero
MatrixOP/FREE data = data - data
WaveClear data
endfor
printf "MatrixOP (single thread): %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
// not sure how to set the complete wave just to zero
MatrixOP/FREE/NTHR=0 data = data - data
WaveClear data
endfor
printf "MatrixOP (multithreaded): %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
Multithread data[] = 0
WaveClear data
endfor
printf "Multithread assignment: %g\r", stopmstimer(timer)/1e6/numRuns
End
On my windows box using IP6 latest I get:
•dostuff()
Plain creation: 0.0398167
Init with value: 0.212837
FastOp: 0.0620453
Plain assignment: 0.268874
MatrixOP (single thread): 0.12646
MatrixOP (multithreaded): 0.12627
Multithread assignment: 0.0722515
Is
FastOp
really the best choice for that?I would have expected that the multithreaded solution is the fastest one.
First MatrixOP: The multithreading in MatrixOP is not going to kick in because you are not working with multiple layers.
FastOP: I suggest that you avoid it.
Multithread is the best approach for this task.
A.G.
WaveMetrics, Inc.
May 11, 2015 at 09:30 am - Permalink
A.G.
WaveMetrics, Inc.
May 12, 2015 at 03:43 pm - Permalink
So I'll stick with
Multithread
for now.Regarding
MatrixOP
you are of course right.And the new MatrixOP functions are nice!
May 13, 2015 at 12:28 pm - Permalink
variable i, timer, numRuns, waveSize
numRuns = 10
waveSize = 2^24
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
WaveClear data
endfor
printf "Plain creation: %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data = 0
WaveClear data
endfor
printf "Init with value: %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
FastOp data = 0
WaveClear data
endfor
printf "FastOp: %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
data[] = 0
WaveClear data
endfor
printf "Plain assignment: %g\r", stopmstimer(timer)/1e6/numRuns
#if IgorVersion() >= 7
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data // Not actually necessary
// not sure how to set the complete wave just to zero
MatrixOP/FREE data = zeroMat(waveSize, 0, 4) // REQUIRES IGOR 7
WaveClear data
endfor
printf "MatrixOP (zeroMat): %g\r", stopmstimer(timer)/1e6/numRuns
#endif
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
// not sure how to set the complete wave just to zero
MatrixOP/FREE data = data * 0
WaveClear data
endfor
printf "MatrixOP (single thread): %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
Multithread data[] = 0
WaveClear data
endfor
printf "Multithread assignment: %g\r", stopmstimer(timer)/1e6/numRuns
End
Here are the results on my Windows machine (64-bit release build of Igor 7):
•doStuff() Plain creation: 0.0446025 Init with value: 0.49112 FastOp: 0.0522403 Plain assignment: 0.491873 MatrixOP (zeroMat): 0.158381 MatrixOP (single thread): 0.167936 Multithread assignment: 0.0947317
WARNING: If you want to run the test yourself using Igor 7, you must download the nightly build dated May 14, 2015 or later. There was a bug in MatrixOP zeroMat prior to May 14, 2015 that could cause a crash when the test code above is executed.
One other note: the Make line in the test block for MatrixOp zeroMat is unnecessary, since zeroMat will create the output wave on its own. Removing that line makes the timing for the MatrixOp zeroMat block:
MatrixOP (zeroMat): 0.113347
I tried using MatrixOP const() as AG suggested but I haven't figured out yet how to get that function to return a wave whose type is double precision floating point.
May 14, 2015 at 06:52 am - Permalink
Note that the following comments apply to IP7.
For example, you can create an int16 output this way:
MatrixOP/O aa=const(10,20,int16(someValue))
For DP:
Note that fp64() may not be necessary if the token "someValue" is already DP. For example,
May 14, 2015 at 03:15 pm - Permalink
MatrixOp
const.variable i, timer, numRuns, waveSize
numRuns = 10
waveSize = 2^24
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
WaveClear data
endfor
printf "Plain creation: %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data = 0
WaveClear data
endfor
printf "Init with value: %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
FastOp data = 0
WaveClear data
endfor
printf "FastOp: %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
data[] = 0
WaveClear data
endfor
printf "Plain assignment: %g\r", stopmstimer(timer)/1e6/numRuns
#if IgorVersion() >= 7
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
MatrixOP/FREE data = const(waveSize, 0, fp64(0))
WaveClear data
endfor
printf "MatrixOP (const): %g\r", stopmstimer(timer)/1e6/numRuns
#else
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
// not sure how to set the complete wave just to zero
MatrixOP/FREE data = data * 0
WaveClear data
endfor
printf "MatrixOP (const using workaround): %g\r", stopmstimer(timer)/1e6/numRuns
#endif
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
Multithread data[] = 0
WaveClear data
endfor
printf "Multithread assignment: %g\r", stopmstimer(timer)/1e6/numRuns
End
This gives on my windows box with latest IP7:
•dostuff() Plain creation: 0.0398512 Init with value: 0.305097 FastOp: 0.0432722 Plain assignment: 0.306107 MatrixOP (const): 0.0908975 Multithread assignment: 0.0686955
So MatrixOP is gaining ground, altough FastOP still leads.
May 19, 2015 at 09:59 am - Permalink
1. WaveTransform setZero data
2. WaveTransform /V=0 setConstant data
Oh, and your testing code should remove all "Make" instructions in MatrixOP cases.
A.G.
May 19, 2015 at 01:25 pm - Permalink
What's wrong with FastOp?
May 19, 2015 at 11:25 pm - Permalink
Larry Hutchinson
WaveMetrics
support@WaveMetrics.com
May 20, 2015 at 07:39 am - Permalink
With the updated code:
variable i, timer, numRuns, waveSize
numRuns = 10
waveSize = 2^24
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
WaveClear data
endfor
printf "Plain creation: %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data = 0
WaveClear data
endfor
printf "Init with value: %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
FastOp data = 0
WaveClear data
endfor
printf "FastOp: %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
data[] = 0
WaveClear data
endfor
printf "Plain assignment: %g\r", stopmstimer(timer)/1e6/numRuns
#if IgorVersion() >= 7
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
MatrixOP/FREE data = const(waveSize, 0, fp64(0))
WaveClear data
endfor
printf "MatrixOP (const): %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
WaveTransform/O setZero data
WaveClear data
endfor
printf "WaveTransform (setZero): %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
WaveTransform/O/V=0 setConstant data
WaveClear data
endfor
printf "WaveTransform (setConstant): %g\r", stopmstimer(timer)/1e6/numRuns
#endif
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
Make/D/FREE/N=(waveSize) data
Multithread data[] = 0
WaveClear data
endfor
printf "Multithread assignment: %g\r", stopmstimer(timer)/1e6/numRuns
End
I now get
•doStuff() Plain creation: 0.037367 Init with value: 0.307956 FastOp: 0.0427034 Plain assignment: 0.306808 MatrixOP (const): 0.0913224 WaveTransform (setZero): 0.0473604 WaveTransform (setConstant): 0.0428477 Multithread assignment: 0.0675981
And so
WaveTransform
andFastOp
are the current winners.May 20, 2015 at 09:20 am - Permalink
variable i, timer, numRuns, waveSize
numRuns = 10
waveSize = 2^24
Make/B/U/FREE/N=(waveSize) data
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
FastOp data = 0
endfor
printf "FastOp: %g\r", stopmstimer(timer)/1e6/numRuns
timer = startmsTimer
for(i = 0; i < numRuns; i += 1)
WaveTransform setZero data
endfor
printf "WaveTransform setZero: %g\r", stopmstimer(timer)/1e6/numRuns
End
On my machine:
FastOp: 0.0385148
WaveTransform setZero: 0.00623636
... and yes, I did not write FastOp :)
May 20, 2015 at 11:26 am - Permalink