gpt4 book ai didi

c - 使用多线程时低于预期的加速

转载 作者:太空狗 更新时间:2023-10-29 15:34:50 26 4
gpt4 key购买 nike

备注:我觉得这有点傻,但这可能对某人有帮助

因此,我试图通过使用并行性来提高程序的性能。但是,我遇到了测量加速的问题。我有 4 个 CPU:

~% lscpu
...
CPU(s): 4
...

但是,加速比四倍低得多。这是一个最小的工作示例,有一个顺序版本,一个使用 OpenMP 的版本和一个使用 POSIX 线程的版本(确保它不是由于任何一个实现)。

纯顺序(add_seq.c):

#include <stddef.h>

int main() {
for (size_t i = 0; i < (1ull<<36); i += 1) {
__asm__("add $0x42, %%eax" : : : "eax");
}
return 0;
}

OpenMP(add_omp.c):

#include <stddef.h>

int main() {
#pragma omp parallel for schedule(static)
for (size_t i = 0; i < (1ull<<36); i += 1) {
__asm__("add $0x42, %%eax" : : : "eax");
}
return 0;
}

POSIX 线程(add_pthread.c):

#include <pthread.h>
#include <stddef.h>

void* f(void* x) {
(void) x;
const size_t count = (1ull<<36) / 4;
for (size_t i = 0; i < count; i += 1) {
__asm__("add $0x42, %%eax" : : : "eax");
}
return NULL;
}
int main() {
pthread_t t[4];
for (size_t i = 0; i < 4; i += 1) {
pthread_create(&t[i], NULL, f, NULL);
}
for (size_t i = 0; i < 4; i += 1) {
pthread_join(t[i], NULL);
}
return 0;
}

生成文件:

CFLAGS := -O3 -fopenmp
LDFLAGS := -O3 -lpthread # just to be sure

all: add_seq add_omp add_pthread

现在,运行它(使用 zsh 的内置时间):

% make -B && time ./add_seq && time ./add_omp && time ./add_pthread
cc -O3 -fopenmp -O3 -lpthread add_seq.c -o add_seq
cc -O3 -fopenmp -O3 -lpthread add_omp.c -o add_omp
cc -O3 -fopenmp -O3 -lpthread add_pthread.c -o add_pthread
./add_seq 24.49s user 0.00s system 99% cpu 24.494 total
./add_omp 52.97s user 0.00s system 398% cpu 13.279 total
./add_pthread 52.92s user 0.00s system 398% cpu 13.266 total

检查 CPU 频率,顺序代码的最大 CPU 频率为 2.90 GHz,并行代码(所有版本)的 CPU 频率统一为 2.60 GHz。所以计算数十亿条指令:

>>> 24.494 * 2.9
71.0326
>>> 13.279 * 2.6
34.5254
>>> 13.266 * 2.6
34.4916

因此,总而言之,线程代码的运行速度仅为顺序代码的两倍,尽管它使用的 CPU 时间是顺序代码的四倍。为什么会这样?

备注:asm_omp.c 的程序集似乎效率较低,因为它通过递增寄存器并比较它来执行 for 循环迭代次数,而不是递减和直接检查 ZF;然而,这对性能没有影响

最佳答案

嗯,答案很简单:实际上只有两个 CPU 内核:

% lscpu
...
Thread(s) per core: 2
Core(s) per socket: 2
Socket(s): 1
...

因此,虽然 htop 显示了四个 CPU,但其中两个是虚拟的,而且只有因为 hyperthreading 而存在。 .由于超线程的核心思想是在两个进程中共享单个内核的资源,因此它确实有助于更快地运行相似的代码(它仅在运行使用不同资源的两个线程时才有用)。

所以,最后,发生的是时间/clock()将每个逻辑核心的使用情况作为底层物理核心的使用情况进行衡量。由于所有报告都报告了 ~100% 的使用率,我们得到了 ~400% 的使用率,尽管它只代表了两倍的加速。

在那之前,我确信这台计算机包含 4 个物理内核,而完全忘记了检查超线程。

关于c - 使用多线程时低于预期的加速,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39523432/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com