相关疑难解决方法(0)

当我删除边界检查时,为什么我的代码运行速度较慢?

我在Rust写了一个线性代数库.

我有一个函数来获取给定行和列的矩阵单元格的引用.此函数以一对断言开始,行和列在边界内:

#[inline(always)]
pub fn get(&self, row: usize, col: usize) -> &T {
    assert!(col < self.num_cols.as_nat());
    assert!(row < self.num_rows.as_nat());
    unsafe {
        self.get_unchecked(row, col)
    }
}
Run Code Online (Sandbox Code Playgroud)

在紧密的循环中,我认为跳过边界检查可能会更快,所以我提供了一个get_unchecked方法:

#[inline(always)]
pub unsafe fn get_unchecked(&self, row: usize, col: usize) -> &T {
    self.data.get_unchecked(self.row_col_index(row, col))
}
Run Code Online (Sandbox Code Playgroud)

奇怪的是,当我使用这些方法来实现矩阵乘法(通过行和列迭代器)时,我的基准测试显示,当我检查边界时它实际上快了大约33%.为什么会这样?

我在两台不同的计算机上试过这个,一台运行Linux,另一台运行OSX,两者都显示效果.

完整的代码在github上.相关文件是lib.rs.感兴趣的功能是:

  • get 在第68行
  • get_unchecked 在第81行
  • next 在第551行
  • mul 在第796行
  • matrix_mul (基准)在第1038行

请注意,我正在使用类型级数来参数化我的矩阵(通过虚拟标记类型也可以选择动态大小),因此基准测试将两个100x100矩阵相乘.

更新:

我已经大大简化了代码,删除了在基准测试中没有直接使用的东西并删除了泛型参数.我还编写了一个不使用迭代器的乘法实现,并且该版本不会产生相同的效果.有关此版本的代码,请参见此处.克隆minimal-performance分支并运行cargo bench将对两种不同的乘法实现进行基准测试(请注意,断言在该分支中以注释开头).

另外值得注意的是,如果我更改get*函数以返回数据的副本而不是引用(f64而不是&f64 …

optimization performance rust llvm-codegen

26
推荐指数
1
解决办法
740
查看次数

Rust的数组边界检查会影响性能吗?

我来自C,我想知道Rust的边界检查会影响性能.每次访问可能需要一些额外的汇编指令,这在处理大量数据时可能会受到影响.

另一方面,处理器性能代价高昂的是内存,因此更多的算术汇编指令可能不会受到影响,但是在加载缓存行之后,顺序访问应该非常快.

有人对此进行了基准测试吗?

arrays performance benchmarking rust

13
推荐指数
1
解决办法
3085
查看次数

Rust 是否会针对计算范围内的循环进行优化?

作为练习,我尝试对 Rust 1.3.0 中的代码进行微优化。我在数组上有一个循环。像这样的东西:

loop {
    for i in 0..arr.len() {
        // something happens here
    }
}
Run Code Online (Sandbox Code Playgroud)

由于 Rust 中的数组大小是固定的,编译器是否会通过arr.len()仅计算一次并重用该值来优化代码,还是会在顶层循环的每次传递中计算表达式?这个问题可以扩展到除了arr.len().

换句话说,上面的代码是否等同于:

let arr_len = arr.len();

loop {
    for i in 0..arr_len {
        // something happens here
    }
}
Run Code Online (Sandbox Code Playgroud)

optimization micro-optimization rust

3
推荐指数
1
解决办法
1088
查看次数