Skip to content

Commit

Permalink
Document all sorts of C debugging tips
Browse files Browse the repository at this point in the history
backport of cbb4bc3
Conflicts:
	doc/index.rst
  • Loading branch information
timholy authored and tkelman committed Nov 18, 2014
1 parent c14aeab commit 507a4c6
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 88 deletions.
13 changes: 13 additions & 0 deletions doc/devdocs/C.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
:orphan:

.. _devdocs-index:

#####################################
Developing/debugging Julia's C code
#####################################

.. toctree::
:maxdepth: 1

backtraces
debuggingtips
107 changes: 107 additions & 0 deletions doc/devdocs/backtraces.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
*******************************************
Reporting and analyzing crashes (segfaults)
*******************************************

So you managed to break Julia. Congratulations! Collected here are some general procedures you can undergo for common symptoms encountered when something goes awry. Including the information from these debugging steps can greatly help the maintainers when tracking down a segfault or trying to figure out why your script is running slower than expected.

If you've been directed to this page, find the symptom that best matches what you're experiencing and follow the instructions to generate the debugging information requested. Table of symptoms:

* `Segfaults during bootstrap (sysimg.jl)`_

* `Segfaults when running a script`_

* `Errors during julia startup`_

.. _version info:

Version/Environment info
------------------------

No matter the error, we will always need to know what version of julia you are running. When julia first starts up, a header is printed out with a version number and date. If your version is ``0.2.0`` or higher, please include the output of ``versioninfo()`` in any report you create::

julia> versioninfo()
Julia Version 0.3.3-pre+25
Commit 417b50a* (2014-11-03 11:32 UTC)
Platform Info:
System: Linux (x86_64-linux-gnu)
CPU: Intel(R) Core(TM) i7 CPU L 640 @ 2.13GHz
WORD_SIZE: 64
BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Nehalem)
LAPACK: libopenblas
LIBM: libopenlibm
LLVM: libLLVM-3.3


.. _Segfaults during bootstrap (sysimg.jl):

Segfaults during bootstrap (sysimg.jl)
--------------------------------------

Segfaults toward the end of the ``make`` process of building julia are a common symptom of something going wrong while julia is preparsing the corpus of code in the ``base/`` folder. Many factors can contribute toward this process dying unexpectedly, however it is as often as not due to an error in the C-code portion of julia, and as such must typically be debugged with a debug build inside of ``gdb``. Explicitly:

Create a debug build of julia::

$ cd <julia_root>
$ make debug

Note that this process will likely fail with the same error as a normal ``make`` incantation, however this will create a debug executable that will offer ``gdb`` the debugging symbols needed to get accurate backtraces. Next, manually run the bootstrap process inside of ``gdb``::

$ cd base/
$ gdb -x ../contrib/debug_bootstrap.gdb

This will start ``gdb``, attempt to run the bootstrap process using the debug build of julia, and print out a backtrace if (when) it segfaults. You may need to hit ``<enter>`` a few times to get the full backtrace. Create a gist_ with the backtrace, the `version info`_, and any other pertinent information you can think of and open a new issue_ on Github with a link to the gist.


.. _Segfaults when running a script:

Segfaults when running a script
-------------------------------

The procedure is very similar to `Segfaults during bootstrap (sysimg.jl)`_. Create a debug build of Julia, and run your script inside of a debugged julia process::

$ cd <julia_root>
$ make debug
$ gdb --args usr/bin/julia-debug-readline <path_to_your_script>

Note that ``gdb`` will sit there, waiting for instructions. Type ``r`` to run the process, and ``bt`` to generate a backtrace once it segfaults::

(gdb) r
Starting program: /home/sabae/src/julia/usr/bin/julia-debug-readline ./test.jl
...
(gdb) bt

Create a gist_ with the backtrace, the `version info`_, and any other pertinent information you can think of and open a new issue_ on Github with a link to the gist.


.. _Errors during julia startup:

Errors during julia startup
---------------------------

Occasionally errors occur during julia's startup process (especially when using binary distributions, as opposed to compiling from source) such as the following::

$ julia
exec: error -5

These errors typically indicate something is not getting loaded properly very early on in the bootup phase, and our best bet in determining what's going wrong is to use external tools to audit the disk activity of the ``julia`` process:

* On Linux, use ``strace``::

$ strace julia

* On OSX, use ``dtruss``::

$ dtruss -f julia

Create a gist_ with the ``strace``/ ``dtruss`` ouput, the `version info`_, and any other pertinent information and open a new issue_ on Github with a link to the gist.


Glossary
--------

A few terms have been used as shorthand in this guide:

* ``<julia_root>`` refers to the root directory of the julia source tree; e.g. it should contain folders such as ``base``, ``deps``, ``src``, ``test``, etc.....

.. _gist: http://gist.github.com
.. _issue: https://github.com/JuliaLang/julia/issues?state=open
59 changes: 59 additions & 0 deletions doc/devdocs/debuggingtips.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
******************
gdb debugging tips
******************

Displaying Julia variables
--------------------------

Within ``gdb``, any ``jl_value_t*`` object ``obj`` can be displayed using
::

(gdb) call jl_(obj)

The object will be displayed in the julia session, not in the gdb session.
This is a useful way to discover the types and values of objects being
manipulated by Julia's C code.

Similarly, if you're debugging some of julia's internals (e.g.,
``inference.jl``), you can print ``obj`` using
::

ccall(:jl_, Void, (Any,), obj)

This is a good way to circumvent problems that arise from the order in which julia's output streams are initialized.

Inserting breakpoints for inspection from gdb
---------------------------------------------

In your ``gdb`` session, set a breakpoint in ``jl_breakpoint`` like so::

(gdb) break jl_breakpoint

Then within your Julia code, insert a call to ``jl_breakpoint`` by adding::

ccall(:jl_breakpoint, Void, ())

If you back up to the ``jl_apply`` frame, then you can display the arguments to the function using, e.g.,
::

(gdb) call jl_(args[0])


Inserting breakpoints upon certain conditions
---------------------------------------------

Loading a particular file
~~~~~~~~~~~~~~~~~~~~~~~~~

Let's say the file is ``sysimg.jl``::

(gdb) break jl_load if strcmp(fname, "sysimg.jl")==0

Calling a particular method
~~~~~~~~~~~~~~~~~~~~~~~~~~~

::

(gdb) break jl_apply_generic if strcmp(F->name->name, "method_to_break")==0

Since this function is used for every call, you will make everything 1000x slower if you do this.
13 changes: 13 additions & 0 deletions doc/devdocs/julia.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
:orphan:

.. _devdocs-index:

####################################
Documentation of Julia's Internals
####################################

.. toctree::
:maxdepth: 1

cartesian
meta

This comment has been minimized.

Copy link
@timholy

timholy Nov 18, 2014

Author Member

You're probably right about meta. If this line causes make html to fail, this line should be deleted from 0.3.

This comment has been minimized.

Copy link
@tkelman

tkelman Nov 18, 2014

Contributor

It's not failing, but it is giving some warnings. (This was my first time trying to build the docs...)

/home/tkelman/Julia/julia/doc/devdocs/index.rst:7: WARNING: duplicate label devdocs-index, other instance in /home/tkelman/Julia/julia/doc/devdocs/C.rst
/home/tkelman/Julia/julia/doc/devdocs/julia.rst:9: WARNING: toctree contains reference to nonexisting document u'devdocs/meta'
/home/tkelman/Julia/julia/doc/devdocs/julia.rst:7: WARNING: duplicate label devdocs-index, other instance in /home/tkelman/Julia/julia/doc/devdocs/index.rst

This comment has been minimized.

Copy link
@timholy

timholy Nov 18, 2014

Author Member

I'll fix it, but I'm up to my neck in another branch right now.

This comment has been minimized.

Copy link
@timholy

timholy Nov 18, 2014

Author Member

Fixed in 4611fa8

5 changes: 3 additions & 2 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ Developer Documentation
#######################

.. toctree::
:maxdepth: 1
:maxdepth: 2

devdocs/cartesian
devdocs/julia
devdocs/C
100 changes: 14 additions & 86 deletions doc/manual/faq.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Suppose you call a function like this::
julia> x # x is unchanged!
10

In Julia, any function (including ``change_value!()``) can't change the binding of a local variable. If ``x`` (in the calling scope) is bound to a immutable object (like a real number), you can't modify the object; likewise, if x is bound in the calling scope to a Dict, you can't change it to be bound to an ASCIIString.
In Julia, any function (including ``change_value!()``) can't change the binding of a local variable. If ``x`` (in the calling scope) is bound to a immutable object (like a real number), you can't modify the object; likewise, if x is bound in the calling scope to a Dict, you can't change it to be bound to an ASCIIString.

But here is a thing you should pay attention to: suppose ``x`` is bound to an Array (or any other mutable type). You cannot "unbind" ``x`` from this Array. But, since an Array is a *mutable* type, you can change its content. For example::

Expand Down Expand Up @@ -193,7 +193,7 @@ Julia uses machine arithmetic for integer computations. This means that the rang

julia> typemax(Int)
9223372036854775807

julia> ans+1
-9223372036854775808

Expand Down Expand Up @@ -255,31 +255,31 @@ At first blush, this seems reasonable enough since 9223372036854775807 is much c

>> n = int64(2)^62
4611686018427387904

>> n + (n - 1)
9223372036854775807

>> (n + n) - 1
9223372036854775806

This makes it hard to write many basic integer algorithms since a lot of
common techniques depend on the fact that machine addition with overflow *is*
associative. Consider finding the midpoint between integer values ``lo`` and
``hi`` in Julia using the expression ``(lo + hi) >>> 1``::

julia> n = 2^62
4611686018427387904

julia> (n + 2n) >>> 1
6917529027641081856

See? No problem. That's the correct midpoint between 2^62 and 2^63, despite
the fact that ``n + 2n`` is -4611686018427387904. Now try it in Matlab::

>> (n + 2*n)/2

ans =

4611686018427387904

Oops. Adding a ``>>>`` operator to Matlab wouldn't help, because saturation
Expand Down Expand Up @@ -471,7 +471,7 @@ to change the type of field ``a``:

julia> t.a = 4.5f0
4.5f0

julia> typeof(t.a)
Float32

Expand All @@ -482,10 +482,10 @@ change:

julia> m.a = 4.5f0
4.5

julia> typeof(m.a)
Float64

The fact that the type of ``m.a`` is known from ``m``'s type---coupled
with the fact that its type cannot change mid-function---allows the
compiler to generate highly-optimized code for objects like ``m`` but
Expand All @@ -502,10 +502,10 @@ an abstract type:

julia> typeof(m.a)
Float64

julia> m.a = 4.5f0
4.5f0

julia> typeof(m.a)
Float32

Expand Down Expand Up @@ -645,7 +645,7 @@ With this approach, one can write functions such as::

julia> myfunc(MyContainer(1:3))
2

julia> myfunc(MyContainer(1.0:3))
3.0

Expand Down Expand Up @@ -735,75 +735,3 @@ When are deprecated functions removed?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Deprecated functions are removed after the subsequent release. For example, functions marked as deprecated in the 0.1 release will not be available starting with the 0.2 release.

Developing Julia
----------------

How do I debug julia's C code? (running the julia REPL from within a debugger like gdb)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

First, you should build the debug version of julia with ``make
debug``. Below, lines starting with ``(gdb)`` mean things you should
type at the gdb prompt.

From the shell
^^^^^^^^^^^^^^

The main challenge is that Julia and gdb each need to have their own
terminal, to allow you to interact with them both. One approach is to
use gdb's ``attach`` functionality to debug an already-running julia
session. However, on many systems you'll need root access to get this
to work. What follows is a method that can be implemented with just
user-level permissions.

The first time you do this, you'll need to define a script, here
called ``oterm``, containing the following lines::

ps
sleep 600000

Make it executable with ``chmod +x oterm``.

Now:

- From a shell (called shell 1), type ``xterm -e oterm &``. You'll see
a new window pop up; this will be called terminal 2.

- From within shell 1, ``gdb julia-debug``. You can find this
executable within ``julia/usr/bin``.

- From within shell 1, ``(gdb) tty /dev/pts/#`` where ``#`` is the
number shown after ``pts/`` in terminal 2.

- From within shell 1, ``(gdb) run``

- From within terminal 2, issue any preparatory commands in Julia that
you need to get to the step you want to debug

- From within shell 1, hit Ctrl-C

- From within shell 1, insert your breakpoint, e.g., ``(gdb) b codegen.cpp:2244``
- From within shell 1, ``(gdb) c`` to resume execution of julia

- From within terminal 2, issue the command that you want to
debug. Shell 1 will stop at your breakpoint.


Within emacs
^^^^^^^^^^^^

- ``M-x gdb``, then enter ``julia-debug`` (this is easiest from
within julia/usr/bin, or you can specify the full path)

- ``(gdb) run``

- Now you'll see the Julia prompt. Run any commands in Julia you need
to get to the step you want to debug.

- Under emacs' "Signals" menu choose BREAK---this will return you to the ``(gdb)`` prompt

- Set a breakpoint, e.g., ``(gdb) b codegen.cpp:2244``

- Go back to the Julia prompt via ``(gdb) c``

- Execute the Julia command you want to see running.

0 comments on commit 507a4c6

Please sign in to comment.