Profiling with fb's profiler
Documentation
Profiling can be used to analyze the performance of an application.Since fbc 1.20.0, FreeBASIC can use fb's profiler for analyzing the execution of an application. The profiler information is collected while the program is running.
This profiling feature may give an easy to use tool to help novice and experienced users analyze their programs.
Some of the capabilities of this profiler implemented through fb:
- easy to use,
- no extra tools needed,
- can profile (analyze) calls to external libraries.
This profiling feature may give an easy to use tool to help novice and experienced users analyze their programs.- no extra tools needed,
- can profile (analyze) calls to external libraries.
The three basic steps to profiling a program are:
- Prepare the program for profiling by passing the the appropriate -profgen ... option to the FreeBASIC compiler or compile the source with appropriate '-profgen ...' #Cmdline option.
- Run the program to build the profiling report stored by default in
- Analyze directly the profiling report (text file).
The fb's profiler offers two types of profiling:- Run the program to build the profiling report stored by default in
<filename[.exe]>.prf (where <filename[.exe]> is the name of the executable).- Analyze directly the profiling report (text file).
1. Function call profiling
2. Cycle count profiling (currently a work in progress on
2. Cycle count profiling (currently a work in progress on
-gen gas64 only)1. Function Call Profiling (with fb's profiler)
The performance of an application might be measured by how many times functions are called, how much time is spent executing those functions, and which functions are calling other functions.
This can help to identify functions that might be taking too long to execute or executed too many times and that might be worth reviewing for optimization.
This feature is a reimplentation of Angelo Mottola's (lillo's) profiler from 2008, rewritten to fix some issues, and then some new features added on. This latest side quest started due to a desire to run some kind of profiling on the fbc compiler itself, and having no luck at all with gprof on windows. Years ago lillo's function call profiler was removed in favor of gmon/gprof.
This tool is not suitable for high resolution timing profiling. However, it helps identify potential problem areas in a program, or gives a better understanding of procedures called as starting point for investigations.
FreeBASIC supports function profiling; not basic-block or line-by-line profiling.
1.1 Preparing a Program for Profiling (with function call fb's profiler)
Only code that is compiled with the -profgen fb command line option can be so profiled.
Pass the -profgen fb option to the FreeBASIC compiler to prepare the program to be profiled or compile the source with '-profgen fb' #Cmdline option:
1.2 Profiling (with function call fb's profiler) the ProgramPass the -profgen fb option to the FreeBASIC compiler to prepare the program to be profiled or compile the source with '-profgen fb' #Cmdline option:
fbc program.bas -profgen fb ' or #cmdline "-profgen fb"This will tell the compiler to insert special startup code at the beginning of the application as well as at the beginning of each function.
The information needed to analyze execution of the program is gathered while the program is running.
Run the program to begin collecting the function call information.
The profiling report is automatically stored in a file named by default
1.3 Analyzing the Profiling Report (from function call fb's profiler)Run the program to begin collecting the function call information.
The profiling report is automatically stored in a file named by default
<filename[.exe]>.prf in the same directory as the program.After compiling and running the program, the user can open the default named profiling report
There are two sections:
In case of multi-threading, each thread has a separate instance of the profiler storing its data in thread-local storage.
The final profiling report groups together one after the other the elementary profiling reports of each thread (including firstly that of the main thread). There is no inter-thread grouping.
<filename[.exe]>.prf (text file).There are two sections:
- per function results - profile of individual procedures and the procedures called
- global results - profile of all procedures with respect to the whole program run time
Times are based on fb's built-in TIMER function.- global results - profile of all procedures with respect to the whole program run time
Function: the parent function / child function profiled. Parents are on the left, children are indentedCount: number of times the procedure was calledTime: number of seconds executing the procedureTotal%: the percentage of execution time versus the whole run timeProc%: the percentage of execution time versus the procedure run timeIn case of multi-threading, each thread has a separate instance of the profiler storing its data in thread-local storage.
The final profiling report groups together one after the other the elementary profiling reports of each thread (including firstly that of the main thread). There is no inter-thread grouping.
- Simple example:
#cmdline "-profgen fb"
Sub Pause_100
Sleep 100, 1
End Sub
Sub Pause_200
Sleep 200, 1
End Sub
Sub Pause_400
Sleep 400, 1
End Sub
For i As Integer = 1 To 3
Pause_100
Next i
Pause_200
Pause_400
Example of profiling report:
' .....
'
'
' Per function results:
'
' Function: Count: Time: Total%: Proc%:
'
' (main) 1 0.92307 100.00%
'
' PAUSE_400 1 0.40091 43.43% 43.43%
' PAUSE_100 3 0.32153 34.83% 34.83%
' PAUSE_200 1 0.20060 21.73% 21.73%
' FB___MAIN 1 0.00000 0.00% 0.00%
'
' PAUSE_100 3 0.32153 34.83%
'
' SLEEP 3 0.32152 34.83% 100.00%
'
' PAUSE_200 1 0.20060 21.73%
'
' SLEEP 1 0.20059 21.73% 100.00%
'
' PAUSE_400 1 0.40091 43.43%
'
' SLEEP 1 0.40086 43.43% 99.99%
'
'
'
' Global results:
'
' (main) 1 0.92307 100.00%
' FB___MAIN 1 0.00000 0.00%
' PAUSE_100 3 0.32153 34.83%
' PAUSE_200 1 0.20060 21.73%
' PAUSE_400 1 0.40091 43.43%
' SLEEP 5 0.92297 99.99%
The following features allow the user to control the information collected by the profiler as well as modify the profiling report, compared to the default operating.
1.4.1 Advanced procedures in the
1.4.1 Advanced procedures in the
./inc/fbc-int/profile.bi include fileThe
These procedures expose fb's profiler as an API that can then be called directly and used to generate a profiling report based on whatever structure of call recording is made by the user:
./inc/fbc-int/profile.bi include file allows user to access some advanced procedures (declared inside Namespace: FBC) for working with the fb's profiler.These procedures expose fb's profiler as an API that can then be called directly and used to generate a profiling report based on whatever structure of call recording is made by the user:
- To set the output report file name at run-time:
- To set/get options for the profiler:
both associated with the
- To ignore a procedure when profiling:
- To call fb's profiler directly to perform custom profiling and a report:
function ProfileSetFileName ( byval filename as const zstring ptr ) as longfunction ProfileSetOptions ( byval options as PROFILE_OPTIONS ) as PROFILE_OPTIONSfunction ProfileGetOptions ( ) as PROFILE_OPTIONSboth associated with the
PROFILE_OPTIONS Enum structure (see ./inc/fbc-int/profile.bi include file)sub ProfileIgnore ( byval procedurename as zstring ptr )Examples of procedures:
sub ProfileInit () '' Initialize the profilerfunction ProfileEnd ( byval errorcode as long ) as long '' Generate the profiling report and terminate the profilerfunction ProfileBeginCall ( byval procedurename as const zstring ptr ) as any ptr '' Begin a call and return a caller_id pointersub ProfileEndCall ( byval procctx as any ptr ) '' End a call- Example for setting the profiling report file name at run-time:
#cmdline "-profgen fb"
#include Once "fbc-int/profile.bi"
Using FBC
'' automatically change the profile report name
Dim t As String = Time
Dim n As String = Left(t, 2) & Mid(t, 4, 2) & Right(t, 2)
ProfileSetFileName( "prof-" & n & ".txt" )
- Example for telling the profiler to generate a call tree instead of timings and counts:
#cmdline "-profgen fb"
#include Once "fbc-int/profile.bi"
Using FBC
ProfileSetOptions( PROFILE_OPTION_REPORT_CALLTREE )
Sub A
Print "A"
End Sub
Sub B
Print "B"
End Sub
Sub C
Print "C"
End Sub
Sub D
Print "D"
A
A
B
B
C
C
End Sub
D
Example of profiling report:
' ..... ' ' ' Call Tree: ' ' \- (main) ' |- D ' | |- A ' | | |- FB_PRINTSTRING ' | | \- FB_STRALLOCTEMPDESCZEX ' | |- B ' | | |- FB_PRINTSTRING ' | | \- FB_STRALLOCTEMPDESCZEX ' | |- C ' | | |- FB_PRINTSTRING ' | | \- FB_STRALLOCTEMPDESCZEX ' | |- FB_PRINTSTRING ' | \- FB_STRALLOCTEMPDESCZEX ' |- FB___MAIN ' \- PROFILESETOPTIONS
- Example for calling fb's profiler directly to perform custom profiling and a report:
#include Once "fbc-int/profile.bi"
Using FBC
#if __FB_PROFILE__ = PROFILE_OPTION_REPORT_CALLS
#error Do Not compile With -profgen fb
#endif
ProfileInit()
Var ctx = ProfileBeginCall( @"Begin" )
Scope
Var ctx = ProfileBeginCall( @"Step 1" )
Sleep 100, 1
ProfileEndCall( ctx )
End Scope
Scope
Var ctx = ProfileBeginCall( @"Step 2" )
Sleep 200, 1
ProfileEndCall( ctx )
End Scope
ProfileEndCall( ctx )
ProfileEnd(0)
Example of profiling report:
' .....
'
'
' Per function results:
'
' Function: Count: Time: Total%: Proc%:
'
' (main) 1 0.30183 100.00%
'
' Begin 1 0.30183 100.00% 100.00%
'
' Begin 1 0.30183 100.00%
'
' Step 2 1 0.20057 66.45% 66.45%
' Step 1 1 0.10125 33.54% 33.54%
'
'
'
' Global results:
'
' (main) 1 0.30183 100.00%
' Begin 1 0.30183 100.00%
' Step 1 1 0.10125 33.54%
' Step 2 1 0.20057 66.45%
The user can also control a conditional generation of profiling code:
This allows optionally including or excluding sections of source code to be profiled.
User can optionally disable profiling code generation with
Profiling code generation can be reactivated with
The
#Pragma Profile controls the generation of profiling code.This allows optionally including or excluding sections of source code to be profiled.
User can optionally disable profiling code generation with
#pragma profile = false or #pragma push( profile , false )Profiling code generation can be reactivated with
#pragma profile = true or #pragma pop( profile ) respectivelyThe
__FB_OPTION_PROFILE__ intrinsic define allows to indicate that the profiling code is generated or not:__FB_OPTION_PROFILE__ is set to non-zero when profiling code is generated__FB_OPTION_PROFILE__ is set to zero when profiling code is not generated- Purely academic example:
#cmdline "-profgen fb"
Print "__FB_OPTION_PROFILE__ = " & __FB_OPTION_PROFILE__
#pragma push( profile , False )
Print "__FB_OPTION_PROFILE__ = " & __FB_OPTION_PROFILE__
Sleep 100, 1
#pragma pop( profile )
Print "__FB_OPTION_PROFILE__ = " & __FB_OPTION_PROFILE__
Example of profiling report:
' .....
'
'
' Per function results:
'
' Function: Count: Time: Total%: Proc%:
'
' (main) 1 0.11714 100.00%
'
' FB_PRINTSTRING 2 0.00517 4.42% 4.42%
' FB_STRALLOCTEMPDESCZEX 2 0.00001 0.01% 0.01%
' FB___MAIN 1 0.00000 0.00% 0.00%
'
'
'
' Global results:
'
' (main) 1 0.11714 100.00%
' FB_PRINTSTRING 2 0.00517 4.42%
' FB_STRALLOCTEMPDESCZEX 2 0.00001 0.01%
' FB___MAIN 1 0.00000 0.00%
The code profiler only takes into account 2 PRINTs (instead of 3) and not the SLEEP.
2. Cycle Count Profiling (with fb's profiler)
This is currently a work in progress on
-gen gas64 only.Cycle count fb's profiler enables cpu cycle count profiling on some targets.
It uses completely different methods than the function call fb's profiler. It stores data in specially named data sections, so will only work with linkers supporting arbitrarily named sections.
After running an executable compiled with this command, it can generate a basic report of cycle counts.
For each called user procedure body, there are two different counts:
- The profiler sums the CPU cycle counts for all internal code blocks that separate possible calls from any other user procedure or built-in procedure (all other called procedures are therefore excluded from this first count).
- The profiler also counts the total number of CPU cycles when executing the entire user procedure body.
2.1 Preparing a Program for Profiling (with cycle count fb's profiler)- The profiler also counts the total number of CPU cycles when executing the entire user procedure body.
Only code that is compiled with the -profgen cycles command line option can be so profiled.
Pass the -profgen cycles option to the FreeBASIC compiler to prepare the program to be profiled or compile the source with '-profgen cycles' #Cmdline option:
2.2 Profiling (with cycle count fb's profiler) the ProgramPass the -profgen cycles option to the FreeBASIC compiler to prepare the program to be profiled or compile the source with '-profgen cycles' #Cmdline option:
fbc program.bas -profgen cycles ' or #cmdline "-profgen cycles"
The information needed to analyze execution of the program is gathered while the program is running.
Run the program to begin collecting the function call information.
The profiling report is automatically stored in a file named by default
2.3 Analyzing the Profiling Report (from cycle count fb's profiler)Run the program to begin collecting the function call information.
The profiling report is automatically stored in a file named by default
<filename[.exe]>.prf in the same directory as the program.After compiling and running the program, the user can open the default named profiling report
Profile of individual procedures per module:
<filename[.exe]>.prf (text file).Profile of individual procedures per module:
total: the number of cycles between the end of the procedure and its beginninginside: the number of cycles really "spent" inside the procedure (procedure calls inside the procedure body are not taken into account)call count: number of times the procedure was called- Simple example:
#cmdline "-gen gas64"
#cmdline "-profgen cycles"
Sub A()
Dim As Integer I
For J As Integer = 1 To 1000
I = I + 1
Next J
End Sub
Sub B()
A()
End Sub
Sub C()
B()
Print "End"
End Sub
C()
Example of profiling report:
' .....
'
'
' module function total inside call count
'
' *.bas
'
' A
' 4242 4242 1
' B
' 4473 42 1
' C
' 858301 169 1
' main
' 0 63 1