Simple Profiler

Share your advanced PureBasic knowledge/code with the community.
Dreglor
Enthusiast
Enthusiast
Posts: 759
Joined: Sat Aug 02, 2003 11:22 pm
Location: OR, USA

Simple Profiler

Post by Dreglor »

Here is a simple cycle profiler I decided to code after a project of mine had some odd execute times on procedures.

All that is required is that you use "BeginProfiler" at the start of the section of code you want to measure and then at the end of section of code put "EndProfiler" and use "GetProfilerCycleCount()" to retrieve the Cycle count between the last section of code you measured.

You must take in account that absolute performance is effected by a variety of factors like background processes, Core architecture,
number of cores, and OS power handling features like speed step.
This is very good for relative performance but not for absolute cycle counts and specific timings
also CPUID can decrease performance due to its serialization properties as out of order execution is designed to keep other things processing while something heavy is being executed.

The overhead might need a tweak if it returns a negative value in a empty measurement section it took me a few times of running to finally get the overhead there it does tend to fluctuate a lot on my machine anywhere between 290 and 650. One other note, it seams that it does seam to have an accuracy of 10 cycles which is crazy for resolution in time and satisfactory for code checks I just find it kind of odd.

And now for your enjoyment the code:

Code: Select all

#ProfilerOverhead = 290 ;On my system (Intel Quad 2.6 running x64) the overhead is with no debugger and nothing between the profiler statments.

Macro BeginProfiler
  __ProfilerCyclesLow.l = 0 ;Clear any Previous times plus make sure its has been defined
  __ProfilerCyclesHigh.l = 0
  __ProfilerCycles.q
  !CPUID ;Force all commands to be completed before continuing (Serialize out of order execution)
  !RDTSC ;Get the current cycle count
  !MOV [v___ProfilerCyclesLow], EAX ;Move the current low part of the cycle count into the varible
  !MOV [v___ProfilerCyclesHigh], EDX ;Move the current high part of the cycle count into the varible
  __ProfilerCycles = ((__ProfilerCyclesHigh << 32) | __ProfilerCyclesLow) ;Save the current cycle count
EndMacro

Macro EndProfiler
  CompilerIf Defined(__ProfilerCycles, #PB_Variable) = #False ;this prevents a compiler error but doesn't runtime ends before begins (it will give a negitive number)
    CompilerError "'BeginProfiler' has not been used yet!"
  CompilerEndIf
  !CPUID ;Force all commands to be completed before continuing (Serialize out of order execution)
  !RDTSC ;Get the current cycle count
  !SUB EAX, [v___ProfilerCyclesLow] ;Subtract the low part
  !SUB EDX, [v___ProfilerCyclesHigh]  ;Subtract the high part
  !MOV [v___ProfilerCyclesLow], EAX ;Move the current low part of the cycle count into the varible
  !MOV [v___ProfilerCyclesHigh], EDX ;Move the current high part of the cycle count into the varible
  __ProfilerCycles = ((__ProfilerCyclesHigh << 32) | __ProfilerCyclesLow) ;Save the current cycle count
EndMacro

Macro GetProfilerCycleCount()
  (__ProfilerCycles - #ProfilerOverhead) ;just for athestics
EndMacro
I have tested this for x86 and x64 versions.
Improvements are welcome.
~Dreglor
LCD
Enthusiast
Enthusiast
Posts: 206
Joined: Sun Jun 01, 2003 10:55 pm
Location: Austria, Vienna
Contact:

Post by LCD »

Thanks!!! This is extremly helpful for optimisations of programs.
My PC
Ryzen 9 5950, 64 GB RAM, nVidia RTX A4000, Win 10
Ryzen 7 1700, 32 GB RAM, nVidia RTX A2000, Win 10
Post Reply