htop 和 OpenMP 线程
htop and OpenMP threads
在我的主要功能中我设置:
omp_set_num_threads(20);
告诉 OpenMP 使用 20 个线程(有 40 个线程可用)。
然后我执行包含指令的代码:
#pragma omp parallel for shared(x,y,z)
for 主 for 循环,并通过 htop 监控 CPU 使用情况(也许不是最好的方法,但仍然如此)。 for 循环必须执行 50 "tasks" 次,每次都需要相当长的时间。我通过 htop 观察到的是,任务完成后,线程数下降。具体来说,使用 20 个线程,我预计 ed 会看到 2000% cpu 的使用率,直到剩余的任务少于 20 个,之后线程应该 "free" 自己。但是,我首先看到的是 2000%,在完成 n 个任务后,我看到了 2000% - (n*100%) 的性能。因此,似乎随着任务完成,线程关闭而不是接收新任务。
这是意料之中的事还是听起来很奇怪?
几乎所有现有 OpenMP 编译器的默认并行循环调度是 static
,这意味着 OpenMP 运行时将尝试在线程之间平均拆分迭代 space 并执行静态工作分配.由于您有 50 次迭代和 20 个线程,工作不能平均分配,因为 20 不能除以 50。因此,一半线程将执行 3 次迭代,而另一半线程将执行 2 次迭代。
在(组合 parallel
)for
构造的末尾有一个隐式屏障,其中较早完成的线程等待其余线程完成。根据 OpenMP 的实现,障碍可能被实现为繁忙的等待循环,作为对某个 OS 同步对象的等待操作,或者作为两者的组合。在后两种情况下,遇到障碍的线程的 CPU 使用率将在进入可中断睡眠时立即降至零,或者最初会在短时间内保持在 100%(繁忙循环),然后降为零(等待)。
如果循环迭代花费的时间完全相同,那么 CPU 最初的使用率为 2000%,然后在两次迭代后(如果屏障实现使用一个短暂的繁忙循环)将下降到 1000%。如果每次迭代花费不同的时间量,那么线程将在不同时刻到达屏障,CPU 使用量将逐渐减少。
在任何情况下,使用 schedule(dynamic)
将每个迭代分配给第一个线程以使其可用。这将在迭代花费不同时间量的情况下提高 CPU 利用率。当迭代每次花费相同的时间时,这将无济于事。后一种情况的解决方案是将迭代次数作为线程数的整数倍。
在我的主要功能中我设置:
omp_set_num_threads(20);
告诉 OpenMP 使用 20 个线程(有 40 个线程可用)。
然后我执行包含指令的代码:
#pragma omp parallel for shared(x,y,z)
for 主 for 循环,并通过 htop 监控 CPU 使用情况(也许不是最好的方法,但仍然如此)。 for 循环必须执行 50 "tasks" 次,每次都需要相当长的时间。我通过 htop 观察到的是,任务完成后,线程数下降。具体来说,使用 20 个线程,我预计 ed 会看到 2000% cpu 的使用率,直到剩余的任务少于 20 个,之后线程应该 "free" 自己。但是,我首先看到的是 2000%,在完成 n 个任务后,我看到了 2000% - (n*100%) 的性能。因此,似乎随着任务完成,线程关闭而不是接收新任务。
这是意料之中的事还是听起来很奇怪?
几乎所有现有 OpenMP 编译器的默认并行循环调度是 static
,这意味着 OpenMP 运行时将尝试在线程之间平均拆分迭代 space 并执行静态工作分配.由于您有 50 次迭代和 20 个线程,工作不能平均分配,因为 20 不能除以 50。因此,一半线程将执行 3 次迭代,而另一半线程将执行 2 次迭代。
在(组合 parallel
)for
构造的末尾有一个隐式屏障,其中较早完成的线程等待其余线程完成。根据 OpenMP 的实现,障碍可能被实现为繁忙的等待循环,作为对某个 OS 同步对象的等待操作,或者作为两者的组合。在后两种情况下,遇到障碍的线程的 CPU 使用率将在进入可中断睡眠时立即降至零,或者最初会在短时间内保持在 100%(繁忙循环),然后降为零(等待)。
如果循环迭代花费的时间完全相同,那么 CPU 最初的使用率为 2000%,然后在两次迭代后(如果屏障实现使用一个短暂的繁忙循环)将下降到 1000%。如果每次迭代花费不同的时间量,那么线程将在不同时刻到达屏障,CPU 使用量将逐渐减少。
在任何情况下,使用 schedule(dynamic)
将每个迭代分配给第一个线程以使其可用。这将在迭代花费不同时间量的情况下提高 CPU 利用率。当迭代每次花费相同的时间时,这将无济于事。后一种情况的解决方案是将迭代次数作为线程数的整数倍。