Oracle Solaris Studio 12.2:使用 dbx 调试程序

可用于 OpenMP 代码的 dbx 功能

除了调试多线程程序这一常规功能外,dbx 还可以调试 OpenMP 程序。

单步步入并行区域

dbx 可以单步步入并行区域。因为并行区域是外联区域并从 OpenMP 运行时库中进行调用,所以单步执行实际涉及几个层次的运行时库调用(这些调用由为此目的而创建的线程执行)。单步步入并行区域时,到达断点的第一个线程引起程序停止。此线程可能是从属线程而不是启动单步执行的主线程。

例如,请参阅编译器如何转换 OpenMP 代码中的 Fortran 代码,并假定主线程 t@1 位于第 10 行。当您单步执行到第 12 行时,将创建从属线程 t@2t@3t@4 来执行运行时库调用。线程 t@3 首先到达断点并导致程序停止执行。因此,由线程 t@1 启动的单步执行在线程 t@3 上结束。此行为不同于正常的单步执行(在正常的单步执行后,通常仍处在与此前相同的线程上)。

输出变量和表达式

dbx 可以输出所有共享、专用和线程专用变量。如果尝试输出并行区域之外的线程专用变量,将输出主线程的副本。whatis 命令用于输出并行构造内共享变量和专用变量的数据共享属性。对于线程专用变量,无论这些变量是否在并行构造内,都将输出其数据共享属性。例如:


(dbx) whatis p_a
# OpenMP first and last private variable
int p_a;

print -s expression 命令用于输出当前 OpenMP 并行区域中每个线程的 expression 表达式的值(如果该表达式包含专用变量或线程专用变量)。例如:


(dbx) print -s p_a
thread t@3: p_a = 3
thread t@4: p_a = 3

如果该表达式不包含任何专用变量或线程专用变量,将仅输出一个值。

输出区域和线程信息

dbx 可以输出当前并行区域或指定并行区域的描述,其中包括父区域、并行区域 ID、组大小(线程数)以及程序位置(程序计数器地址)。例如:


(dbx) omp_pr
parallel region 127283434369843201
    team size = 4
    source location = test.c:103
    parent = 127283430568755201

它还可以输出所有并行区域的描述以及从当前并行区域或指定并行区域到其根目录的路径。例如:


(dbx) omp_pr -ancestors
parallel region 127283434369843201
    team size = 4
    source location = test.c:103
    parent = 127283430568755201

    parallel region 127283430568755201
        team size = 4
        source location = test.c:95
        parent = <no parent>

它也可以输出整个并行区域树。例如:


(dbx) omp_pr -tree
parallel region 127283430568755201
    team size = 4
    source location = test.c:95
    parent = <no parent>

    parallel region 127283434369843201
        team size = 4
        source location = test.c:103
        parent = 127283430568755201

有关更多信息,请参见omp_pr 命令

dbx 可以输出当前任务区域或指定任务区域的描述,其中包括任务区域 ID、状态(已产生、正在执行、正在等待)、正在执行的线程、程序位置(程序计数器地址)、未完成子项以及父项。例如:


(dbx) omp_tr
task region 65540
    type = implicit
    state = executing
    executing thread = t@4
    source location == test.c:46
    unfinished children = 0
    parent = <no parent>

它还可以输出所有任务区域的描述以及从当前任务区域或指定任务区域到其根目录的路径。


(dbx) omp_tr -ancestors
task region 196611
    type = implicit
    state = executing
    executing thread = t@3
    source location - test.c:103
    unfinished children = 0
    parent = 131075

    task region 131075
        type = implicit
        state = executing
        executing thread = t@3
        unfinished children = 0
        parent = <no parent>

它也可以输出整个任务区域树。例如:


(dbx) omp_tr -tree
task region 10
    type = implicit
    state = executing
    executing thread = t@10
    source location = test.c:103
    unfinished children = 0
    parent = <no parent>
task region 7
    type = implicit
    state = executing
    executing thread = t@7
    source location = test.c:103
    unfinished children = 0
    parent = <no parent>
task region 6
    type implicit
    state = executing
    executing thread = t@6
    source location = test.c:103
    unfinished children = 0
    parent = <o parent>
task region 196609
    type = implicit
    state = executing
    executing thread = t@1
    source location = test.c:95
    unfinished children = 0
    parent = <no parent>

    task region 262145
        type = implicit
        state = executing
        executing thread = t@1
        source location = test.c:103
        unfinished children - 0
        parent = 196609
 

有关更多信息,请参见omp_tr 命令

dbx 可以输出当前循环的描述,其中包括调度类型(静态、动态、指导、自动或运行时)、有序性、界限、步幅或跨距以及迭代数。例如:


(dbx) omp_loop
    ordered loop: no
    lower bound: 0
    upper bound: 3
    step: 1
    chunk: 1
    schedule type: static
    source location: test.c:49

有关更多信息,请参见omp_loop 命令

dbx 可以输出当前组或指定并行区域组上的所有线程。例如:


(dbx) omp_team
team members:
    0: t@1 state = in implicit barrier, task region = 262145
    1: t@6 state = in implicit barrier, task region = 6
    2: t@7 state = working, task region = 7
    3: t@10 state = in implicit barrier, task region = 10

有关更多信息,请参见omp_team 命令

调试 OpenMP 代码时,除有关当前或指定线程的常规信息外,thread -info 还将输出 OpenMP 线程 ID、并行区域 ID、任务区域 ID 及 OpenMP 线程状态。有关更多信息,请参见thread 命令

将并行区域的执行序列化

dbx 命令可以将当前线程或当前组中的所有线程遇到的下一个并行区域的执行序列化。有关更多信息,请参见omp_serialize 命令

使用栈跟踪

当执行在并行区域中停止时,where 命令会显示包含外联子例程的栈跟踪。


(dbx) where
current thread: t@4
=>[1] _$d1E48.main(), line 52 in "test.c"
  [2] _$p1I46.main(), line 48 in "test.c"

--- frames from parent thread ---
current thread: t@1
  [7] main(argc = 1, argv = 0xffffffff7fffec98), line 46 in "test.c"

栈的顶帧是外联函数帧。尽管代码是外联的,源代码行号仍映射回 15。

当执行在并行区域中停止时,如果相关帧仍处于活动状态,来自从属线程的 where 命令将输出主线程的栈跟踪。来自主线程的 where 命令具有完全的回溯。

也可以首先使用 omp_team 命令列出当前组中的所有线程,然后切换到主线程(OpenMP 线程 ID 为 0 的线程)并从该线程获得栈跟踪,以此来确定执行到达从属线程中断点的方式。

使用 dump 命令

当执行在并行区域中停止时,dump 命令可以输出专用变量的多个副本。在下例中,dump 命令输出变量 i 的两个副本:


[t@1 l@1]: dump
i = 1
sum = 0.0
a = ARRAY
i = 1000001

因为外联例程作为宿主例程的嵌套函数实现,而专用变量作为外联例程的局部变量实现,所以会输出变量 i 的两个副本。由于 dump 命令输出作用域内的所有变量,因此宿主例程中的 i 和外联例程中的 i 均会显示。

使用事件

dbx 提供了可以与 stopwhentrace 命令结合用于 OpenMP 代码的事件。有关将事件与这些命令结合使用的信息,请参见设置事件规范

同步事件

omp_barrier [type] [state]

跟踪线程进入屏障事件。

type 可以是以下值:

  • explicit,表示跟踪显式屏障

  • implicit,表示跟踪隐式屏障

如果不指定 type,则只跟踪显式屏障。

state 可以是以下值:

  • enter,表示在有线程进入屏障时报告该事件

  • exit,表示在有线程退出屏障时报告该事件

  • all_entered,表示在所有线程都进入屏障时报告该事件

如果不指定 state,缺省值为 all_entered

如果指定 enterexit,可以设置线程 ID 以指定仅跟踪该线程。

omp_taskwait [state]

跟踪线程进入任务等待事件。

state 可以是以下值:

  • enter,表示在线程进入任务等待时报告该事件

  • exit,表示在所有子任务都已完成时报告该事件

如果不指定 state,缺省值为 exit

omp_ordered [state]

跟踪线程进入有序区域事件。

state 可以是以下值:

  • begin,表示在有序区域开始时报告该事件

  • enter,表示在线程进入有序区域时报告该事件

  • exit,表示在线程退出有序区域时报告该事件

如果不指定 state,则缺省值为 enter

omp_critical

跟踪线程进入关键区域事件。

omp_atomic [state]

跟踪线程进入原子区域事件。

state 可以是以下值:

  • begin,表示在原子区域开始时报告该事件

  • exit,表示在线程退出原子区域时报告该事件

如果不指定 state,缺省值为 begin

omp_flush

跟踪线程执行刷新事件。

其他事件

omp_task [state]

跟踪任务的创建与终止。

state 可以是以下值:

  • create,表示在任务刚刚创建完毕且尚未开始执行时报告该事件

  • start,表示在任务开始执行时报告该事件

  • finish,表示在任务执行完毕即将终止时报告该事件

如果不指定 state,缺省值为 start

omp_master

跟踪主线程进入主区域事件。

omp_single

跟踪线程进入单个区域事件。