How to find the most time-consuming function?

BlitzMax Forums/BlitzMax Programming/How to find the most time-consuming function?

Tibit(Posted 2005) [#1]
Somewhere I got some function that slows everything down. I'm guessing it has to do with my packing functions because they are no way optimized and I have no idea what to look for or how to code them in a more efficient way. It's easy to check the time a function takes to execute by simply runnin it 100000 times and check the total time. But how do I know when a function is slow or fast? I mean any function takes some time. What would be considered fast or slow? Anyone who has any experience in this?


LarsG(Posted 2005) [#2]
You have to measure it to the rest of your code...
you can for example run different functions repeatively, and timeing them with millisecs, to get an quick overview of which function is the most time consuming..


SoggyP(Posted 2005) [#3]
Hello.

You need to consider each function in relation to the other functions around it. How often is each function being called per iteration - the function might not be particularly slow but if it's being called a massive number of times then that's where it will impact.

Whether a function is slow or fast is relative: if it's doing an overly complex task then it will take a long time - see if there's a way you can run a particular function in chunks. Check out the code archives or post code and ask for more optimum solutions.

Goodbye.


Perturbatio(Posted 2005) [#4]
are you using flushmem inside your loops (I'm assuming your packing function uses a for or while loop somewhere in it)?
Flushmem can dramatically speed up a large loop.


tonyg(Posted 2005) [#5]
If you know your most used/most time consuming function you, at least, have a way of knowing where potential time savings are.
Looking at a function which takes 0-5ms and is called once won't be high on your optimisation lists even if you save 1 ms.
If you have a function which takes 1000 ms and is called
every loop (or every nth loop) and you save 50ms it's a better use of time.
Just an idea, how about creating a small viewport which displays a coloured rect in proportion to the function time to get a graphical output of where you're spending time. Alternatively, save the times to a type and then use that at the end to create a graph of time spent along with the raw data.


Tibit(Posted 2005) [#6]
I guess I have to test each function with my benchmark test. All my packing stuff does pretty small but complex things which should take but a fraction of the CPU. I mean if the pack/unpack makes the game slower (online) than by sending tha unpacked Data then somethings is really wrong =)


are you using flushmem inside your loops (I'm assuming your packing function uses a for or while loop somewhere in it)?
Flushmem can dramatically speed up a large loop.
Can you explain how/why, seems like a good thing to know.


ImaginaryHuman(Posted 2005) [#7]
You might find that sometimes an optimization that you try to make, such as compressing something, may actually end up being slower and less efficient than the routine was before you optimized it. It really depends. Optimizing doesn't always give you better results. I would compare the optimized version of something with the original and see how it fares. Sometimes a more elegant algorithm is better, sometimes it makes a total meal of it.


Dreamora(Posted 2005) [#8]
"more elegant algorithm" have the problem that they were often created for "industrial usage" with really large amount of data and stuff and not for "little games" which is why their "computer science small constant" overhead sometimes tends too make them run worse than naive algorithm implementations because the constant was never meant for 1000 operations or similar "funny little values" ;-)

Can only agree with AngelDaniel, perhaps even extend it:

If you optimize stuff you should not only check single functions on their runtimes but check for crossreferences that might have influence on other functions.


FlameDuck(Posted 2005) [#9]
Bollocks. A more elegant algorithm (ie. one with a lower degree of time complexity) will always be more effective than one with a higher degree of time complexity. Particularly with larger datasets, or many itterations. If an algorithm has linear time complexity (for example) on 100.000 objects run 100.000 times, it will still have linear time complexity on a 100 objects with 100 itterations, the time factor will just be smaller. The only worthwhile optimisation is to design an more elegant algorithm, with a lower degree of time complexity, namely logarithmic or constant.

In this light, the better test would be not to test the same function several thousands of times with the same input, but instead test it only once, with increasingly larger inputs. That way you can get a good picture about which factors contribute to slower code.

BlitzMax really could use a code profiler tho'.


Perturbatio(Posted 2005) [#10]
Can you explain how/why, seems like a good thing to know.

The BlitzWiki has a reasonable page on flushmem


Tibit(Posted 2005) [#11]
I see now why Flushmem help when I do that many irritations. I did really speed up the test times.

FlameDuck I agree that looping it thousands of times may not be the best way of measure, still if I loop it less than a couple of tousand times, the time to complete the function will be smaller than a millisec. Then I can't measure it, right?

Also I have the problem that all packing functions seems to run fast enought, 22 microsecs at most. Is there a crucial limit I should watch for and have as high-cap? Let's say I run a function that takes 22microsecs five times when a pack arrives, that would mean a 0,1 millisec delay which shouldn't be noticable.

I re-made the test. This seems to give a much better measure. Anyone has any idea on how to improve it?

Strict

Graphics 80,40,0,-1
Global Loops = 10000000'Set This depending on the speed of your function
	
Local T%=0, MinFlex!=4321, MaxFlex! , PicoDelay% = 0

For Local NR_Times = 1 To 5'Do the test 5 times
	
	Local Start = MilliSecs()
	
	'	\	\	\	\	\	\	\	\
	For Local Count = 0 To Loops 
		' I N S E R T   F U N C T I O N   T O	 T E S T   H E R E
	
		
	
	
		FlushMem
		' A N D   C H E C K S   H O W   L O N G   I T   T A K E S 
	Next
	'	/	/	/	/	/	/	/	/
	
	Local Tex% = ( MilliSecs() - Start )'Time since loops started
	Local Flex! = 1000*( Double(Tex) / Double(Loops) )'time For each loop
	
		T:+1
		If Flex > MaxFlex MaxFlex = Flex'Get slowest time ')
		If Flex < MinFlex MinFlex = Flex'Get best time =)

	Print "Test"+T+" - Time for "+Loops+" loops is "+Tex+" MilliSec. Each Loop Avg :"+Flex+" MicroSec"
	CalcAvg.Create( Tex, Flex )'Time, EachTime
	FlushMem
	Delay 100
Next

CalcAvg.Avg()

Print ""
Print "AVERAGE Time for "+Loops+" loops is "+CalcAvg.AvgMilli+" MilliSec."
Print ""
Print "Each Loop Avg :"+CalcAvg.AvgMicro+" MicroSec"
Print ""
Print "In PICO sec: "+CalcAvg.AvgMicro*1000


Type CalcAvg

	Global AvgMicro!,AvgMilli!,List2:TList
	Field Micro!,Milli!

	Function Create(Milli!,Micro!)'Milli=TimeForAllLoops, Micro=TimeFor1Loop
		Local C:CalcAvg = New CalcAvg
		If List2 = Null Then List2 = CreateList()
		List2.Addlast(C)
		C.Micro = Micro
		C.Milli = Milli
	EndFunction
	Function Avg()
		Local TotalMicro!,TotalMilli!,Count
		For Local C:CalcAvg = EachIn List2
			TotalMicro:+ C.Micro
			TotalMilli:+ C.Milli
			Count:+1
		Next
		AvgMicro = TotalMicro/Count
		AvgMilli = TotalMilli/Count
	EndFunction
	
EndType	



Tibit(Posted 2005) [#12]
What about doing it simple and right within the actuall code of the main program?

Time = Millisecs()

Update() 'Function to test

TimeTook = Millisecs() - Time

But how would I make the above work if Update() takes less than 1 millisec. I want a better timer..

What is the precition of the CPU clock? Is that what blitz uses? It it impossible to measure in nanosecs() or better?


BadJim(Posted 2005) [#13]
I suggest putting a counter in your functions so you get an idea of how often they are being called.


"A more elegant algorithm (ie. one with a lower degree of time complexity) will always be more effective than one with a higher degree of time complexity."

Not true. Take, for example, the quicksort vs insertion sort. On large disorganised databases the quicksort wins hands down.

However, the recursive function calls are time consuming. With just a few elements the insertion sort will be a lot faster since the time complexity isn't slowing it down yet. Optimised quicksorts sort down to small groups then use another algorithm to sort the small groups out.

Also, the insertion sort has much better time complexity on mostly sorted data. If it sorts something in a game loop then it may already be mostly ordered from the previous frame and the insertion sort will be faster.


LeisureSuitLurie(Posted 2005) [#14]
Unless I dreamt it, I think Mark mentioned support for code profiling at some point.

It appears not to have been implemented yet.


teamonkey(Posted 2005) [#15]
I wrote a simple profiler a while ago. It should do the job.

http://blitzbasic.com/Community/posts.php?topic=43396