gpt4 book ai didi

performance - 在 x86_64 汇编程序 (yasm) 中使用 POSIX 线程库需要更多的执行时间

转载 作者:行者123 更新时间:2023-12-02 01:02:41 25 4
gpt4 key购买 nike

我想在 yasm 程序中使用 POSIX 线程(或简称 pthread)库实现并行处理。

代码

这是我程序中最重要的部分。

section .data
pThreadID1 dq 0
pThreadID2 dq 0
MAX: dq 100000000
value: dd 0

section .bss
extern pthread_create
extern pthread_join

section .text

global main
main:
;create the first thread with id = pThreadID1
mov rdi, pThreadID1
mov rsi, NULL
mov rdx, thread1
mov rcx, NULL
call pthread_create
;join the 1st thread
mov rdi, qword [pThreadID1]
mov rsi, NULL
call pthread_join

;create the second thread with id = pThreadID2
mov rdi, pThreadID2
mov rsi, NULL
mov rdx, thread2
mov rcx, NULL
call pthread_create
;join the 2nd thread
mov rdi, qword [pThreadID2]
mov rsi, NULL
call pthread_join
;print value block

其中 thread1 包含循环,其中 value 递增 MAX/2 次:

global thread1
thread1:
mov rcx, qword [MAX]
shr rcx, 1

thread1.loop:
mov eax, dword [value]
inc eax
mov dword [value], eax
loop thread1.loop

ret

thread2类似。注意:thread1thread2 共享 变量 value

结果

我将上面的程序汇编编译如下:

yasm -g dwarf2 -f elf64 Parallel.asm -l Parallel.lst
gcc -g Parallel.o -lpthread -o Parallel

然后我使用 time命令以了解经过的执行时间:

time ./Parallel

我明白了

value: +100000000

real 0m0.482s
user 0m0.472s
sys 0m0.000s

问题

好的。在上面的程序中,我创建了一个线程,等待它完成,然后才创建第二个线程。不是最好的“线程”,不是吗?所以我改变了程序中的顺序如下:

;create thread1
;create thread2
;join thread1
;join thread2

我希望在这种情况下耗时会更少,但我明白了

value: +48634696

real 0m2.403s
user 0m4.772s
sys 0m0.000s

我明白为什么 value 不等于 MAX 但我不明白的是 为什么在这种情况下耗时明显更多 ?我错过了什么吗?

编辑

我决定通过为每个变量使用不同的变量来排除 thread1thread2 之间的重叠,然后只添加结果。在这种情况下,“并行”顺序给出的运行时间较少(与之前的结果相比),但无论如何,大于“系列”顺序。

代码

仅显示更改

数据

现在有两个变量 --- 每个线程一个。

section .data
value1: dd 0
value2: dd 0

线程

每个线程负责增加自己的值。

global thread1
thread1:
mov rcx, qword [MAX]
shr rcx, 1

thread1.loop:
mov eax, dword [value1]
inc eax
mov dword [value1], eax
loop thread1.loop

ret

thread2 类似(将 1 替换为 2)。

得到最终结果

假设评论代表问题开头的代码部分的相应代码块,程序如下。

平行订单
;create thread1
;create thread1

;join thread1
;join thread2

mov eax, dword [value]
add eax, dword [value1]
add eax, dword [value2]
mov dword [value], eax
结果
value: +100000000

Performance counter stats for './Parallel':

3078.140527 cpu-clock (msec)

1.586070821 seconds time elapsed
系列订单
;create thread1
;join thread1

;create thread2
;join thread2

mov eax, dword [value]
add eax, dword [value1]
add eax, dword [value2]
mov dword [value], eax
结果
value: +100000000

Performance counter stats for './Parallel':

508.757321 cpu-clock (msec)

0.509709406 seconds time elapsed

更新

我绘制了一个简单的图表,反射(reflect)了 4 种不同模式下 MAX 值的时间依赖性。 enter image description here

最佳答案

同时运行两个线程的版本速度较慢,因为运行代码的两个内核将竞争包含计数器值的缓存行。缓存行将不得不在两个核心之间来回移动,每次需要 10s 个周期,并且在移回另一个核心之前只会发生一些增量。将其与单线程情况相比,在单线程情况下,增量可以每 ~5 个周期发生一次1,受存储转发延迟和慢速 loop 指令限制。

对于线程递增共享值的情况以及它们不同的其他情况都是如此。它甚至适用于后一种情况,因为值 value1value2 被声明为占据内存中的连续位置,因此出现在同一缓存行中。由于一致性发生在缓存行粒度上,这种所谓的“虚假共享”效应类似于真实共享(第一种情况)。

您提到虽然真共享和假共享情况都比单线程情况慢得多,但真共享情况仍然比假共享情况更慢。我原以为,在没有测试的情况下,这两种情况在性能方面是等效的,但它们没有意义:虽然两者都遭受上述缓存行抖动,但真正的共享情况可能还遭受额外的内存顺序清除 - 尽管确切的机制尚不清楚。

关于performance - 在 x86_64 汇编程序 (yasm) 中使用 POSIX 线程库需要更多的执行时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49475380/

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