|
Sometimes it helps to use external tools while debugging and testing Perl. This section
tries to guide you through using some common testing and debugging tools with Perl. This is
meant as a guide to interfacing these tools with Perl, not as any kind of guide to the use of
the tools themselves.
Purify is a commercial tool that is helpful in identifying memory overruns, wild pointers,
memory leaks and other such badness. Perl must be compiled in a specific way for optimal
testing with Purify. Purify is available under Windows NT, Solaris, HP-UX, SGI, and Siemens
Unix.
The only currently known leaks happen when there are compile-time errors within eval or
require. (Fixing these is non-trivial, unfortunately, but they must be fixed eventually.)
On Unix, Purify creates a new Perl binary. To get the most benefit out of Purify, you
should create the perl to Purify using:
sh Configure -Accflags=-DPURIFY -Doptimize='-g' \
-Uusemymalloc -Dusemultiplicity
|
|
where these arguments mean:
- -Accflags=-DPURIFY
- Disables Perl's arena memory allocation functions, as well as forcing use of memory
allocation functions derived from the system malloc.
- -Doptimize='-g'
- Adds debugging information so that you see the exact source statements where the problem
occurs. Without this flag, all you will see is the source filename of where the error
occurred.
- -Uusemymalloc
- Disable Perl's malloc so that Purify can more closely monitor allocations and leaks.
Using Perl's malloc will make Purify report most leaks in the "potential" leaks
category.
- -Dusemultiplicity
- Enabling the multiplicity option allows perl to clean up thoroughly when the interpreter
shuts down, which reduces the number of bogus leak reports from Purify.
Once you've compiled a perl suitable for Purify'ing, then you can just:
which creates a binary named 'pureperl' that has been Purify'ed. This binary is used in
place of the standard 'perl' binary when you want to debug Perl memory problems.
To minimize the number of memory leak false alarms (see /PERL_DESTRUCT_LEVEL),
set environment variable PERL_DESTRUCT_LEVEL to 2.
setenv PERL_DESTRUCT_LEVEL 2
|
|
In Bourne-type shells:
PERL_DESTRUCT_LEVEL=2
export PERL_DESTRUCT_LEVEL
|
|
As an example, to show any memory leaks produced during the standard Perl testset you would
create and run the Purify'ed perl as:
make pureperl
cd t
../pureperl -I../lib harness
|
|
which would run Perl on test.pl and report any memory problems.
Purify outputs messages in "Viewer" windows by default. If you don't have a
windowing environment or if you simply want the Purify output to unobtrusively go to a log
file instead of to the interactive window, use these following options to output to the log
file "perl.log":
setenv PURIFYOPTIONS "-chain-length=25 -windows=no \
-log-file=perl.log -append-logfile=yes"
|
|
If you plan to use the "Viewer" windows, then you only need this option:
setenv PURIFYOPTIONS "-chain-length=25"
|
|
In Bourne-type shells:
PURIFYOPTIONS="..."
export PURIFYOPTIONS
|
|
or if you have the "env" utility:
env PURIFYOPTIONS="..." ../pureperl ...
|
|
Purify on Windows NT instruments the Perl binary 'perl.exe' on the fly. There are several
options in the makefile you should change to get the most use out of Purify:
- DEFINES
-
You should add -DPURIFY to the DEFINES line so the DEFINES line looks something like:
DEFINES = -DWIN32 -D_CONSOLE -DNO_STRICT $(CRYPT_FLAG) -DPURIFY=1
|
|
to disable Perl's arena memory allocation functions, as well as to force use of memory
allocation functions derived from the system malloc.
- USE_MULTI = define
- Enabling the multiplicity option allows perl to clean up thoroughly when the interpreter
shuts down, which reduces the number of bogus leak reports from Purify.
- #PERL_MALLOC = define
- Disable Perl's malloc so that Purify can more closely monitor allocations and leaks.
Using Perl's malloc will make Purify report most leaks in the "potential" leaks
category.
- CFG = Debug
- Adds debugging information so that you see the exact source statements where the problem
occurs. Without this flag, all you will see is the source filename of where the error
occurred.
As an example, to show any memory leaks produced during the standard Perl testset you would
create and run Purify as:
cd win32
make
cd ../t
purify ../perl -I../lib harness
|
|
which would instrument Perl in memory, run Perl on test.pl, then finally report any memory
problems.
NOTE: as of Perl 5.8.0, the ext/Encode/t/Unicode.t takes extraordinarily long
(hours?) to complete under Purify. It has been theorized that it would eventually finish, but
nobody has so far been patient enough :-) (This same extreme slowdown has been seen also with
the Third Degree tool, so the said test must be doing something that is quite unfriendly for
memory debuggers.) It is suggested that you simply kill away that testing process.
Third Degree is a tool for memory leak detection and memory access checks. It is one of the
many tools in the ATOM toolkit. The toolkit is only available on Tru64 (formerly known as
Digital UNIX formerly known as DEC OSF/1).
When building Perl, you must first run Configure with -Doptimize=-g and -Uusemymalloc
flags, after that you can use the make targets "perl.third" and "test.third".
(What is required is that Perl must be compiled using the -g flag, you may need
to re-Configure.)
The short story is that with "atom" you can instrument the Perl executable to
create a new executable called perl.third. When the instrumented executable is run, it
creates a log of dubious memory traffic in file called perl.3log. See the manual pages
of atom and third for more information. The most extensive Third Degree documentation is
available in the Compaq "Tru64 UNIX Programmer's Guide", chapter "Debugging
Programs with Third Degree".
The "test.third" leaves a lot of files named foo_bar.3log in the t/
subdirectory. There is a problem with these files: Third Degree is so effective that it finds
problems also in the system libraries. Therefore you should used the Porting/thirdclean script
to cleanup the *.3log files.
There are also leaks that for given certain definition of a leak, aren't. See /PERL_DESTRUCT_LEVEL for more information.
If you want to run any of the tests yourself manually using the pureperl or perl.third
executables, please note that by default perl does not explicitly cleanup all the
memory it has allocated (such as global memory arenas) but instead lets the exit() of the
whole program "take care" of such allocations, also known as "global
destruction of objects".
There is a way to tell perl to do complete cleanup: set the environment variable
PERL_DESTRUCT_LEVEL to a non-zero value. The t/TEST wrapper does set this to 2, and this is
what you need to do too, if you don't want to see the "global leaks": For example,
for "third-degreed" Perl:
env PERL_DESTRUCT_LEVEL=2 ./perl.third -Ilib t/foo/bar.t
|
|
(Note: the mod_perl apache module uses also this environment variable for its own purposes
and extended its semantics. Refer to the mod_perl documentation for more information.)
Depending on your platform there are various of profiling Perl.
There are two commonly used techniques of profiling executables: statistical
time-sampling and basic-block counting.
The first method takes periodically samples of the CPU program counter, and since the
program counter can be correlated with the code generated for functions, we get a statistical
view of in which functions the program is spending its time. The caveats are that very
small/fast functions have lower probability of showing up in the profile, and that
periodically interrupting the program (this is usually done rather frequently, in the scale of
milliseconds) imposes an additional overhead that may skew the results. The first problem can
be alleviated by running the code for longer (in general this is a good idea for profiling),
the second problem is usually kept in guard by the profiling tools themselves.
The second method divides up the generated code into basic blocks. Basic blocks are
sections of code that are entered only in the beginning and exited only at the end. For
example, a conditional jump starts a basic block. Basic block profiling usually works by instrumenting
the code by adding enter basic block #nnnn book-keeping code to the generated code.
During the execution of the code the basic block counters are then updated appropriately. The
caveat is that the added extra code can skew the results: again, the profiling tools usually
try to factor their own effects out of the results.
gprof is a profiling tool available in many UNIX platforms, it uses statistical
time-sampling.
You can build a profiled version of perl called "perl.gprof" by invoking the make
target "perl.gprof" (What is required is that Perl must be compiled using the -pg
flag, you may need to re-Configure). Running the profiled version of Perl will create an
output file called gmon.out is created which contains the profiling data collected
during the execution.
The gprof tool can then display the collected data in various ways. Usually gprof
understands the following options:
- -a
- Suppress statically defined functions from the profile.
- -b
- Suppress the verbose descriptions in the profile.
- -e routine
- Exclude the given routine and its descendants from the profile.
- -f routine
- Display only the given routine and its descendants in the profile.
- -s
- Generate a summary file called gmon.sum which then may be given to subsequent
gprof runs to accumulate data over several runs.
- -z
- Display routines that have zero usage.
For more detailed explanation of the available commands and output formats, see your own
local documentation of gprof.
Starting from GCC 3.0 basic block profiling is officially available for the GNU CC.
You can build a profiled version of perl called perl.gcov by invoking the make
target "perl.gcov" (what is required that Perl must be compiled using gcc with the
flags -fprofile-arcs -ftest-coverage, you may need to re-Configure).
Running the profiled version of Perl will cause profile output to be generated. For each
source file an accompanying ".da" file will be created.
To display the results you use the "gcov" utility (which should be installed if
you have gcc 3.0 or newer installed). gcov is run on source code files, like this
which will cause sv.c.gcov to be created. The .gcov files contain the source
code annotated with relative frequencies of execution indicated by "#" markers.
Useful options of gcov include -b which will summarise the basic block,
branch, and function call coverage, and -c which instead of relative frequencies
will use the actual counts. For more information on the use of gcov and basic block
profiling with gcc, see the latest GNU CC manual, as of GCC 3.0 see
http://gcc.gnu.org/onlinedocs/gcc-3.0/gcc.html
|
|
and its section titled "8. gcov: a Test Coverage Program"
http://gcc.gnu.org/onlinedocs/gcc-3.0/gcc_8.html#SEC132
|
|
Pixie is a profiling tool available on IRIX and Tru64 (aka Digital UNIX aka DEC OSF/1)
platforms. Pixie does its profiling using basic-block counting.
You can build a profiled version of perl called perl.pixie by invoking the make
target "perl.pixie" (what is required is that Perl must be compiled using the -g
flag, you may need to re-Configure).
In Tru64 a file called perl.Addrs will also be silently created, this file contains
the addresses of the basic blocks. Running the profiled version of Perl will create a new file
called "perl.Counts" which contains the counts for the basic block for that
particular program execution.
To display the results you use the prof utility. The exact incantation depends on
your operating system, "prof perl.Counts" in IRIX, and "prof -pixie -all -L.
perl" in Tru64.
In IRIX the following prof options are available:
- -h
- Reports the most heavily used lines in descending order of use. Useful for finding the
hotspot lines.
- -l
- Groups lines by procedure, with procedures sorted in descending order of use. Within a
procedure, lines are listed in source order. Useful for finding the hotspots of
procedures.
In Tru64 the following options are available:
- -p[rocedures]
- Procedures sorted in descending order by the number of cycles executed in each
procedure. Useful for finding the hotspot procedures. (This is the default option.)
- -h[eavy]
- Lines sorted in descending order by the number of cycles executed in each line. Useful
for finding the hotspot lines.
- -i[nvocations]
- The called procedures are sorted in descending order by number of calls made to the
procedures. Useful for finding the most used procedures.
- -l[ines]
- Grouped by procedure, sorted by cycles executed per procedure. Useful for finding the
hotspots of procedures.
- -testcoverage
- The compiler emitted code for these lines, but the code was unexecuted.
- -z[ero]
- Unexecuted procedures.
For further information, see your system's manual pages for pixie and prof.
-
Those debugging perl with the DDD frontend over gdb may find the following useful:
You can extend the data conversion shortcuts menu, so for example you can display an
SV's IV value with one click, without doing any typing. To do that simply edit ~/.ddd/init
file and add after:
! Display shortcuts.
Ddd*gdbDisplayShortcuts: \
/t () // Convert to Bin\n\
/d () // Convert to Dec\n\
/x () // Convert to Hex\n\
/o () // Convert to Oct(\n\
|
|
the following two lines:
((XPV*) (())->sv_any )->xpv_pv // 2pvx\n\
((XPVIV*) (())->sv_any )->xiv_iv // 2ivx
|
|
so now you can do ivx and pvx lookups or you can plug there the sv_peek
"conversion":
Perl_sv_peek(my_perl, (SV*)()) // sv_peek
|
|
(The my_perl is for threaded builds.) Just remember that every line, but the last one,
should end with \n\
Alternatively edit the init file interactively via: 3rd mouse button -> New Display
-> Edit Menu
Note: you can define up to 20 conversion shortcuts in the gdb section.
- If you see in a debugger a memory area mysteriously full of 0xabababab, you may be
seeing the effect of the Poison() macro, see perlclib.
We've had a brief look around the Perl source, an overview of the stages perl goes
through when it's running your code, and how to use a debugger to poke at the Perl guts. We
took a very simple problem and demonstrated how to solve it fully - with documentation,
regression tests, and finally a patch for submission to p5p. Finally, we talked about how to
use external tools to debug and test Perl.
I'd now suggest you read over those references again, and then, as soon as possible, get
your hands dirty. The best way to learn is by doing, so:
- Subscribe to perl5-porters, follow the patches and try and understand them; don't be
afraid to ask if there's a portion you're not clear on - who knows, you may unearth a bug
in the patch...
- Keep up to date with the bleeding edge Perl distributions and get familiar with the
changes. Try and get an idea of what areas people are working on and the changes they're
making.
- Do read the README associated with your operating system, e.g. README.aix on the IBM AIX
OS. Don't hesitate to supply patches to that README if you find anything missing or
changed over a new OS release.
- Find an area of Perl that seems interesting to you, and see if you can work out how it
works. Scan through the source, and step over it in the debugger. Play, poke, investigate,
fiddle! You'll probably get to understand not just your chosen area but a much wider range
of perl's activity as well, and probably sooner than you'd think.
- The Road
goes ever on and on, down from the door where it began.
-
If you can do these things, you've started on the long road to Perl porting. Thanks for
wanting to help make Perl better - and happy hacking!
|