gpt4 book ai didi

performance - 为什么XOR比OR快得多?

转载 作者:行者123 更新时间:2023-12-03 11:23:25 24 4
gpt4 key购买 nike

这是一个基准:

fn benchmark_or(repetitions: usize, mut increment: usize) -> usize {
let mut batch = 0;
for _ in 0..repetitions {
increment |= 1;
batch += increment | 1;
}
batch
}

fn benchmark_xor(repetitions: usize, mut increment: usize) -> usize {
let mut batch = 0;
for _ in 0..repetitions {
increment ^= 1;
batch += increment | 1;
}
batch
}

fn benchmark(c: &mut Criterion) {
let increment = 1;
let repetitions = 1000;

c.bench_function("Increment Or", |b| {
b.iter(|| black_box(benchmark_or(repetitions, increment)))
});
c.bench_function("Increment Xor", |b| {
b.iter(|| black_box(benchmark_xor(repetitions, increment)))
});
}
结果是:
Increment Or            time:   [271.02 ns 271.14 ns 271.28 ns]
Increment Xor time: [79.656 ns 79.761 ns 79.885 ns]
如果将 or替换为 and,我将得到相同的结果。
or基准编译为
.LBB0_5:
or edi, 1
add eax, edi
add rcx, -1
jne .LBB0_5
xor基准可以编译成基本相同的指令,外加两个附加的指令:
.LBB1_6:
xor edx, 1
or edi, 1
add eax, edi
mov edi, edx
add rcx, -1
jne .LBB1_6
Full Assembly code
为什么差异如此之大?

最佳答案

这部分功能使用了您引用的XOR:

.LBB1_6:
xor rdx, 1
or rsi, 1
add rax, rsi
mov rsi, rdx
add rcx, -1
jne .LBB1_6
只是展开循环的“尾端”。 “肉”(实际上运行很多的部分)是这样的:
.LBB1_9:
add rax, rdx
add rdi, 4
jne .LBB1_9
rdx设置为 increment的4倍-在某种程度上,我将其描述为“只有编译器才是这个愚蠢的东西”,但是它只发生在循环之外,因此这并不是完全的灾难。循环计数器在每次迭代中增加4(从负数开始计数到零,这很聪明,可以在某种程度上赎回编译器)。
该循环可以每个循环执行1次迭代,即每个循环进行4次源循环的迭代。
使用OR的函数中的循环也会展开,这是该函数的实际“实质”:
.LBB0_8:
or rsi, 1
lea rax, [rax + 2*rsi]
lea rax, [rax + 2*rsi]
lea rax, [rax + 2*rsi]
lea rax, [rax + 2*rsi]
add rdi, 8
jne .LBB0_8
它已经解开了8位,这可能不错,但是像这样将 lea链接4次确实需要“只有编译器才是愚蠢的”才能进入下一个级别。通过 lea的串行依赖关系每次迭代至少要花费4个周期,这意味着每个周期要进行2次源循环迭代。
这就解释了性能存在2倍的差异(支持XOR版本),并不是您所测得的3.4倍的差异,因此可以进行进一步的分析。

关于performance - 为什么XOR比OR快得多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65010708/

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