I'm working in dm-script and need to measure the execution time of various functions. Currently, I use the following pattern to measure time:
Number time1, time2
time1 = GetCurrentTime()
// run some function
time2 = GetCurrentTime()
Result(CalcTimeUnitsBetween(time1, time2, 1) + "\n")
I would like to encapsulate this behavior into a reusable function that accepts another function (by its name) as an input parameter. For example, I attempted the following:
Void time_elapse(function_name)
{
Number time1, time2
time1 = GetCurrentTime()
function_name()
time2 = GetCurrentTime()
Result(CalcTimeUnitsBetween(time1, time2, 1) + "\n")
}
However, I'm not sure if passing a function as a parameter in this way is supported in dm-script, or if there is a better approach.
What I've Tried:
Questions:
Any insights or alternative approaches would be appreciated.
Why would you want to do that?
Any additional code-execution to the to-be-measured code will just add to the measurement time.
Is function_name really just the name? i.e. Will it be only used for functions that do not take any input parameters?
I'm not convinced that what you are aiming for is in any way beneficial. You could do it using the following, though:
Void time_elapse(string function_call)
{
Number startVal = GetHighResTickCount()
if (ExecuteScriptString(function_call)) Throw("Script call failed")
number time = GetHighResTickCount() - startVal
time /= GetHighResTicksPerSecond()
Result("\nCall took "+Format(time,"%5.9f")+" sec.")
}
string call = "sleep(0.1)"
time_elapse(call)
As for better measurements:
To get a good idea of actual processing time, you do need statistics. A single execution measurement can widely deviate from the average due to other CPU tasks (within and without DigitalMicrograph) being active at the same time.
You may want to use GetHighResTicks() and GetHighResTicksPerSecond() for higher precision measurements.
A "convenient" way of adding a time is to make it into a class, where the constructor and the destructor perform the measurement. Just be aware that - as with your idea - a bit of overhead stems from the construction itself. However, the convenience of such a Sentry-Class stems from the fact that object-destruction happens automatically when leaving the code-block of the local variable. Example:
class CTimerSentry
{
string nameOp
number startVal, prec
CTimerSentry(object self){
startVal=GetHighResTickCount()
nameOP="Operation"
prec = 3
}
~CTimerSentry(object self){
number time = GetHighResTickCount() - startVal
time /= GetHighResTicksPerSecond()
Result("\n"+nameOP+" took "+Format(time,"%5."+prec+"f")+" sec.")
}
object init(object self, string name, number precision)
{
nameOP = name
prec = precision
return self
}
}
// Any code you want to time
{
object timer = Alloc(CTimerSentry).Init("Test sleep(0.1)",3)
sleep(0.1)
for (number i=0;i<10;i++)
{
object timer2 = Alloc(CTimerSentry).Init("Test loop sleep(0.1)",3)
sleep(0.1)
}
}