Quick Start

The mdb program has two subcommands which act as modes of operation, launch and attach. mdb’s command line interface (CLI) is built with Click and each command has a --help option. For more information please see the Command Line Interface documentation. For example, mdb attach --help produces the following output.

Usage: mdb attach [OPTIONS]

  Attach to mdb debug server.

  Example:

  $ mdb attach -x script.mdb

Options:
  -h, --hostname TEXT            Hostname where exchange server is running.
                                 [default: localhost]
  -p, --port INTEGER             Starting port address. Each rank's port is
                                 assigned as [port_address + rank].  [default:
                                 2000]
  -x, --exec-script FILENAME     Execute a set of mdb commands contained in a
                                 script file. This script will run and then
                                 normal shell mode will be resumed unless
                                 `--interactive=false` is also passed.
  --interactive BOOLEAN          Controls whether mdb will spawn an
                                 interactive debugging shell or not. Intended
                                 use is for with `-x/--exec-script`.
  --log-level TEXT               Choose minimum level of debug messages:
                                 [DEBUG, INFO, WARN, ERROR, CRITICAL]
                                 [default: WARN]
  --log-file TEXT                The path to a file to write the logs to. Will
                                 create the file if it does not exist. Special
                                 values are `stderr` and `stdout`, which
                                 correspond to the programs standard error and
                                 output respectively.  [default: mdb-
                                 attach.log]
  --plot-lib TEXT                Plotting library to use. Recommended default
                                 is [termgraph] but if this is not available
                                 [matplotlib] will be used. [matplotlib] is
                                 best if there are many ranks to debug e.g.,
                                 -n 100.  [default: termgraph]
  --connection-attempts INTEGER  Maximum number of failed connection attempts.
                                 A connection attempt is made once per second.
                                 [default: 3]
  --help                         Show this message and exit.

An example program

Well, first things first, we need a program to debug. Whilst you probably already have one if you are looking for an MPI debugger, it may be best to start simple. To that end, I have provided a simple example program written in fortran. We will need to move into the examples/ directory and compile the code.

$ cd examples/
$ make
mpif90 -ggdb -O0 -c  simple-mpi.f90 -o simple-mpi.o
mpif90  simple-mpi.o -o simple-mpi.exe
mpic++ -ggdb -O0 -c  simple-mpi-cpp.cpp -o simple-mpi-cpp.o
mpic++  simple-mpi-cpp.o -o simple-mpi-cpp.exe
$ ls
Makefile   simple-mpi-cpp.cpp  simple-mpi-cpp.o  simple-mpi.f90  simple-mpi-script.mdb
README.md  simple-mpi-cpp.exe  simple-mpi.exe    simple-mpi.o

You should now see the binary simple-mpi.exe. I also included a simple debug script simple-mpi-script.mdb which can be used to execute a sample debug session, but we will come to that later.

Launching the mdb Client

To begin a debugging session, first we must launch the debugger as part of the MPI launcher. Currently supported MPI launchers are Intel MPI and open MPI mpirun. For simplicity, this example will all be run on the same machine

Here is an example launching mdb with the simple-mpi.exe binary on 8 processes. If you don’t have an 8 core processor to hand, then you can pass the --oversubscribe option to open MPI’s mpirun using --mpi-command "mpirun --oversubscribe". Intel’s mpirun can oversubscribe by default, but for this tutorial I am running (and compiling) with open MPI (and gfortran). By default the log level of mdb launch is set to WARN. For the tutorial we will override this to show more information using the --log-level flag.

$ mdb launch -b gdb -n 8 -t ./simple-mpi.exe --log-level=DEBUG
running on host: 127.0.1.1
to connect to the debugger run:
mdb attach -h 127.0.1.1 -p 2000

DEBUG:mdb.mdb_launch:generating ssl certificate and key
DEBUG:mdb.mdb_launch:openssl req -x509 -newkey rsa:4096 -sha256 -days 365 -keyout

[key stuff omitted]

DEBUG:asyncio:Using selector: EpollSelector
DEBUG:mdb.mdb_launch:launch command: mpirun --app .mdb.appfile
INFO:mdb.exchange_server:echange server started :: localhost:2000
DEBUG:mdb.async_connection:msg received [debug_conn_request]
INFO:mdb.exchange_server:exchange server received [debug_conn_request] from debug client.
DEBUG:mdb.async_connection:sent message [mdb_conn_response]
[repeats 7 more times]
DEBUG:mdb.async_connection:msg received [debug_init_complete]
INFO:mdb.exchange_server:Client sent initialization confirmed
[repeats 7 more times]
connecting to debuggers ... (8/8)
all debug clients connected
INFO:mdb.exchange_server:Client sent initialization confirmed

Note

If your target program requires command line arguments, you can pass those using the option --. For example, if you would normally run your binary as ./binary -arg1 value, then you can launch it with the following command mdb using mdb launch -n 2 -t ./binary -- -arg1 value.

Attaching to the mdb Client

Now in a separate terminal (but same physical machine – see Multi-node debugging (HPC) for information on how to attach to remote machines) run the attach command.

$ mdb attach -h 127.0.1.1 -p 2000 --log-level=DEBUG
mdb - mpi debugger - built on various backends. Type ? for more info. To exit interactive mode
type "q", "quit", "Ctrl+D" or "Ctrl+]".
(mdb 0-7)

The first part of the output will look something like the above. This means that mdb has successfully attached to the client processes (launched in the previous step). If you get a connection error like the following, then please check mdb was launched properly in the first step.

$ mdb attach --log-level=DEBUG
couldn't connect to exchange server at localhost:2000.

Hopefully you are now connected and you see the following welcome message.

mdb - mpi debugger - built on gdb. Type ? for more info. To exit interactive mode type "q",
"quit", "Ctrl+D" or "Ctrl+]".

This text provides information on how to use mdb. Typing help or ? will print this same message. Typing help or ? followed by one of the mdb commands will display help text for that command e.g.,

(mdb 0-7) ? command

     Description:
     Run [command] on every selected process. Alternatively, manually
     specify which ranks to run the command on.

     Example:
     The following command will run {self.backend.name} command [command] on every process.

         (mdb) command [command]

     The following command will run {self.backend.name} command [command] on processes 0,3,4 and 5.

         (mdb) command 0,3-5 [command]

Another important point is the mdb prompt (mdb 0-7), in this specific example. This tells us that any commands issued via command will be sent to processors 0-7. For example,

(mdb 0-7) command info proc
0:      process 54584
0:      cmdline = '/home/melt/sync/cambridge/projects/side/mdb/examples/simple-mpi.exe'
0:      cwd = '/home/melt/sync/cambridge/projects/side/mdb'
0:      exe = '/home/melt/sync/cambridge/projects/side/mdb/examples/simple-mpi.exe'
************************************************************************
1:      process 54576
1:      cmdline = '/home/melt/sync/cambridge/projects/side/mdb/examples/simple-mpi.exe'
1:      cwd = '/home/melt/sync/cambridge/projects/side/mdb'
1:      exe = '/home/melt/sync/cambridge/projects/side/mdb/examples/simple-mpi.exe'
************************************************************************
.
.
.
************************************************************************
7:      process 54590
7:      cmdline = '/home/melt/sync/cambridge/projects/side/mdb/examples/simple-mpi.exe'
7:      cwd = '/home/melt/sync/cambridge/projects/side/mdb'
7:      exe = '/home/melt/sync/cambridge/projects/side/mdb/examples/simple-mpi.exe'

From brevity I have used ... to shorten the output. command is used to send commands directly to the gdb instance of each processor (see Broadcast mode which covers the broadcast command – this is useful for longer debug sessions). In this case I sent info proc which prints information on each process. The output is sorted in numerical order with each process having it’s own rank id prepended to the output in the format [rank id]:. Each rank’s output is separated by a dividing line of asterisk characters i.e., ***. If you want to issue a gdb command to a specific rank (or set of ranks) only then you can provide an optional set of ranks, either comma-separated, hyphen-separated or a mix of both. For example, to send command backtrace -1 to ranks 0,2-4 use the following.

(mdb 0-7) command 0,2-4 backtrace -1
0:      #0  simple () at simple-mpi.f90:8
************************************************************************
2:      #0  simple () at simple-mpi.f90:8
************************************************************************
3:      #0  simple () at simple-mpi.f90:8
************************************************************************
4:      #0  simple () at simple-mpi.f90:8

In theory you now have enough information to start debugging your own programs. Have a play with this simple example if you want to get to grips with mdb. There are a couple more useful things I want to show you though before you leave.

Broadcast mode

Whilst the command command is pretty useful. For long debugging sessions it can be annoying constantly prefixing command to every gdb command you want to run. This is where broadcast mode comes in handy. In broadcast mode all commands will be automatically prefixed with command so that they run on the selected ranks. By default all ranks are selected unless you have manually specified a different selection with the select command.

To enter broadcast mode type the following,

(mdb 0-7) broadcast start
(bcm 0-7)

The command prompt will turn to (bcm 0-7). To leave broadcast mode either press CTRL+D or type quit/broadcast stop, e.g.,

(bcm 0-7) broadcast stop
(mdb 0-7)

The prompt should return to (mdb 0-7) and be back to the standard font color.

Plotting variables across ranks

It may be useful for some applications to see how the value of a single variable varies across all ranks. This can be achieved with the plot command, which will display an ASCII plot (if termgraph is installed) or a Matplotlib plot if not. In simple-example.f90 we can see that variable var is set on line 15.

11   call mpi_init(ierror)
12   call mpi_comm_size(mpi_comm_world, size_of_cluster, ierror)
13   call mpi_comm_rank(mpi_comm_world, process_rank, ierror)
14
15   var = 10.*process_rank
16
17   if (process_rank == 0) then
18     print *, 'process 0 sleeping for 3s...'

We will set the following breakpoints:

(mdb 0-7) command b simple-mpi.f90:15
(mdb 0-7) command b simple-mpi.f90:17
(mdb 0-7) command continue
(mdb 0-7) command 0-2,5,7 continue

The first breakpoint b simple-mpi.f90:15 will ensure we make it past the call to mpi_init. The second breakpoint b simple-mpi.f90:17 is just the other side of where var is set. The first continue command will be sent to all ranks 0-7. This will get all ranks up to the first breakpoint. The second continue command command 0-2,5,7 continue will only move ranks 0,1,2,5 and 7 to line 17. If we issue the plot var command we should see a plot showing non-zero values for those ranks (except rank 0 which is actually set to 0.0.)

(mdb 0-7) plot var
min  =  0.0
max  =  70.0
mean =  18.75

0:  0.00
1: ▇▇▇▇▇▇▇ 10.00
2: ▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 20.00
3:  0.00
4:  0.00
5: ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 50.00
6:  0.00
7: ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 70.00

We can see that ranks 0,1,2,5 and 7 are displaying the correct values. If we now continue on ranks 3,4 and 6 we should see the full plot.

(mdb 0-7) command 3,4,6 c
(mdb 0-7) plot var
min  =  0.0
max  =  70.0
mean =  35.0

0:  0.00
1: ▇▇▇▇▇▇▇ 10.00
2: ▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 20.00
3: ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 30.00
4: ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 40.00
5: ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 50.00
6: ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 60.00
7: ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 70.00

Perfect, we can now see that all ranks are showing the expected values. For debugging large numbers of ranks e.g., n>10, it is probably best to switch to matplotlib using the mdb attach --plot-lib matplotlib command.

Exiting mdb

To quit the mdb debugger, you can either press CTRL+D or type quit.

Note

CTRL+C is forwarded directly to each gdb processes allowing the user to interrupt execution as would be expected in a serial gdb session.

Scripting the mdb Debug Session

All of the commands explained here have been placed into an example script simple-mpi-script.mdb which can be used to execute this debug session. The script is selected via the -x/--exec-script option. Feel free to use this as inspiration for scripting your own debug sessions. To run the example debug session you can use the following command,

$ mdb attach -h 127.0.1.1 -p 2000 -x simple-mpi-script.mdb --log-level=DEBUG

Scripted debugging is also allowed in gdb and this is where the true benefit of CLI tools really shines.

Multi-node debugging (HPC)

It is now possible to debug multi-node jobs using mdb. The easiest way is to first obtain an interactive session. From here you can run mdb launch. After this command has launched, you will see connection information printed to the terminal e.g.,:

running on host: 127.0.1.1
to connect to the debugger run:
mdb attach -h 127.0.1.1 -p 2000

Now run mdb attach with the correct hostname and port from the previous part from the login node. Do not worry, the target program is running in the interactive session (not on the login node).