使用 GDB 调试 OpenMP

5

使用GDB,我似乎无法打印OpenMP线程中共享变量的值。例如,使用以下程序:

#include <omp.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
  int priv, tid, pub = 100;
  #pragma omp parallel private(priv, tid) num_threads(2)
  {
    tid = omp_get_thread_num();
    priv = tid * 10; 
    #pragma omp sections
    {
      #pragma omp section
      {
        printf("SECTION 0: tid=%d, priv=%d, pub=%d\n", tid, priv, pub);
      }
      #pragma omp section
      {
        printf("SECTION 1: tid=%d, priv=%d, pub=%d\n", tid, priv, pub);
      }

    }
  }
  return EXIT_SUCCESS;
}

在GDB中,如果我在第15行(section 0的printf语句)断点,并尝试打印“pub”的值,我会收到“当前上下文中没有符号'pub'” 的错误信息。
Breakpoint 1, main._omp_fn.0 () at omp_simplesec.c:15
15          printf("SECTION 0: tid=%d, priv=%d, pub=%d\n", tid, priv, pub);
(gdb) print pub
No symbol "pub" in current context.

我正在使用GCC编译,并尝试了不同的调试标志 (-g3 -ggdb3 -gstabs3 -gstabs+3),但没有成功。我也尝试使用 -O0 禁用所有优化,但仍然没有成功。然而,我可以通过使用 -gstabs+ 标志来查看私有变量的值。

先行感谢。


你使用的gdb/gcc版本是什么?我可以在我的机器上使用gdb 7.2和gcc 4.4.7打印“pub”,只需使用-g3 -fopenmp标志进行编译。 - Robert Prior
@RobertPrior,我正在使用gcc 4.6.3 + gdb 7.4(这些是Ubuntu 12.04LTS存储库中的版本)。我还没有尝试在不同的gcc / gdb版本中编译/调试此代码,让我检查一下... - faken
使用gcc 4.7.3 + gdb 7.5(在Ubuntu 13.04存储库中)时,我遇到了相同的问题。 - faken
2个回答

17

在GCC中实现OpenMP使用的是大纲。这意味着每个并行区域的代码都会被提取到自己的函数中。例如:

int main(int argc, char *argv[]) {
  int priv, pub = 100;
  #pragma omp parallel private(priv) num_threads(2)
  {
    printf("priv = %d, pub = %d\n", priv, pub);
  }
  return EXIT_SUCCESS;
}

被转换为:

strict .omp_data_s {
  int pub;
};

void main._omp_fn.0(struct .omp_data_s* .omp_data_i) {
  int priv;
  printf("priv = %d, pub = %d\n", priv, .omp_data_i->pub);      
}

int main(int argc, char *argv[]) {
  int priv, pub = 100;
  struct .omp_data_s .omp_data_o;

  .omp_data_o.pub = pub;     // (1)

  __builtin_GOMP_parallel_start (main._omp_fn.0, &.omp_data_o, 2);
  main._omp_fn.0 (&.omp_data_o);
  __builtin_GOMP_parallel_end ();

  pub = .omp_data_o.pub;     // (2)
  return EXIT_SUCCESS;
}

main._omp_fn.0是一个轮廓化的并行区域。struct .omp_data_s是一个结构体,它保存了在相应的并行区域中引用了所有基本(非数组)共享变量的副本。在这个例子中,唯一这样的变量是pub,因此struct .omp_data_s只有一个成员pub。每个共享变量的值在并行区域开始之前被复制到这个数据结构中(1),然后在并行区域结束后从数据结构中复制回来(2)。

问题在于较新版本的GCC不为struct .omp_data_s生成调试信息,因此GDB无法解码main._omp_fn.0函数的参数。这与生成的调试信息格式无关,我也找不到任何启用它的选项。我猜这只是GDB不能解码较新GCC生成的调试信息,因为它与英特尔的调试器(idb)非常配合,即它在info locals中显示了pubpriv两个变量。


1
当我运行你的代码时,我得到了类似的结果。如果你查看回溯信息,它会告诉你,你处于一个与GCC如何实现OpenMP相关的OpenMP环境中。
(gdb) backtrace 
#0  main._omp_fn.0 () at tmp.c:15
#1  0x000000000040082e in main (argc=1, argv=0x7fffffffe6c8) at tmp.c:7

您可以通过以下方式获取pub的值:

(gdb) up
(gdb) print pub
$1 = 100

但是这仅获得并行区域之前的pub值。您应该查看Hristo Iliev的答案,以获取更详细和更好的描述。


没问题。我建议你查阅一些关于调试的教材或教程,因为在堆栈中上下移动确实是基本操作之一。对于你的程序,只有一个层级是由你编写的,但通常情况下,你会深入到自己编写的函数中,并且相同的机制也让你能够检查不同层次的情况。 - Daniel Landau
1
这个答案是误导性的。你正在打印main函数中局部变量pub的值。这不是在并行区域内使用的共享变量的值,因为GCC将共享OpenMP变量实现为结构体的成员,并将其传递给轮廓化的区域。在printf语句之前插入pub = 110;以验证这一点。 - Hristo Iliev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接