gpt4 book ai didi

c - 为什么更新大型静态 float 组的程序在 Rust 中比在 C 中慢?

转载 作者:太空狗 更新时间:2023-10-29 17:09:13 28 4
gpt4 key购买 nike

我写了一个简单的程序来比较 Rust 和 C 的性能。

Rust 版本:

use std::time::Instant;

const STREAM_ARRAY_SIZE: usize = 10000000;
static mut A: [f64; STREAM_ARRAY_SIZE] = [1.0; STREAM_ARRAY_SIZE];

fn main() {
let now = Instant::now();

unsafe {
for i in 0..STREAM_ARRAY_SIZE {
A[i] = 2.0E0 * A[i];
}
}

let duration = now.elapsed();
println!("{}", (duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64) / 1000);
}

在调试和 Release模式下运行它:

$ ./target/debug/calc
472046 us.
$ ./target/release/calc
62860 us.

与调试版本相比,发布版本具有显着的性能提升。

C 版本做同样的事情并在同一台服务器上运行:

#include <sys/time.h>
#include <stdio.h>

#define STREAM_ARRAY_SIZE 10000000

static double A[STREAM_ARRAY_SIZE];
int mysecond(void)
{
struct timeval tp;
struct timezone tzp;
int i;

i = gettimeofday(&tp,&tzp);
return (tp.tv_sec * 1000000 + tp.tv_usec);
}

int main(void)
{
int j = 0;
for (j = 0; j < STREAM_ARRAY_SIZE; j++)
{
A[j] = 1.0;
}

int t = mysecond();
for (j = 0; j < STREAM_ARRAY_SIZE; j++)
{
A[j] = 2.0E0 * A[j];
}
printf("%d us.\n", mysecond() - t);
return 0;
}

-O0-O2编译运行:

$ gcc test.c
$ ./a.out
41626 us.
$ gcc -O2 test.c
$ ./a.out
13499 us.

Rust 优化版仅与gcc -O0 相比,与gcc -O2 相比非常弱。这合理吗?如何提高 Rust 版本的性能?

最佳答案

Rust 将循环编译为:

.LBB0_1:
movupd xmm0, xmmword ptr [rcx + 8*rax - 48]
movupd xmm1, xmmword ptr [rcx + 8*rax - 32]
addpd xmm0, xmm0
addpd xmm1, xmm1
movupd xmmword ptr [rcx + 8*rax - 48], xmm0
movupd xmmword ptr [rcx + 8*rax - 32], xmm1
movupd xmm0, xmmword ptr [rcx + 8*rax - 16]
movupd xmm1, xmmword ptr [rcx + 8*rax]
addpd xmm0, xmm0
addpd xmm1, xmm1
movupd xmmword ptr [rcx + 8*rax - 16], xmm0
movupd xmmword ptr [rcx + 8*rax], xmm1
add rax, 8
cmp rax, 100006
jne .LBB0_1

当 GCC 7.1.0 编译为:

L6:
movsd (%rbx), %xmm0
addq $8, %rbx
addsd %xmm0, %xmm0
movsd %xmm0, -8(%rbx)
cmpq %rbp, %rbx
jne L6

Rust 将数组放在数据部分,而 C 实际上将 (memset with pattern) 写入内存。这意味着您运行应用程序的操作系统可能只是映射范围并依赖虚拟内存来做正确的事情。

如果您更改代码以在测量前运行相同的循环,则运行时间会大大缩短。它实际上比我机器上的 C 版本要快。 (可能是由于该循环展开)

unsafe {
for i in 0..STREAM_ARRAY_SIZE {
A[i] = 2.0E0 * A[i];
}
}

let now = Instant::now();

unsafe {
for i in 0..STREAM_ARRAY_SIZE {
A[i] = 2.0E0 * A[i];
}
}

let duration = now.elapsed();

关于c - 为什么更新大型静态 float 组的程序在 Rust 中比在 C 中慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44403154/

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