How to debug _k2

This section introduces how to debug _k2.

Code with bugs

Suppose you have the following buggy code,

Listing 13 Code with bugs
#!/usr/bin/env python3

import k2

tensor = k2.RaggedTensor([[1, 2], [3]])
print(tensor[2])

Error logs of the buggy code

After running it, you would get the following error logs:

Listing 14 Error logs of the buggy code
[F] /root/fangjun/open-source/k2/k2/csrc/array.h:178:k2::Array1<T> k2::Array1<T>::Arange(int32_t, int32_t) const [with T = int; int32_t = int] Check failed: end >= start (0 vs. 3) 


[ Stack-Trace: ]
/root/fangjun/open-source/k2/build-cpu-debug/lib/libk2_log.so(k2::internal::GetStackTrace()+0x5b) [0x7f716d321105]
/root/fangjun/open-source/k2/build-cpu-debug/lib/_k2.cpython-38-x86_64-linux-gnu.so(+0xb52e2) [0x7f716dc362e2]
/root/fangjun/open-source/k2/build-cpu-debug/lib/_k2.cpython-38-x86_64-linux-gnu.so(+0x1b8676) [0x7f716dd39676]
/root/fangjun/open-source/k2/build-cpu-debug/lib/_k2.cpython-38-x86_64-linux-gnu.so(+0x1eab1d) [0x7f716dd6bb1d]
/root/fangjun/open-source/k2/build-cpu-debug/lib/_k2.cpython-38-x86_64-linux-gnu.so(+0x1fbf7f) [0x7f716dd7cf7f]
/root/fangjun/open-source/k2/build-cpu-debug/lib/_k2.cpython-38-x86_64-linux-gnu.so(+0x1fa291) [0x7f716dd7b291]
/root/fangjun/open-source/k2/build-cpu-debug/lib/_k2.cpython-38-x86_64-linux-gnu.so(+0x1f4b2f) [0x7f716dd75b2f]
/root/fangjun/open-source/k2/build-cpu-debug/lib/_k2.cpython-38-x86_64-linux-gnu.so(+0x1f4ba3) [0x7f716dd75ba3]
/root/fangjun/open-source/k2/build-cpu-debug/lib/_k2.cpython-38-x86_64-linux-gnu.so(+0x916e0) [0x7f716dc126e0]
/star-fj/fangjun/open-source/pyenv/versions/3.8.0/lib/libpython3.8.so.1.0(PyCFunction_Call+0xf5) [0x7f723baa2535]
/star-fj/fangjun/open-source/pyenv/versions/3.8.0/lib/libpython3.8.so.1.0(_PyObject_MakeTpCall+0x9e) [0x7f723ba9f80e]
/star-fj/fangjun/open-source/pyenv/versions/3.8.0/lib/libpython3.8.so.1.0(+0xa3c8b) [0x7f723baa3c8b]
/star-fj/fangjun/open-source/pyenv/versions/3.8.0/lib/libpython3.8.so.1.0(+0x11b93e) [0x7f723bb1b93e]
/star-fj/fangjun/open-source/pyenv/versions/3.8.0/lib/libpython3.8.so.1.0(+0x11baa7) [0x7f723bb1baa7]
/star-fj/fangjun/open-source/pyenv/versions/3.8.0/lib/libpython3.8.so.1.0(PyObject_GetItem+0x49) [0x7f723ba85de9]
/star-fj/fangjun/open-source/pyenv/versions/3.8.0/lib/libpython3.8.so.1.0(_PyEval_EvalFrameDefault+0x5025) [0x7f723ba72355]
/star-fj/fangjun/open-source/pyenv/versions/3.8.0/lib/libpython3.8.so.1.0(_PyEval_EvalCodeWithName+0xb67) [0x7f723bba0f47]
/star-fj/fangjun/open-source/pyenv/versions/3.8.0/lib/libpython3.8.so.1.0(PyEval_EvalCodeEx+0x3e) [0x7f723bba0ffe]
/star-fj/fangjun/open-source/pyenv/versions/3.8.0/lib/libpython3.8.so.1.0(PyEval_EvalCode+0x1b) [0x7f723bba102b]
/star-fj/fangjun/open-source/pyenv/versions/3.8.0/lib/libpython3.8.so.1.0(PyRun_FileExFlags+0x122) [0x7f723bbe6902]
/star-fj/fangjun/open-source/pyenv/versions/3.8.0/lib/libpython3.8.so.1.0(PyRun_SimpleFileExFlags+0xfd) [0x7f723bbe6add]
/star-fj/fangjun/open-source/pyenv/versions/3.8.0/lib/libpython3.8.so.1.0(Py_RunMain+0x7a0) [0x7f723bc0a750]
/star-fj/fangjun/open-source/pyenv/versions/3.8.0/lib/libpython3.8.so.1.0(Py_BytesMain+0x56) [0x7f723bc0ac26]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xe7) [0x7f723b630bf7]
python3(_start+0x2a) [0x55f05c1e378a]

Traceback (most recent call last):
  File "test.py", line 6, in <module>
    print(tensor[2])
RuntimeError: 
    Some bad things happened. Please read the above error messages and stack
    trace. If you are using Python, the following command may be helpful:

      gdb --args python /path/to/your/code.py

    (You can use `gdb` to debug the code. Please consider compiling
    a debug version of k2.).

    If you are unable to fix it, please open an issue at:

      https://github.com/k2-fsa/k2/issues/new
    

Ways to debug

In order debug it, please first follow Build a debug version to build a debug version of k2 so that you can use gdb to debug the code.

Note

Since the underlying implementation is in C++ you can you use gdb to debug it, even if you are using Python.

First, let us use gdb to run our code:

(py38) kuangfangjun:build-cpu-debug$ gdb --args python3 ./test.py

You will see the following output:

GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git
Copyright (C) 2018 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 "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from python3...done.
warning: File "/star-fj/fangjun/open-source/pyenv/versions/3.8.0/bin/python3.8-gdb.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".
To enable execution of this file add
        add-auto-load-safe-path /star-fj/fangjun/open-source/pyenv/versions/3.8.0/bin/python3.8-gdb.py
line to your configuration file "/root/fangjun/.gdbinit".
To completely disable this security protection add
        set auto-load safe-path /
line to your configuration file "/root/fangjun/.gdbinit".
For more information about this security protection see the
"Auto-loading safe path" section in the GDB manual.  E.g., run from the shell:
        info "(gdb)Auto-loading safe path"
(gdb)

Next, enter catch throw so that it stops the process on exception:

(gdb) catch throw
Catchpoint 1 (throw)

Then we can run the program with run:

(gdb) run
Starting program: /star-fj/fangjun/py38/bin/python3 ./test.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7fff90f66700 (LWP 1184088)]
[New Thread 0x7fff90765700 (LWP 1184089)]
... ...
[F] /root/fangjun/open-source/k2/k2/csrc/array.h:179:k2::Array1<T> k2::Array1<T>::Arange(int32_t, int32_t) const [with T = int; int32_
t = int] Check failed: end <= dim_ (32767 vs. 3)


[ Stack-Trace: ]
/root/fangjun/open-source/k2/build-cpu-debug/lib/libk2_log.so(k2::internal::GetStackTrace()+0x5b) [0x7fff2913c105]
/root/fangjun/open-source/k2/build-cpu-debug/lib/_k2.cpython-38-x86_64-linux-gnu.so(+0xb52e2) [0x7fff29a512e2]
... ...
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xe7) [0x7ffff7458bf7]
/star-fj/fangjun/py38/bin/python3(_start+0x2a) [0x55555555478a]


Thread 1 "python3" hit Catchpoint 1 (exception thrown), 0x00007ffff2553d1d in __cxa_throw ()
   from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
(gdb)

We can find the backtrace with backtrace:

(gdb) backtrace
#0  0x00007ffff2553d1d in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1  0x00007fff29a51365 in k2::internal::Logger::~Logger (this=0x7fffffffd5e0, __in_chrg=<optimized out>)
    at /root/fangjun/open-source/k2/k2/csrc/log.h:195
#2  0x00007fff29b54786 in k2::Array1<int>::Arange (this=0x555558db63f8, start=3, end=32767)
    at /root/fangjun/open-source/k2/k2/csrc/array.h:179
#3  0x00007fff29b86b1d in k2::<lambda(k2::RaggedAny&, int32_t)>::operator()(k2::RaggedAny &, int32_t) const (
    __closure=0x555558d973e8, self=..., i=2) at /root/fangjun/open-source/k2/build-cpu-debug/k2/python/csrc/torch/v2/any.cc:107
#4  0x00007fff29b97f7f in pybind11::detail::argument_loader<k2::RaggedAny&, int>::call_impl<pybind11::object, k2::PybindRaggedAny(pybind11::module&)::<lambda(k2::RaggedAny&, int32_t)>&, 0, 1, pybind11::detail::void_type>(k2::<lambda(k2::RaggedAny&, int32_t)> &, std::index_sequence, pybind11::detail::void_type &&) (this=0x7fffffffd820, f=...)
    at /star-fj/fangjun/open-source/k2/build-cpu-debug/_deps/pybind11-src/include/pybind11/cast.h:1439
#5  0x00007fff29b96291 in pybind11::detail::argument_loader<k2::RaggedAny&, int>::call<pybind11::object, pybind11::detail::void_type,
k2::PybindRaggedAny(pybind11::module&)::<lambda(k2::RaggedAny&, int32_t)>&>(k2::<lambda(k2::RaggedAny&, int32_t)> &) (
    this=0x7fffffffd820, f=...) at /star-fj/fangjun/open-source/k2/build-cpu-debug/_deps/pybind11-src/include/pybind11/cast.h:1408
#6  0x00007fff29b90b2f in pybind11::cpp_function::<lambda(pybind11::detail::function_call&)>::operator()(pybind11::detail::function_call &) const (__closure=0x0, call=...)
    at /root/fangjun/open-source/k2/build-cpu-debug/_deps/pybind11-src/include/pybind11/pybind11.h:249
#7  0x00007fff29b90ba3 in pybind11::cpp_function::<lambda(pybind11::detail::function_call&)>::_FUN(pybind11::detail::function_call &)
    () at /root/fangjun/open-source/k2/build-cpu-debug/_deps/pybind11-src/include/pybind11/pybind11.h:224
#8  0x00007fff29a2d6e0 in pybind11::cpp_function::dispatcher (self=0x7fff29fd4a50, args_in=0x7ffff64adb40, kwargs_in=0x0)
    at /root/fangjun/open-source/k2/build-cpu-debug/_deps/pybind11-src/include/pybind11/pybind11.h:929
#9  0x00007ffff78ca535 in cfunction_call_varargs (kwargs=<optimized out>, args=<optimized out>, func=0x7fff29fd6310)
    at Objects/call.c:742

The remaining steps are the same for debugging a C/C++ program with gdb.

Summary

The most important parts of the debugging process are:

    1. Build a debug version of k2

    1. Run catch throw

    1. View the backtrace on exception