NAME
Kernel::Prof – Perl profiling made easy
TODO
nytprofmerge is sometimes failing:
2023-09-27_10-27-28 [2076163] ERROR running 'nytprofhtml': 6400
2023-09-27_10-27-28 [2076163] Sub Class::MOP::Method::Accessor::try {...} already defined!
Sub Devel::GlobalDestruction::in_global_destruction already defined!
...
Can't call method "inc" on an undefined value at /home/tim/perl5/perlbrew/perls/perl-5.34.1/lib/site_perl/5.34.1/x86_64-linux/Devel/NYTProf/FileInfo.pm line 438.
Apply ENV settings in a service file.
SYNOPSIS
Let's make profiling Perl code easy and simple as can be!
Below, CODE
is placeholder for any code, such as:
my $n = 0; for ( 1..10000 ){ $n+= $_ }
% is a command to be run on the command line (for triggers).
Profile a one-liner
OneShot
Generates the html results after the object goes out of scope.
% perl -MKernel::Prof -e 'my $p = Kernel::Prof->Run; CODE'
Triggered
Start recording after touch nytprof/work/start
Stop recording after touch nytprof/work/stop
% perl -MKernel::Prof -E 'while(1){ my $p = Kernel::Prof->Run( UseTriggers => 1); say "HERE"; sleep 2 }'
% perl -I. -MKernel::Prof -MMojo::MemoryMap -E 'my $m = Mojo::MemoryMap->new(); while(1){ my $p = Kernel::Prof->Run( UseTriggers => 1, MemoryMap => $m, CompressResults => 1, StopAfterNMinutes => 5 ); say "HERE"; sleep 5 }'
Profile a block of perl code:
use Kernel::Prof;
{
my $ProfilerObject = Kernel::Prof->Run();
CODE
}
Profile using file triggers
% touch nytprof/work/start
use Kernel::Prof;
my $ProfilerObject = Kernel::Prof->Run( UseTriggers => 1 );
CODE
% touch nytprof/work/stop
DESCRIPTION
This module is a tool that is designed to make profiling perl code as easy as can be.
Run Stages
When profiling, keep in mind:
- The stages described below.
- the scope of what should be captured/recorded.
Flow of Code Execution:
|== <-- Stage 1: Setup environment.
|
|==== <-- Stage 2: Beginning of code.
|
|======== <-- Stage 3: Start profiling.
|
| (Data is collected/recorded ONLY here!)
|
|======== <-- Stage 4: Stop profiling.
|
|==== <-- Stage 5: End of code.
|
|== <-- Stage 6: Restore environment
|
v
Stage 1: Setup Environment
These environmental variables should be setup. Failure to do so may result in missing links and/or data in the results!
export PERL5OPT=-d:NYTProf
export NYTPROF='trace=0:start=no:addpid=1:slowops=0'
# Trace - Set to a higher value like '1' for more details.
# Start - Put profiler into "standby" mode (ready, but not running).
# AddPid - Important when there are multiple processes.
# SlowOps - Disabled to avoid profiling say `sleep` or `print`.
If running as a service, the environmental variables should be stored in the service file instead:
systemctl status OTRS_WEBSERVICE_NAME
sudo vi /etc/systemdsystem/OTRS_WEBSERVICE_NAME.service
Add this line:
Environment="PERL5OPT=-d:NYTProf" "NYTPROF='trace=0:start=no:addpid=1:slowops=0'"
systemctl restart OTRS_WEBSERVICE_NAME
Stage 2: Beginning of Code
The C<profiler> at this point is in "standby" mode:
- Aware of source files (important for later).
- Not actually recording anything yet.
Stage 3: Start Profiling
To start profiling is like pressing a global record button. Anything after starting to profile will be stored in a file in a data format (which is mostly in machine-readable format).
Stage 4: Stop Profiling
Similary, to stop profiling is to press the global stop button.
NOTE: It is important to stop the profile correctly since the results would otherwise be useless. As stated in Devel::NYTProf:
"NYTProf writes some important data to the data file when finishing profiling."
Stage 5: End of Code
The C<profiler> at this point returns again to "standby" mode:
- Aware of source files (maybe important for later).
- Not actually recording anything anymore.
Stage 6: Restore Environment
Once profiling is done, the environment should be restored using:
unset PERL5OPT
unset NYTPROF
Run Modes
Run modes affect when the profiler
should start and stop.
OneShot
This run mode is simpler, but perhaps less useful as well.
The profiler
starts recording data after calling Run().
The profiler
stops recording data after the return object goes out of scope (via DESTROY
).
Therefore, make sure to assign the return object from Run() or the recorded data will be quite short 😉
{
my $ProfilerObject = Kernel::Prof->Run();
...
CODE
}
# $ProfilerObject goes out of scope here and stops the recording.
Triggered
This run mode is a bit more complicated, but also more useful.
It relies on the existence of files on the system to determine when to start and to stop the recording of data.
The profiler
starts recording data when Run() is invoked a "start" file has been detected.
The profiler
stops recording data when the return object goes out of scope and a "stop" file has been detected.
NOTE: The start/stop of recording is a GLOBAL setting and may remain in effect past ProfilerObject destruction.
while (...) {
my $ProfilerObject = Kernel::Prof->Run(); # Would start recording
# if a "start" file exists.
...
CODE
} # Would stop recording
# if a "stop" file exists.
METHODS
Run
Run the profiler
and return a special ProfilerObject.
my $ProfilerObject = Kernel::Prof->Run( %Options );
Will automatically close the recording data file when the ProfilerObject goes out of scope (by default).
Main Options
Values shown are the defaults.
Name => "my", # Name/title of the results.
UseTriggers => 0, # Trigger mode: enable flag.
StopAfterNMinutes => 0, # Trigger mode: automatically stop after N minutes.
MemoryMap => Mojo::MemoryMap->new(), # For IPC (multiple processes).
NYTProf
Build Options
UseFlameGraph => 0, # Generate the flame graph (slower).
KeepAllFiles => 0, # For debugging.
CompressResults => 0, # Generate a tar ball of the results and remove the data.
CreateIndividualResults => 1, # Make also html per worker.
CreateMergedResults => 0, # Make also html based on all workers (might fail).
File/Folder Name Options
RootName => "mytprof", # Root folder for all sub folders of results and triggers.
WorkName => "work", # Where raw data and file triggers are stored.
WorkDir => "$RootName/$WorkName", # Folder to store results.
StartFlag => "$WorkDir/start", # File to tell the profiler to begin recording.
StopFlag => "$WorkDir/stop", # File to tell the profiler to finish recording.
NotifyFlag => "$WorkDir/notify", # Notification if profling active.
Log => "$WorkDir/log", # Proflier log.