在执行的各个阶段中,程序的实际调用栈与上面在直观模型中描述的有很大差异。机器表示模式将调用栈显示为已度量,没有进行转换,且没有构造人工函数。但是,仍显示时钟分析度量。
在下面的每个调用栈中,libmtsk 表示 OpenMP 运行时库内调用栈中的一个或多个帧。出现哪些函数以及出现顺序的详细信息随发行版的不同而不同,屏障代码的内部实现或执行归约也是如此。
在第一个并行区域之前
在进入第一个并行区域之前,只有一个线程,即主线程。调用栈与用户模式下的完全相同。
主线程 |
---|
foo |
main |
_start |
在并行区域中执行时
主线程 |
从属线程 1 |
从属线程 2 |
从属线程 3 |
---|---|---|---|
foo-OMP... | |||
libmtsk | |||
foo |
foo-OMP... |
foo-OMP... |
foo-OMP... |
main |
libmtsk |
libmtsk |
libmtsk |
_start |
_lwp_start |
_lwp_start |
_lwp_start |
在机器模式下,从属线程显示为在 _lwp_start 中启动,而不是在 _start(主线程在其中启动)中启动。(在线程库的某些版本中,该函数可能显示为 _thread_start。)
所有线程都在屏障处时
主线程 |
从属线程 1 |
从属线程 2 |
从属线程 3 |
---|---|---|---|
libmtsk | |||
foo-OMP... | |||
foo |
libmtsk |
libmtsk |
libmtsk |
main |
foo-OMP... |
foo-OMP... |
foo-OMP... |
_start |
_lwp_start |
_lwp_start |
_lwp_start |
与线程在并行区域中执行时不同,当线程在屏障处等待时,在 foo 和并行区域代码 foo-OMP... 之间没有来自 OpenMP 运行时的帧。原因是实际执行中不包括 OMP 并行区域函数,但 OpenMP 运行时处理寄存器,以便堆栈展开显示从最后执行的并行区域函数到运行时屏障代码的调用。如果没有它,在机器模式下将无法确定哪个并行区域与屏障调用相关。
离开并行区域之后
主线程 |
从属线程 1 |
从属线程 2 |
从属线程 3 |
---|---|---|---|
foo | |||
main |
libmtsk |
libmtsk |
libmtsk |
_start |
_lwp_start |
_lwp_start |
_lwp_start |
在从属线程中,没有用户帧位于调用栈上。
在嵌套并行区域中时
主线程 |
从属线程 1 |
从属线程 2 |
从属线程 3 |
从属线程 4 |
---|---|---|---|---|
bar-OMP... | ||||
foo-OMP... |
libmtsk | |||
libmtsk |
bar | |||
foo |
foo-OMP... |
foo-OMP... |
foo-OMP... |
bar-OMP... |
main |
libmtsk |
libmtsk |
libmtsk |
libmtsk |
_start |
_lwp_start |
_lwp_start |
_lwp_start |
_lwp_start |