Profiler
Monkey Forums/Monkey Code/Profiler
| ||
This is the profiler code I use myself.
'=============================
'profiler.monkey by Belimoth
'uncomment the commented code to have the profiler profile itself :P
'=============================
Import mojo
'=============================
Class cProfilerMap Extends StringMap<cProfiler>
End
'=============================
Class Profiler
Const NUMBER_OF_CALLS_TO_AVERAGE:Int = 100
Global profilers := New cProfilerMap
Global running := New List<cProfiler>
'Global startProfiler := New cProfiler("Profiler Start", NUMBER_OF_CALLS_TO_AVERAGE, False)
'Global stopProfiler := New cProfiler("Profiler Stop", NUMBER_OF_CALLS_TO_AVERAGE, False)
Function Start:Void(profilerName:String, callsMax:Int = NUMBER_OF_CALLS_TO_AVERAGE)
'startProfiler.Start()
If profilers.Contains(profilerName)
profilers.Get(profilerName).Start()
Else
Local parent:cProfiler
If running.IsEmpty()
parent = Null
Else
parent = running.Last()
Endif
If parent = Null
Local profilerNew := New cProfiler(profilerName, callsMax, True)
profilers.Add(profilerName, profilerNew)
profilerNew.Start()
Elseif parent.children.Contains(profilerName)
parent.children.Get(profilerName).Start()
Else
Local profilerNew := New cProfiler(profilerName, callsMax, True)
parent.children.Add(profilerName, profilerNew)
profilerNew.Start()
Endif
Endif
'startProfiler.Stop()
End
Function Stop:Void(profilerName:String = "this doesn't really matter")
'stopProfiler.Start()
running.Last().Stop()
'stopProfiler.Stop()
End
Function Output:Void()
Print ""
Print "PROFILER RESULTS"
Print ""
'Print startProfiler
'Print stopProfiler
Local profilerTemp:cProfiler
For profilerTemp = Eachin profilers.Values()
PrintProfiler(profilerTemp)
Next
Print ""
End
Function PrintProfiler:Void(profiler:cProfiler, indent:String = "")
Print indent + profiler
If profiler.HasChildren()
Local profilerTemp:cProfiler
For profilerTemp = Eachin profiler.children.Values()
PrintProfiler(profilerTemp, indent + " ")
Next
Endif
End
End
'=============================
Class cProfiler
Field name:String
Field timeStart:Int
Field calls:Int
Field callsMax:Int
Field total:Float
Field result:Float
Field doneCounting:Bool
Field children:cProfilerMap
Field nest:Bool
Method New(name:String, callsMax:Int, nest:Bool = False)
Self.name = name
Self.callsMax = callsMax
Self.nest = nest
If nest = True
Self.children = New cProfilerMap
Endif
End
Method New(callsMax:Int)
Self.name = "Profiler"
Self.callsMax = callsMax
Self.nest = False
End
Method GetResult:Float()
Return result
End
Method HasChildren:Bool()
Return Not( children.IsEmpty() )
End
Method Start:Void()
If nest Then Profiler.running.AddLast(Self)
timeStart = Millisecs()
If calls >= callsMax
calls = 0
total = 0.0
Endif
End
Method Stop:Void()
If nest Then Profiler.running.RemoveLast() 'should be self
Local timePassed:Int = Millisecs() - timeStart
total += timePassed
calls += 1
If calls >= callsMax
doneCounting = True
result = total / calls
Endif
End
Method ToString:String()
If doneCounting
Return name + ": " + result
Else
Return name + " is not done counting"
Endif
End
End
'=============================
|
| ||
Here is how it would be used:
'=============================
'example.monkey
'=============================
Strict
Import mojo
Import profiler
'=============================
'============MAIN=============
Function Main:Int()
New MyApp()
Return 1
End
'=============================
'=============APP=============
Class MyApp Extends App
Field fpsProfiler:cProfiler
'=============================
Method OnCreate:Int()
fpsProfiler = New cProfiler(10)
Profiler.Start("OnCreate", 1)
'initializing stuff
SetUpdateRate(60)
Profiler.Stop("OnCreate")
Return 1
End
'=============================
Method OnUpdate:Int()
Profiler.Start("OnUpdate")
'doing stuff
Profiler.Stop("OnUpdate")
If KeyHit(KEY_ENTER)
Profiler.Output()
Endif
Return 1
End
'=============================
Method OnRender:Int()
Profiler.Start("OnRender")
Profiler.Start("Drawing Stuff")
'drawing stuff
Profiler.Stop("Drawing Stuff")
'drawing other stuff
Profiler.Stop("OnRender")
fpsProfiler.Stop()
fpsProfiler.Start()
DrawText("FPS: " + Int(1000 / fpsProfiler.GetResult()), 1, 1)
Return 1
End
'=============================
End
'=============================
As you can see there are two ways to use it: a) Standalone profilers that you manage yourself, as in fpsProfiler above. b) Automatically managed profilers that are named and will show all of their results together when Profiler.Output() is called. It is nifty :) |
| ||
The syntaxes are:myProfiler = New cProfiler(numberOfCallsToAverage:Int) myProfiler.Start() myProfiler.Stop() myProfiler.GetResult() Profiler.Start("My Profile", numberOfCallsToAverage:Int = 100)
Profiler.Stop("My Profile")
Profiler.Output()One caveat, don't do this with the named profilers: Profiler.Start("Profile A")
Profiler.Start("Profile B")
Profiler.Stop("Profile A")
Profiler.Stop("Profile B")I'm not sure why you would do that, but just so you are aware, it will expect named profilers to be nested properly. |
| ||
| You can see it in action in this demo. |
| ||
| Excellent. Thank you for sharing. |
| ||
| Great work I am going to use this on my current project that has a bottle neck. |
| ||
| I know this could be a stupid question, but what do I use this for? |
| ||
| You use it to see how long each part of your program takes on average, so if things are going slow you can find out where the problem is :) |
| ||
| Okay thanks! |
| ||
| EDIT: Double post :( |
| ||
| Been putting some more work into this for my framework. The new version doesn't do any averaging yet, but it DOES have the ability to graph its results. The DrawLine and DrawRect commands look like absolute garbage on HTML5, so I ended up using an image-based approach with WritePixels. I haven't used Monkey's WritePixels before so I'm sure there are plenty of optimizations to be made. A basic usage would look like this:
Class MyApp Extends App
Method OnUpdate()
Profiler.Update()
Profiler.Start("OnUpdate", [255, 0, 0])
...
Profiler.Stop("OnUpdate")
End
Method OnRender()
Profiler.Start("OnRender", [0, 128, 255])
...
Profiler.Stop("OnRender")
Profiler.Draw(0, 0)
End
End
Still a work in progress. EDIT: Also there is a "dummy" profiler that gets substituted for release mode. That way you don't have to go through and remove all the function calls. EDIT: Fixed a small error with the rendering. EDIT: More small fixes. |