How to run a python script under the debugger¶
First be sure that you have built either Debug or RelWithDebInfo. In an icetray environment:
% ./env-shell.sh
************************************************************************
* *
* W E L C O M E to I C E T R A Y *
* *
* Version offline-software.trunk r48553 *
* *
* You are welcome to visit our Web site *
* http://icecube.umd.edu *
* *
************************************************************************
Icetray environment has:
I3_SRC = /home/troy/Icecube/meta-projects/offline-software/trunk/src
I3_BUILD = /home/troy/Icecube/meta-projects/offline-software/trunk/build
run gdb using --args
, passing python
and your script:
% gdb --args python ./examples/resources/scripts/pass1.py
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
I have added some segfaulting code to an example module. Run the script using r:
(gdb) r
Starting program: /usr/bin/python ./examples/resources/scripts/pass1.py
[Thread debugging using libthread_db enabled]
[New Thread 0xb7ddcad0 (LWP 18082)]
Loading libicetray........................................ok
Loading libdataclasses....................................ok
Loading libphys-services..................................ok
Loading libDOMcalibrator..................................ok
Loading libdataio.........................................ok
Loading libexamples.......................................ok
i3reader: Filename = /opt/i3/ports/test-data/2006data/Run00089508.i3.gz
i3reader: SkipKeys = ['I3PfFilterMask']
writer: filename = pass1.i3
/home/troy/Icecube/meta-projects/offline-software/trunk/src/dataio/private/dataio/I3Reader.cxx:177: INFO : Opened file /opt/i3/ports/test-data/2006data/Run00089508.i3.gz
/home/troy/Icecube/meta-projects/offline-software/trunk/src/dataio/private/dataio/I3WriterBase.cxx:113: INFO : Not compressing.
Geometry.....[1]
[ I3Frame (Geometry):
'I3Geometry' [Geometry] ==> I3Geometry(459538)
]
---------------------------------
Calibration.....[2]
[ I3Frame (Calibration):
'I3Calibration' [Calibration] ==> I3Calibration(11267753)
'I3Geometry' [Geometry] ==> I3Geometry(459538)
]
---------------------------------
DetectorStatus.....[3]
[ I3Frame (DetectorStatus):
'I3Calibration' [Calibration] ==> I3Calibration(11267753)
'I3DetectorStatus' [DetectorStatus] ==> I3DetectorStatus(96286)
'I3Geometry' [Geometry] ==> I3Geometry(459538)
]
---------------------------------
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb7ddcad0 (LWP 18082)]
0xb2dbca1c in DumbFeatureExtractor::Physics (this=0x83a5c58, frame=@0xbfdc6c00)
at /home/troy/Icecube/meta-projects/offline-software/trunk/src/examples/private/modules/DumbFeatureExtractor.cxx:55
55 printf("%d", *p);
Current language: auto; currently c++
(gdb)
One of the modules has segfaulted and gdb has stopped execution and given you a prompt. Now it is useful to see a stack trace:
(gdb) where
#0 0xb2dbca1c in DumbFeatureExtractor::Physics (this=0x83a5c58, frame=@0xbfdc6c00)
at /home/troy/Icecube/meta-projects/offline-software/trunk/src/examples/private/modules/DumbFeatureExtractor.cxx:55
#1 0xb77afc73 in I3Module::Process (this=0x83a5c58)
at /home/troy/Icecube/meta-projects/offline-software/trunk/src/icetray/private/icetray/I3Module.cxx:179
#2 0xb77b0443 in I3Module::Do (this=0x83a5c58, f=&virtual I3Module::Process())
at /home/troy/Icecube/meta-projects/offline-software/trunk/src/icetray/private/icetray/I3Module.cxx:113
#3 0xb77b050b in I3Module::Do (this=0x83a4ed0, f=&virtual I3Module::Process())
at /home/troy/Icecube/meta-projects/offline-software/trunk/src/icetray/private/icetray/I3Module.cxx:131
#4 0xb77b050b in I3Module::Do (this=0x83a44f0, f=&virtual I3Module::Process())
at /home/troy/Icecube/meta-projects/offline-software/trunk/src/icetray/private/icetray/I3Module.cxx:131
#5 0xb779bbe6 in I3Tray::Execute (this=0x81ccd08)
at /home/troy/Icecube/meta-projects/offline-software/trunk/src/icetray/private/icetray/I3Tray.cxx:381
#6 0xb7c12230 in boost::python::detail::invoke<int, void (I3Tray::*)(), boost::python::arg_from_python<I3Tray&> > (f=@0x8352c14,
tc=@0xbfdc6df4) at /opt/i3/ports/include/boost-1.36.0/boost/python/detail/invoke.hpp:94
#7 0xb7c14aee in boost::python::detail::caller_arity<1u>::impl<void (I3Tray::*)(), boost::python::default_call_policies, boost::mpl::vector2<void, I3Tray&> >::operator() (this=0x8352c14, args_=0x832ae0c)
at /opt/i3/ports/include/boost-1.36.0/boost/python/detail/caller.hpp:223
#8 0xb7c14b4a in boost::python::objects::caller_py_function_impl<boost::python::detail::caller<void (I3Tray::*)(), boost::python::default_call_policies, boost::mpl::vector2<void, I3Tray&> > >::operator() (this=0x8352c10, args=0x832ae0c, kw=0x0)
at /opt/i3/ports/include/boost-1.36.0/boost/python/object/py_function.hpp:38
#9 0xb73408e1 in boost::python::objects::py_function::operator() (this=0x8359040, args=0x832ae0c, kw=0x0)
at /opt/i3/ports/var/db/dports/build/file._opt_i3_ports_var_db_dports_sources_rsync.code.icecube.wisc.edu_icecube-tools-ports_devel_boost_1.36.0/work/boost_1.36.0/libs/python/include/boost/python/object/py_function.hpp:143
#10 0xb733f2d2 in boost::python::objects::function::call (this=0x83591e8, args=0x832ae0c, keywords=0x0)
at /opt/i3/ports/var/db/dports/build/file._opt_i3_ports_var_db_dports_sources_rsync.code.icecube.wisc.edu_icecube-tools-ports_devel_boost_1.36.0/work/boost_1.36.0/libs/python/src/object/function.cpp:226
#11 0xb733f3d1 in operator() (this=0xbfdc7000)
at /opt/i3/ports/var/db/dports/build/file._opt_i3_ports_var_db_dports_sources_rsync.code.icecube.wisc.edu_icecube-tools-ports_devel_boost_1.36.0/work/boost_1.36.0/libs/python/src/object/function.cpp:581
#12 0xb733f3f0 in invoke (function_obj_ptr=@0xbfdc6fe0)
at /opt/i3/ports/var/db/dports/build/file._opt_i3_ports_var_db_dports_sources_rsync.code.icecube.wisc.edu_icecube-tools-ports_devel_boost_1.36.0/work/boost_1.36.0/boost/function/function_template.hpp:179
#13 0xb7355cb7 in boost::function0<void>::operator() (this=0xbfdc6fdc)
at /opt/i3/ports/var/db/dports/build/file._opt_i3_ports_var_db_dports_sources_rsync.code.icecube.wisc.edu_icecube-tools-ports_devel_boost_1.36.0/work/boost_1.36.0/boost/function/function_template.hpp:815
#14 0xb73545f0 in boost::python::handle_exception_impl (f=@0xbfdc6fdc)
at /opt/i3/ports/var/db/dports/build/file._opt_i3_ports_var_db_dports_sources_rsync.code.icecube.wisc.edu_icecube-tools-ports_devel_boost_1.36.0/work/boost_1.36.0/libs/python/src/errors.cpp:25
#15 0xb733e177 in handle_exception<boost::python::objects::<unnamed>::bind_return> (f={m_result = @0xbfdc7030, m_f = 0x83591e8, m_args = 0x832ae0c, m_keywords = 0x0})
at /opt/i3/ports/var/db/dports/build/file._opt_i3_ports_var_db_dports_sources_rsync.code.icecube.wisc.edu_icecube-tools-ports_devel_boost_1.36.0/work/boost_1.36.0/libs/python/include/boost/python/errors.hpp:29
#16 0xb733e1ff in function_call (func=0x83591e8, args=0x832ae0c, kw=0x0)
at /opt/i3/ports/var/db/dports/build/file._opt_i3_ports_var_db_dports_sources_rsync.code.icecube.wisc.edu_icecube-tools-ports_devel_boost_1.36.0/work/boost_1.36.0/libs/python/src/object/function.cpp:613
#17 0x0805cb97 in PyObject_Call (func=0x2, arg=0x832ae0c, kw=0x0) at ../Objects/abstract.c:1861
#18 0x080c7aa7 in PyEval_EvalFrameEx (f=0x83a4104, throwflag=0) at ../Python/ceval.c:3784
#19 0x080cb1f7 in PyEval_EvalCodeEx (co=0xb7d6e2a8, globals=0xb7d69cec, locals=0x0, args=0x81a4bbc, argcount=1, kws=0x81a4bc0,
kwcount=0, defs=0x0, defcount=0, closure=0x0) at ../Python/ceval.c:2836
#20 0x080c93fe in PyEval_EvalFrameEx (f=0x81a4a84, throwflag=0) at ../Python/ceval.c:3669
#21 0x080cb1f7 in PyEval_EvalCodeEx (co=0xb7d679b0, globals=0xb7db6acc, locals=0xb7db6acc, args=0x0, argcount=0, kws=0x0,
kwcount=0, defs=0x0, defcount=0, closure=0x0) at ../Python/ceval.c:2836
#22 0x080cb347 in PyEval_EvalCode (co=0xb7d679b0, globals=0xb7db6acc, locals=0xb7db6acc) at ../Python/ceval.c:494
#23 0x080ea818 in PyRun_FileExFlags (fp=0x816b008, filename=0xbfdc931f "./examples/resources/scripts/pass1.py", start=257,
---Type <return> to continue, or q <return> to quit---
globals=0xb7db6acc, locals=0xb7db6acc, closeit=1, flags=0xbfdc7648) at ../Python/pythonrun.c:1273
#24 0x080eaab9 in PyRun_SimpleFileExFlags (fp=0x816b008, filename=0xbfdc931f "./examples/resources/scripts/pass1.py", closeit=1,
flags=0xbfdc7648) at ../Python/pythonrun.c:879
#25 0x08059335 in Py_Main (argc=1, argv=0xbfdc7714) at ../Modules/main.c:523
#26 0x080587f2 in main (argc=Cannot access memory at address 0x2) at ../Modules/python.c:23
(gdb)
OK, this is quite huge, but don’t be discouraged. Start at the top,
where the innermost function is listed, where the to-first-order most
useful information probably is. In this case it is after icetray has
entered the I3Tray::Execute()
method:
(gdb) where
#0 0xb2dbca1c in DumbFeatureExtractor::Physics (this=0x83a5c58, frame=@0xbfdc6c00)
at /home/troy/Icecube/meta-projects/offline-software/trunk/src/examples/private/modules/DumbFeatureExtractor.cxx:55
#1 0xb77afc73 in I3Module::Process (this=0x83a5c58)
at /home/troy/Icecube/meta-projects/offline-software/trunk/src/icetray/private/icetray/I3Module.cxx:179
#2 0xb77b0443 in I3Module::Do (this=0x83a5c58, f=&virtual I3Module::Process())
at /home/troy/Icecube/meta-projects/offline-software/trunk/src/icetray/private/icetray/I3Module.cxx:113
#3 0xb77b050b in I3Module::Do (this=0x83a4ed0, f=&virtual I3Module::Process())
at /home/troy/Icecube/meta-projects/offline-software/trunk/src/icetray/private/icetray/I3Module.cxx:131
#4 0xb77b050b in I3Module::Do (this=0x83a44f0, f=&virtual I3Module::Process())
at /home/troy/Icecube/meta-projects/offline-software/trunk/src/icetray/private/icetray/I3Module.cxx:131
#5 0xb779bbe6 in I3Tray::Execute (this=0x81ccd08)
Here you can see that the crashing function is
DumbFeatureExtractor::Physics()
. We can see where we are in the
function with list:
(gdb) list
50 }
51 frame->Put(outputSeries_, inIceSeries);
52 }
53
54 int *p = 0;
55 printf("%d", *p);
56
57 // ice top
58 if(featureExtractIceTop_)
59 {
Line 55 above is also what gdb reported to us when it first caught our segfault. I can examine the values of various variables:
(gdb) print outputSeries_
$1 = {static npos = 4294967295,
_M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>},
_M_p = 0x83a57b4 "InIceRecoHitSeries"}}
(gdb) print featureExtractIceTop_
$2 = true
(gdb) print p
$2 = (int *) 0x0
And this would explain my segfault (that I am dereferencing a null pointer).
Dealing with log_fatal()
calls¶
log_fatal()
is a function that throws an exception. I add a log_fatal()
before
the crashing call to printf, but I don’t give it an informative message:
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /usr/bin/python ./examples/resources/scripts/pass1.py
[Thread debugging using libthread_db enabled]
[New Thread 0xb7d98ad0 (LWP 18183)]
Loading libicetray........................................ok
Loading libdataclasses....................................ok
Loading libphys-services..................................ok
Loading libDOMcalibrator..................................ok
Loading libdataio.........................................ok
Loading libexamples.......................................ok
i3reader: Filename = /opt/i3/ports/test-data/2006data/Run00089508.i3.gz
i3reader: SkipKeys = ['I3PfFilterMask']
writer: filename = pass1.i3
/home/troy/Icecube/meta-projects/offline-software/trunk/src/dataio/private/dataio/I3Reader.cxx:177: INFO : Opened file /opt/i3/ports/test-data/2006data/Run00089508.i3.gz
/home/troy/Icecube/meta-projects/offline-software/trunk/src/dataio/private/dataio/I3WriterBase.cxx:113: INFO : Not compressing.
Geometry.....[1]
[ I3Frame (Geometry):
'I3Geometry' [Geometry] ==> I3Geometry(459538)
]
---------------------------------
Calibration.....[2]
[ I3Frame (Calibration):
'I3Calibration' [Calibration] ==> I3Calibration(11267753)
'I3Geometry' [Geometry] ==> I3Geometry(459538)
]
---------------------------------
DetectorStatus.....[3]
[ I3Frame (DetectorStatus):
'I3Calibration' [Calibration] ==> I3Calibration(11267753)
'I3DetectorStatus' [DetectorStatus] ==> I3DetectorStatus(96286)
'I3Geometry' [Geometry] ==> I3Geometry(459538)
]
---------------------------------
/home/troy/Icecube/meta-projects/offline-software/trunk/src/examples/private/modules/DumbFeatureExtractor.cxx:56: FATAL: I am crashing here but not telling you why.
Traceback (most recent call last):
File "./examples/resources/scripts/pass1.py", line 81, in <module>
tray.Execute()
File "/home/troy/Icecube/meta-projects/offline-software/trunk/build/lib/I3Tray.py", line 74, in Execute
args[0].the_tray.Execute()
RuntimeError: I am crashing here but not telling you why.
merge: 1 calls to physics 13.00s user 0.00s system
Program exited with code 01.
(gdb) where
No stack.
Here you can see that I get the filename, linenumber, and message
associated with the crash, but I have no stacktrace and cannot examine
the values/conditions that may have provoked this call to
log_fatal()
. This is because log_fatal()
has thrown an
exception. I can tell gdb to stop when an exception is thrown by
issuing catch throw:
(gdb) catch throw
Catchpoint 1 (throw)
(gdb) r
Starting program: /usr/bin/python ./examples/resources/scripts/pass1.py
[Thread debugging using libthread_db enabled]
[New Thread 0xb7d5fad0 (LWP 18185)]
Loading libicetray........................................ok
Loading libdataclasses....................................ok
Loading libphys-services..................................ok
Loading libDOMcalibrator..................................ok
Loading libdataio.........................................ok
Loading libexamples.......................................ok
i3reader: Filename = /opt/i3/ports/test-data/2006data/Run00089508.i3.gz
i3reader: SkipKeys = ['I3PfFilterMask']
writer: filename = pass1.i3
/home/troy/Icecube/meta-projects/offline-software/trunk/src/dataio/private/dataio/I3Reader.cxx:177: INFO : Opened file /opt/i3/ports/test-data/2006data/Run00089508.i3.gz
/home/troy/Icecube/meta-projects/offline-software/trunk/src/dataio/private/dataio/I3WriterBase.cxx:113: INFO : Not compressing.
Geometry.....[1]
[ I3Frame (Geometry):
'I3Geometry' [Geometry] ==> I3Geometry(459538)
]
---------------------------------
Calibration.....[2]
[ I3Frame (Calibration):
'I3Calibration' [Calibration] ==> I3Calibration(11267753)
'I3Geometry' [Geometry] ==> I3Geometry(459538)
]
---------------------------------
DetectorStatus.....[3]
[ I3Frame (DetectorStatus):
'I3Calibration' [Calibration] ==> I3Calibration(11267753)
'I3DetectorStatus' [DetectorStatus] ==> I3DetectorStatus(96286)
'I3Geometry' [Geometry] ==> I3Geometry(459538)
]
---------------------------------
/home/troy/Icecube/meta-projects/offline-software/trunk/src/examples/private/modules/DumbFeatureExtractor.cxx:56: FATAL: I am crashing here but not telling you why.
[Switching to Thread 0xb7d5fad0 (LWP 18185)]
Catchpoint 1 (exception thrown)
0xb73b7e05 in __cxa_throw () from /usr/lib/libstdc++.so.6
(gdb)
And I see that gdb has stopped me inside the exception-throwing function. This isn’t immediately helpful:
(gdb) list
../Modules/python.c: No such file or directory. in
../Modules/python.c
But I can ask for a stacktrace:
(gdb) where
#0 0xb73b7e05 in __cxa_throw () from /usr/lib/libstdc++.so.6
#1 0xb2d3fbfb in DumbFeatureExtractor::Physics (this=0x83a5c58, frame=@0xbfd20360)
at /home/troy/Icecube/meta-projects/offline-software/trunk/src/examples/private/modules/DumbFeatureExtractor.cxx:56
#2 0xb7732c73 in I3Module::Process (this=0x83a5c58)
at /home/troy/Icecube/meta-projects/offline-software/trunk/src/icetray/private/icetray/I3Module.cxx:179
#3 0xb7733443 in I3Module::Do (this=0x83a5c58, f=&virtual I3Module::Process())
at /home/troy/Icecube/meta-projects/offline-software/trunk/src/icetray/private/icetray/I3Module.cxx:113
#4 0xb773350b in I3Module::Do (this=0x83a4ed0, f=&virtual I3Module::Process())
at /home/troy/Icecube/meta-projects/offline-software/trunk/src/icetray/private/icetray/I3Module.cxx:131
#5 0xb773350b in I3Module::Do (this=0x83a44f0, f=&virtual I3Module::Process())
at /home/troy/Icecube/meta-projects/offline-software/trunk/src/icetray/private/icetray/I3Module.cxx:131
#6 0xb771ebe6 in I3Tray::Execute (this=0x81ccd08)
and I see I need to move up the stack from __cxa_throw()
to the site of the throw:
(gdb) up
#1 0xb2d3fbfb in DumbFeatureExtractor::Physics (this=0x83a5c58, frame=@0xbfd20360)
at /home/troy/Icecube/meta-projects/offline-software/trunk/src/examples/private/modules/DumbFeatureExtractor.cxx:56
56 log_fatal("I am crashing here but not telling you why.");
(gdb) list
51 frame->Put(outputSeries_, inIceSeries);
52 }
53
54 int *p = 0;
55 if (!p)
56 log_fatal("I am crashing here but not telling you why.");
57 printf("%d", *p);
58
59 // ice top
60 if(featureExtractIceTop_)
If you know that your program will throw (e.g. you’re diagnosing a
problem that manifests itself via log_fatal()
, the catch throw
might not work at first:
% gdb --args python ./examples/resources/scripts/pass1.py
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
(gdb) catch throw
Function "__cxa_throw" not defined.
(gdb)
But after the first time you have run your program, gdb will know that there exists an exception-throwing function and will allow you to catch there:
(gdb) r
Starting program: /usr/bin/python ./examples/resources/scripts/pass1.py
[Thread debugging using libthread_db enabled]
[New Thread 0xb7d8aad0 (LWP 18191)]
Loading libicetray........................................ok
Loading libdataclasses....................................Quit
[ etc etc... get dumped back to the prompt ]
(gdb) catch throw
Catchpoint 1 (throw)
(gdb) r
Profiling C++ Code¶
Profilers show you how much time your code is spending in each function. The “80/20 rule” is that on average your code will spend 80% of its time in 20% of the code. This means of course that only 20% of the code is really worth optimizing. We tend to be extremely bad at predicting which 20% that will be.
When one optimizes code, one makes a decision that the loss of clarity introduced by rearranging code is worth the increase in speed that it brings. One therefore wants to do it only when and where necessary.
Furthermore, do not ever optimize code that is not thoroughly, I mean thoroughly tested:
"It is much, much easier to make correct code fast than it is to make fast code correct."
Use the utilities valgrind (specifically the callgrind tool) and kcachegrind (nice graphical tool for viewing results). Google them, you’ll find stuff.