[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [amibroker] Timing test example between Arrays and Loops



PureBytes Links

Trading Reference Links

Tomasz,

I had a typo in the previous results.  The 1,000 and 10,000 cases were  
swapped.

I still can not explain the differences I am seeing.  I have tried  
rearranging my code in many ways and the differences remain about the  
same, 2x more time for 10x shorter loop.  There might be some overhead  
associated with the timer function itself in my system since I am  
running XP in a Parallels virtualization environment on a Mac.  There  
might be an emulated component that is making these numbers come out  
different than I expect and your results also.

However, even though I am not certain about the absolute results, on a  
relative basis I have already found an interesting speed difference in  
3 different approaches to the example problem, which I will explain  
for the benefit of others.

I tried three different ways to do a Max() function in a loop (times  
are per 1000 bars over a 10,000 bar length):

1.  MaxPrice = Max( MaxPrice, C[i] ); // 585us
2.  MaxPrice = IIf( MaxPrice < C[i], C[i], MaxPrice ); // 860us
3.  if ( MaxPrice < C[i] ) { MaxPrice = C[i]; } // 100us

formula 2 was 1.5 times slower than formula 1, which I would expect.
formula 3 was 6 times faster than formula 1, which was a big surprise.

I was sure that a Max() function would be faster than an if control  
statement.  Obviously, my intuition was not as good as the facts  
proved.  On further thought though it makes sense that it should be  
faster because, just one comparison has to take place and no  
assignment most of the time.  So, it only has to do half the work --  
but 6 times faster?

This example shows why it is important to have a good intuitive  
understanding of which AFL operations are fast or slow to code the  
fastest formula.

4. MaxPrice = LastValue( HHV( C, Length ) ); // 23us

The array version of this solution in formula 4, blows away the others  
by a factor of 2 to 20 depending on the overhead details -- as long as  
all the bars are used in both cases.  You certainly know how to  
optimize the array operators.  Fantastic job!

However, when the array has to use all the bars, and a loop only has  
to use 10% of the bars, then the loop could end up blowing away the  
array operations.  This is not the most common case though.  It would  
be good if the problem was simplified to the extent that the array  
operations were always faster,  Then no thought would have to be given  
to loops at all.  If the number of bars back can optionally be set to  
a smaller number, arrays will always be the fastest solution by a  
mile.  Then loops would only be used when the logic is too complex for  
built-in array operations. -- just thinking out loud.

I made some minor improvements to my example code, so I am attaching  
it again at the end of this thread and snipping off the old one.

Best regards,
Dennis


On Jul 4, 2009, at 3:31 PM, Dennis Brown wrote:

> Tomasz,
>
> Thank you for looking at it.
>
> On my machine, I get the following results:
>
> 1,000 Base cycle length:
> 	Loop Overhead = 181us / 1000 bars
> 	Loop Operator = 576us / 1000 bars
>
> 10,000 Base cycle length:
> 	Loop Overhead = 240us / 1000 bars
> 	Loop Operator = 1024us / 1000 bars
>
> Best regards,
> Dennis
>
> On Jul 4, 2009, at 3:05 PM, Tomasz Janeczko wrote:
>
>> Hello,
>>
>> I have run your code and results are pretty much the same in both
>> settings.
>>
>> Best regards,
>> Tomasz Janeczko
>> amibroker.com
>>
>> Dennis Brown wrote:
>>> Hello Tomasz,
>>>
>>> Below is some AFL I wrote to explore the speed difference between
>>> Array and Loop operations.  I wanted to explore a number of  
>>> different
>>> array operations to see if I could speed up my indicators.
>>>
>>> It shows the difference in speed for finding the highest value in a
>>> whole array.
>>> I am not sure my math is correct though, because one of the results
>>> seem counter intuitive.
>>>
>>> For instance:
>>>
>>> I test a for() loop that does nothing in order to get the loop
>>> overhead.  I subtract that number from the loop that is doing the
>>> real
>>> operation to get just the time to do the one operation.  I  
>>> subtracted
>>> off the loop overhead because a loop will usually have a lot of
>>> operations that spread out the overhead.  I do this for 1,000 cycles
>>> and for 10,000 cycles.
>>>
>>> I would expect the time to execute a single AFL line after
>>> subtracting
>>> off the overhead would be the same regardless of the number of
>>> cycles.  However, the results say that it takes almost twice as long
>>> to execute that operation in a 1,000 cycle loop than a 10,000 cycle
>>> loop.  Since this is not what I would expect, so I have to assume I
>>> did something wrong.  I figured I should ask for a review before
>>> making statements about how much faster arrays are.
>>>
>>> On the other hand, the array operation shows almost one third of the
>>> time per bar when going from 1,000 to 10,000 bars, which is
>>> reasonable.
>>>
>>> Am I missing something in my understanding, or am I just a lousy AFL
>>> coder? :)
>>>
>>> Best regards,
>>> Dennis
>>>

////////////////////////////////////////////////////////////////////////////////////////
// Simple test code to show speed difference between loop and array  
operations -- 7/4/2009 Dennis Brown
// Edit this AFL for each comparison of equivelent operations
// Check both 1000 and 10,000 bar operations to derive the overhead
// Timing on one pass is jumpy, so it will avarage passes for a large  
term average -- just wait a while
// Watch out for differences in operation lengths due to one way  
nature of SetBarsRequired()
// Do the short cycle length first, then the long one, then edit AFL  
with short one selected to reset SBR -- what a pain
// If I could switch to lower SBR numbers on the fly, I would display  
a complete curve with overheads
// Number of bars loaded seems to always be 200 more than the  
requested number with SBR
// Interestingly, //comments seem to run a little faster than /*  
comments */ in the timing loop
//
LoopText = ArrayText = ""; // init and make global

function LoopOperation( Length ) { /* Edit this function with the loop  
operator to be tested */
	GetPerformanceCounter( 1 ); /* reset the timer */
	MaxPrice = 0;
	MinPrice = 0;
	for ( i=0; i<Length; i++ ) {
		/* insert the loop operation(s) to be tested below */
		if ( MaxPrice < C[i] ) { MaxPrice = C[i]; }
//		MaxPrice = Max( MaxPrice, C[i] );
//		MaxPrice = IIf(  MaxPrice < C[i], C[i], MaxPrice );
	}
	time = GetPerformanceCounter();
	LoopText = "if ( MaxPrice < C[i] ) { MaxPrice = C[i];" ; /* duplicate  
operator here for display output */
	return round( (1000000/Length)*time ); /* returns time in  
microseconds per 1000 */
}

function ArrayOperation( Length ) { /* Edit this function with the  
array operator to be tested */
	GetPerformanceCounter( 1 );
	/* insert the array operation(s) to be tested below */
	MaxPrice = LastValue( HHV( C, Length ) );
	time = GetPerformanceCounter();
	ArrayText = "MaxPrice = LastValue( HHV( C, Length ) );" ; /*  
duplicate operator here for display output */
	return round( (1000000/Length)*time );
}

function LoopOverhead( Length ) {
	GetPerformanceCounter( True );
	for ( i=0; i<Length; i++ ) { ; }
	time = GetPerformanceCounter();
	return round( (1000000/Length)*time );
}

// main routine
LastSBRLength = StaticVarGet( "LastSBRParameterValue" );
SBRLength = Param( "Base cycle length", 1000, 1000, 10000, 9000 );
Length = BarCount-200;
if ( ParamTrigger("Reset Averages", "Click to Reset" ) OR  
LastSBRLength != SBRLength OR Length != SBRLength ) {
	StaticVarSet( "TimeSum0", 0 );
	StaticVarSet( "TimeSum1", 0 );
	StaticVarSet( "TimeSum2", 0 );
	StaticVarSet( "TimeCycles", 0 );
	StaticVarSet( "LastSBRParameterValue", SBRLength );
	Title = " Warning -- SetBarsRequired() can not reduce bars --  Edit  
AFL to reset SBR or increase length parameter";
}
else { // only execute the code if all the bar requirements match so  
we get accurate results (i.e., first cycle is all bars)

	TimeSum0 = StaticVarGet( "TimeSum0" );
	TimeSum1 = StaticVarGet( "TimeSum1" );
	TimeSum2 = StaticVarGet( "TimeSum2" );
	TimeCycles = 1 + StaticVarGet( "TimeCycles" );

	TimeSum0 += LoopOverhead( Length ); // loop overhead to be tested
	TimeSum1 += LoopOperation( Length ); // loop operator to be tested
	TimeSum2 += ArrayOperation( Length ); // array operator to be tested

	StaticVarSet( "TimeSum0", TimeSum0 );
	StaticVarSet( "TimeSum1", TimeSum1 );
	StaticVarSet( "TimeSum2", TimeSum2 );
	StaticVarSet( "TimeCycles", TimeCycles );

	Time0 = round( TimeSum0 / TimeCycles );
	Time1 = round( TimeSum1 / TimeCycles );
	Time2 = round( TimeSum2 / TimeCycles );

	OpTime =  Time1-Time0; // subtract off the constant loop overhead
	speedup = NumToStr( OpTime /Time2, 0.1 );
	if ( Length != SBRLength ) { warning = " !!! Warning Length  
Mismatch !!!"; } else { warning = ""; }

	Title = "Per 1000 bars (cycles) Tming Test\n" +
	"Bars Loaded = " + BarCount + "\n" +
	"Base Cycle Length = " + Length + warning + "\n\n" +
	"Looped Operation:  " + LoopText +
	"\n\n" +
	"Loop Overhead    = " + time0  + "us\n" +
	"Looped Operator = " + OpTime + "us\n\n" +
	"Array Operation:   " + ArrayText +
	"\n\n" +
	"Array Operator      = " + time2 + "us\n" +
	"Speedup Factor   = " + speedup;

} // end of active code

RequestTimedRefresh( 1 );
//Override all bar requirements for our test
SetBarsRequired( SBRLength, sbrAll );




------------------------------------

**** IMPORTANT PLEASE READ ****
This group is for the discussion between users only.
This is *NOT* technical support channel.

TO GET TECHNICAL SUPPORT send an e-mail directly to 
SUPPORT {at} amibroker.com

TO SUBMIT SUGGESTIONS please use FEEDBACK CENTER at
http://www.amibroker.com/feedback/
(submissions sent via other channels won't be considered)

For NEW RELEASE ANNOUNCEMENTS and other news always check DEVLOG:
http://www.amibroker.com/devlog/

Yahoo! Groups Links

<*> To visit your group on the web, go to:
    http://groups.yahoo.com/group/amibroker/

<*> Your email settings:
    Individual Email | Traditional

<*> To change settings online go to:
    http://groups.yahoo.com/group/amibroker/join
    (Yahoo! ID required)

<*> To change settings via email:
    mailto:amibroker-digest@xxxxxxxxxxxxxxx 
    mailto:amibroker-fullfeatured@xxxxxxxxxxxxxxx

<*> To unsubscribe from this group, send an email to:
    amibroker-unsubscribe@xxxxxxxxxxxxxxx

<*> Your use of Yahoo! Groups is subject to:
    http://docs.yahoo.com/info/terms/