并行调试器 PDB(Parallel debugger) 简介
长期以来,高性能并行环境下的程序调试一直是一个热门话题。PDB 是 IBM 发布的一种强大的并行环境下的命令行调试工具。它能够在并行程序运行时观察程序的所有 tasks 的内部结构和内存的使用情况,方便用户对并行程序进行调试。与串行调试器相比,PDB V5.3 增加了以下功能(本文中均以 PDB V5.3 为例,进行介绍):
- 支持单步调试并行程序的每一个 task
- 支持同时对并行程序的多个 task 进行调试
- 提供了一个控制中心,用来对并行程序的所有 tasks 进行集中管理
- 支持同时对多达 1024k 的任务进行调试
- 提供了一种机制,可以让用户自定义消息过滤准则。
- 支持对数据进行分类显示
PDB 的架构(如图 1)的核心部分,是具有多层的树形结构的 SCI(Scalable Communication Infrastructure)—它可以启动及管理并行程序的所有分布式的 tasks,所有的通信及任务管理都由 SCI 完成。PDB 底层调用的是串行调试器 GDB,即 GNU Project Debugger(在 Linux 系统上),及 DBX(在 AIX 系统上)。使用 PDB 进行调试,类似于同时启动多个 GDB(DBX),对并行程序的多个任务同时进行调试。关于 PDB 的基本信息请参见“参考资源”中的 IBM Publication: 《 Parallel Environment for AIX and Linux V5.2.1 》的“Using the PDB debugger”章节。
图 1. PDB 的架构
PDB 的两种启动方式:Launch 模式和 Attach 模式
使用 PDB 进行调试,必须使并行程序在编译时包含调试信息,即在编译时用“-g”选项打开调试选项。调试信息包含程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号。PDB 利用这些信息使源代码和机器码相关联。
下面是本文中要用 PDB 调试的并行程序。此程序调用 MPI(Message Passing Interface,消息传递接口)函数初始化并行环境,查询应用中进程的总数等,进行点对点通信,传输消息,以及结束该并行环境。
清单 1. 并行程序“mpihello.c”文件的代码:
#include "mpi.h"
void main(int argc, char **argv)
{
int numprocs,myrank,i,namelen;
MPI_Status status;
char msg[128];
char processor_name[MPI_MAX_PROCESSOR_NAME];
/* 调用 MPI_Init 函数,初始化并行环境 */
MPI_Init(&argc,&argv);
/* 调用 MPI_Comm_size 函数,查询进程总数 */
MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
/* 调用 MPI_Comm_rank 函数,查询当前进程的标识号 */
MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
/* 调用 MPI_Get_processor_name 函数,查询当前进程运行的机器的名称 */
MPI_Get_processor_name(processor_name,&namelen);
/* 每一个进程都向进程 0 发送消息 */
strcpy(msg,"hello world!");
sprintf(msg,"hello world from %s",processor_name);
MPI_Send(msg,strlen(msg) + 1,MPI_CHAR,0,99,MPI_COMM_WORLD);
/* 进程 0 从所有进程接收消息,并将其打印 */
if(myrank ==0) {
for (i=0;i<numprocs;i++) {
MPI_Recv(msg,strlen(msg)+1,MPI_CHAR,i,99,MPI_COMM_WORLD,&status);
printf("Message from %d of %d: %s\n",i,numprocs,msg);
}
}
/* 调用 MPI_Finalize 函数,结束并行环境 */
MPI_Finalize();
}
|
利用 IBM 并行编译器 mpcc 编译该并行程序(在编译时用“-g”选项打开调试选项):
$ mpcc -g -o mpihello mpihello.c |
利用 IBM 并行环境运行该并行程序的结果为(其中:参数“-procs 2”指定了该并行程序以两个任务运行):
$ poe ./mpihello -procs 2 Message from 0 of 2: hello world from node1 Message from 1 of 2: hello world from node2 |
下面将介绍使用 PDB 的两种启动方式对该并行程序进行调试。
根据一个调试会话是如何启动的,PDB 分为两种启动方式:“Launch”模式和“Attach”模式。
“Launch”模式 :
“Launch”模式,即使用 PDB 启动一个新的调试进程。在 Launch mode 下,PDB 必须启动在该并行程序希望被执行(即 poe 希望被执行)的主机上。其启动方式如下:
清单 2. “Launch”模式启动方式:
pdb executable_and_arguments
[--poe poe_options]
[--gdb gdb_options] (Linux only) or [--dbx dbx_options] (AIX only)
FLAGS
executable_and_arguments
Specifies to launch the target executable and start debugging from
the beginning of the program. The arguments are to the executable,
not to PDB.
--gdb gdb_options
Specifies the options to pass to GDB. Applies to Linux only.
--dbx dbx_options
Specifies the options to pass to dbx. Applies to AIX only.
--poe poe_options
Specifies the options to pass to POE.
|
例如以“Launch”模式启动 PDB,调试一个并行程序“mpihello”,如下所示(其中:参数“-procs 2”指定了该并行程序以两个任务运行,参数“-hostfile”指定了将要执行该并行程序的主机列表):
$ pdb ./mpihello --poe -procs 2 -hostfile ./host.list |
“Attach”模式:
“Attach”模式,即使用 PDB 挂接一个正在运行的进程。在“Attach”模式下,PDB 必须启动在该并行程序已经被执行(即 poe 已经被启动)的主机上。其启动方式如下:
清单 3. “Attach”模式启动方式:
pdb -a [poe_process_id] [--gdb gdb_options] (Linux only) or [--dbx dbx_options] (AIX only) FLAGS executable_and_arguments Specifies to launch the target executable and start debugging from the beginning of the program. The arguments are to the executable, not to PDB. -a [poe_process_id] Specifies to attach to a running POE job. pdb -a must be issued from the node on which the POE job was initiated. If the POE process ID is not specified, PDB tries to find one and reports an error if multiple POE processes exist. --gdb gdb_options Specifies the options to pass to GDB. Applies to Linux only. --dbx dbx_options Specifies the options to pass to dbx. Applies to AIX only. |
例如以“Attach”模式启动 PDB,挂接一个已经被执行的并行程序“mpihello”(进程号为 [poe_pid])进行调试,如下所示:
$ pdb – a [poe_id] |
PDB 启动以后,可以利用 DBX/GDB 命令,以及 PDB 内部命令对并行程序进行调试。
控制中心
PDB 成功启动后,提供了一个控制中心 console,用来对被启动的并行程序的所有 tasks 进行集中管理。除了该控制中心外,PDB 还可以通过以下方式挂接新的控制中心到该调试会话上,对任务进行管理,即:
pdb -c [session_number] |
PDB 通过控制中心可以利用 DBX/GDB 命令,以及 PDB 内部命令对并行程序的任务进行调试。
PDB 启动以后,可以使用 DBX(在 AIX 系统上)/GDB(在 Linux 系统上)命令对并行程序进行调试。下面通过在 IBM-Power 550, AIX61(AIX 系统)/ SLES11(Linux 系统)平台上的简单实例演示如何在 PDB 中进行设置断点,运行程序,以及打印变量等操作。
清单 4. 在 AIX 系统上,使用 DBX 进行调试:
(IBM-Power 550, AIX61(AIX 系统 )) $ pdb ./mpihello --poe -procs 2 -hostfile ./host.list PDB -- Parallel Debugger for IBM Parallel Environment on AIX Current PDB debug session number is 655534. Be aware, only one console will connect to this session after startup, type 'pdb -c 655534' to connect more consoles to this session. At the prompt, enter any DBX command. Enter 'help' for more usage. (all) stop in main ( 设置断点在源程序的 main 函数 ) 0:1 | [1] stop in main (all) run ( 运行程序 ) 0:1 | [1] stopped in main at line 10 in file "mpihello.c" ($t1) 0:1 | 10 MPI_Init(&argc,&argv); (all) list ( 显示源代码 ) 0:1 | 11 MPI_Comm_size(MPI_COMM_WORLD,&numprocs); 0:1 | 12 MPI_Comm_rank(MPI_COMM_WORLD,&myrank); 0:1 | 13 MPI_Get_processor_name(processor_name,&namelen); 0:1 | 14 0:1 | 15 /* every process send msg to process 0 */ 0:1 | 16 strcpy(msg,"hello world!"); 0:1 | 17 sprintf(msg,"hello world from %s",processor_name); 0:1 | 18 0:1 | 19 MPI_Send(msg,strlen(msg) + 1,MPI_CHAR,0,99,MPI_COMM_WORLD); 0:1 | 20 (all) stop at 13 ( 设置断点在源程序的第 13 行 ) 0:1 | [6] stop at "mpihello.c":13 (all) cont ( 继续运行程序 ) 0:1 | [6] stopped in main at line 13 in file "mpihello.c" ($t1) 0:1 | 13 MPI_Get_processor_name(processor_name,&namelen); (all) print numprocs ( 打印变量 numprocs 的值 ) 0:1 | 2 (all) print myrank ( 打印变量 myrank 的值 ) 0 | 0 1 | 1 |
在上例中,PDB 使用 DBX 命令设置了两个断点,运行了该并行程序,并打印了变量“numprocs”,及“myrank”的值。
清单 5. 在 Linux 系统上,使用 GDB 进行调试:
(IBM-Power 550, SLES11(Linux 系统 )) $ pdb ./mpihello --poe -procs 2 -hostfile ./host.list PDB -- Parallel Debugger for IBM Parallel Environment on Linux Current PDB debug session number is 2405. Be aware, only one console will connect to this session after startup, type 'pdb -c 2405' to connect more consoles to this session. At the prompt, enter any GDB command. Enter 'help' for more usage. (all) break main ( 设置断点在源程序的 main 函数 ) 0:1 | Breakpoint 1 at 0x100008a8: file mpihello.c, line 10. (all) run ( 运行程序 ) 0:1 | Starting program: /u/ronglli/tests_linux/mpihello 0:1 | [Thread debugging using libthread_db enabled] 0 | [New Thread 0x4045f4b0 (LWP 2455)] 1 | [New Thread 0x4045f4b0 (LWP 2457)] 0 | [New Thread 0x4085f4b0 (LWP 2456)] 1 | [New Thread 0x4085f4b0 (LWP 2458)] 0:1 | 0:1 | Breakpoint 1, main (argc=1, argv=0xfffeef94) at mpihello.c:10 0:1 | 10 MPI_Init(&argc,&argv); (all) list ( 显示源代码 ) 0:1 | 5 int numprocs,myrank,i,namelen; 0:1 | 6 MPI_Status status; 0:1 | 7 char msg[128]; 0:1 | 8 char processor_name[MPI_MAX_PROCESSOR_NAME]; 0:1 | 9 0:1 | 10 MPI_Init(&argc,&argv); 0:1 | 11 MPI_Comm_size(MPI_COMM_WORLD,&numprocs); 0:1 | 12 MPI_Comm_rank(MPI_COMM_WORLD,&myrank); 0:1 | 13 MPI_Get_processor_name(processor_name,&namelen); 0:1 | 14 (all) break 13 ( 设置断点在源程序的第 13 行 ) 0:1 | Breakpoint 2 at 0x100008cc: file mpihello.c, line 13. (all) cont ( 继续运行程序 ) 0:1 | Continuing. 0 | [New Thread 0x476ff4b0 (LWP 2557)] 1 | [New Thread 0x476ff4b0 (LWP 2558)] 0 | [New Thread 0x4843f4b0 (LWP 2559)] 1 | [New Thread 0x4843f4b0 (LWP 2560)] 0 | [New Thread 0x48a4f4b0 (LWP 2562)] 1 | [New Thread 0x48a4f4b0 (LWP 2561)] 0 | [New Thread 0x4906f4b0 (LWP 2563)] 1 | [New Thread 0x4906f4b0 (LWP 2564)] 1 | 0:1 | Breakpoint 2, main (argc=1, argv=0xfffeef94) at mpihello.c:13 0:1 | 13 MPI_Get_processor_name(processor_name,&namelen); (all) print numprocs ( 打印变量 numprocs 的值 ) 0:1 | $1 = 2 (all) print myrank ( 打印变量 myrank 的值 ) 1 | $2 = 1 0 | $2 = 0 |
在上例中,PDB 使用 GDB 命令设置了两个断点,运行了该并行程序,并打印了变量“numprocs”,及“myrank”的值。
PDB 提供了内部命令便于对并行程序进行调试,例如“组操作”,“用户自定义消息过滤准则”,“消息聚合”,以及退出等。
PDB 支持对其并行程序的所有任务进行组操作,即提供“group”命令,显示组成员,创建一个包含一部分或全部任务的新组,删除组,对组进行赋值,加减操作等;并提供了“on”命令,来切换组名,选择已定义的组为当前组。在 PDB 一个调试会话启动后,PDB 就创建了预定义组“all”(包括了所有的任务);“FILTERED”(包括所以针对上一条命令有消息输出的任务);以及“0”,“1”…“<num clinets -1>”(仅包括一个任务)。“group”及“on”命令提供的操作如下所示:
清单 6. “group”命令提供的操作:
(all) help group
Group clients
group -- show all groups.
group <name> -- show the group of <name>.
group <name> = <clients> -- set group <name> to have <clients>.
group <name> + <clients> -- add <clients> into group <name>.
group <name> - <clients> -- delete <clients> from group <name>.
<name>: the name of a group.
<clients>: list of clients separated by space. <client>:<client>
can be used for a range of clients. Group names can be
used in the list too.
Predefined groups are:
0, 1, 2, ..., <num clients - 1> representing individual clients,
'all' containing all clients, and
Examples:
group a = 0:2 4 -- Group a has clients 0,1,2,4
group b = 3 a -- Group b has clients 0,1,2,3,4
group a + b 5:7 -- Group a has clients 0,1,2,3,4,5,6,7
|
清单 7. “on”命令提供的操作:
(all) help on
Switch client group
on <group> -- Set current group to be <group>.
Client commands are broadcast to all members in
current group.
|
下面通过 IBM-Power 550, AIX61(AIX 系统)/ SLES11(Linux 系统)平台上的简单实例演示如何在 PDB 中进行组操作,例如创建新组,删除组,切换组等。
清单 8. 使用“group”及“on”命令进行组操作:
(IBM-Power 550, AIX61(AIX 系统 )/ SLES11(Linux 系统 ))
(all) group ( 使用 group 命令显示组名 )
FILTERED: 0 1 2 3 4 5 6 7
all: 0 1 2 3 4 5 6 7
(all) group g1 = 0 1:4 ( 创建新组 )
(all) group g2 = 4 5
(all) group
FILTERED: 0 1 2 3 4 5 6 7
all: 0 1 2 3 4 5 6 7
g1: 0 1 2 3 4
g2: 4 5
(all) group g1 - g2
(all) group
FILTERED: 0 1 2 3 4 5 6 7
all: 0 1 2 3 4 5 6 7
g1: 0 1 2 3
g2: 4 5
(all) group g2 + g1 7
(all) group
FILTERED: 0 1 2 3 4 5 6 7
all: 0 1 2 3 4 5 6 7
g1: 0 1 2 3
g2: 0 1 2 3 4 5 7
(all) list
0:7 | 1 #include "mpi.h"
0:7 | 2
0:7 | 3 main(int argc, char **argv)
0:7 | 4 {
0:7 | 5 int numprocs,myrank,i,namelen;
0:7 | 6 MPI_Status status;
0:7 | 7 char msg[128];
0:7 | 8 char processor_name[MPI_MAX_PROCESSOR_NAME];
0:7 | 9
0:7 | 10 MPI_Init(&argc,&argv);
(all) on g1 ( 使用 on 命令切换当前组 )
(g1) list
0:3 | 11 MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
0:3 | 12 MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
0:3 | 13 MPI_Get_processor_name(processor_name,&namelen);
0:3 | 14
0:3 | 15 /* every process send msg to process 0 */
0:3 | 16 strcpy(msg,"hello world!");
0:3 | 17 sprintf(msg,"hello world from %s",processor_name);
0:3 | 18
0:3 | 19 MPI_Send(msg,strlen(msg) + 1,MPI_CHAR,0,99,MPI_COMM_WORLD);
0:3 | 20
|
PDB 提供了用户自定义消息过滤准则,即提供“match”命令,对消息进行过滤。
清单 9. “match”命令提供的操作:
(all) help match
Filter client command outputs with regular expression
match -- show last client command outputs.
match <regexp> -- filter the last client command output with <regexp>.
match <regexp> | match <regexp> | ... -- cascade style.
Note: If you want to filter <command> output with <regexp>,
you can use the system command.
<command> | grep <regexp> -- filter <command> output with <regexp>.
<command> | grep <regexp> | grep <regexp> | ... -- cascade style.
<regexp>: regular expression surrounded by single(double) quotation marks
<command>: client command.
Examples:
match 'Hello' -- Show lines that contain 'Hello' in last command
outputs
match 'Hello' | match 'World' -- Show lines that contain 'Hello'
and 'World' in last command outputs
match 'Hello|World' -- Show lines that contain 'Hello' or 'World'
in last command outputs
list | grep 'Hello' -- Show lines that contain 'Hello' in current
command outputs
list | grep 'Hello' | grep 'World' -- Show lines that contain
'Hello' and 'World' in current command outputs
list | grep -E "Hello|World" -- Show lines that contain 'Hello' or
'World' in current command outputs
This is available only in normal state.
|
下面通过 IBM-Power 550, AIX61(AIX 系统)/ SLES11(Linux 系统)平台上的简单实例演示如何在 PDB 中使用“match”命令,对消息进行过滤。
清单 10. 使用“match”命令对消息进行过滤:
(IBM-Power 550, AIX61(AIX 系统 )/ SLES11(Linux 系统 ))
(all) list
0:7 | 1 #include "mpi.h"
0:7 | 2
0:7 | 3 main(int argc, char **argv)
0:7 | 4 {
0:7 | 5 int numprocs,myrank,i,namelen;
0:7 | 6 MPI_Status status;
0:7 | 7 char msg[128];
0:7 | 8 char processor_name[MPI_MAX_PROCESSOR_NAME];
0:7 | 9
0:7 | 10 MPI_Init(&argc,&argv);
(all) match msg ( 使用 match 命令过滤与 msg 字符串匹配的消息 )
0:7 | 7 char msg[128];
(all) list | grep MPI |grep Comm
0:7 | 11 MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
0:7 | 12 MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
|
在 PDB 中,不同任务中的相同的消息会被聚合,从而大幅度地增加了 PDB 的输出消息的可读性,减少了消息的冗余度。如下例:
0 | this is a test 1 | this is a test … 99 | this is a test |
以上输出消息,会被聚合成一条消息:
[0:99] | this is a test |
综上所述,PDB 提供了多种内部命令,使得同时对多个任务进行管理变得更加简单、方便;其输出消息通过“用户自定义消息过滤”、“消息聚合”等方法,增加了 PDB 的可用性
本文主要介绍了 IBM 发布的一种并行环境下的命令行调试工具 PDB,并详细讲解了 PDB V5.3 的特点及使用方法。通过 PDB,技术人员可以在 AIX/Linux 系统上,更加方便、高效地完成对并行程序的调试。
学习
-
IBM Publication: 《 Parallel Environment for AIX and Linux V5.2.1 》:IBM 并行环境文档,在这里您可以找到和 PDB 及其他 IBM 并行环境相关的技术资料和规范说明。
-
dbx Symbolic Debug Program Overview:获取关于 dbx 调试的一般信息。
-
GDB:在 LinuxCommand Web 站点查看 GDB man 页面。
- AIX and UNIX 专区:developerWorks 的“AIX and UNIX 专区”提供了大量与 AIX 系统管理的所有方面相关的信息,您可以利用它们来扩展自己的 UNIX 技能。
- AIX and UNIX 新手入门:访问“AIX and UNIX 新手入门”页面可了解更多关于 AIX 和 UNIX 的内容。
- AIX and UNIX 专题汇总:AIX and UNIX 专区已经为您推出了很多的技术专题,为您总结了很多热门的知识点。我们在后面还会继续推出很多相关的热门专题给您,为了方便您的访问,我们在这里为您把本专区的所有专题进行汇总,让您更方便的找到您需要的内容。
-
AIX and UNIX 下载中心:在这里你可以下载到可以运行在 AIX 或者是 UNIX 系统上的 IBM 服务器软件以及工具,让您可以提前免费试用他们的强大功能。
- IBM Systems Magazine for AIX 中文版:本杂志的内容更加关注于趋势和企业级架构应用方面的内容,同时对于新兴的技术、产品、应用方式等也有很深入的探讨。IBM Systems Magazine 的内容都是由十分资深的业内人士撰写的,包括 IBM 的合作伙伴、IBM 的主机工程师以及高级管理人员。所以,从这些内容中,您可以了解到更高层次的应用理念,让您在选择和应用 IBM 系统时有一个更好的认识。
讨论
- 加入 developerWorks 中文社区。查看开发人员推动的博客、论坛、组和维基,并与其他 developerWorks 用户交流。