Java 诊断性能问题

Java 诊断性能问题,java,performance,multidimensional-array,rust,Java,Performance,Multidimensional Array,Rust,我对生锈不是很有经验,我正在尝试诊断性能问题。下面是一个非常快速的Java代码(运行时间为7秒),我认为应该是等效的Rust代码。但是,Rust代码运行非常慢(是的,我也用--release编译了它),而且它似乎也溢出了。将i32更改为i64只会在稍后推动溢出,但它仍然会发生。我怀疑我写的东西中有一些bug,但在长时间关注这个问题之后,我决定寻求帮助 公共类废话{ 静态最终整数N=100; 静态最终int K=50; 公共静态void main(字符串[]args){ //初始化S int[]S

我对生锈不是很有经验,我正在尝试诊断性能问题。下面是一个非常快速的Java代码(运行时间为7秒),我认为应该是等效的Rust代码。但是,Rust代码运行非常慢(是的,我也用
--release
编译了它),而且它似乎也溢出了。将
i32
更改为
i64
只会在稍后推动溢出,但它仍然会发生。我怀疑我写的东西中有一些bug,但在长时间关注这个问题之后,我决定寻求帮助

公共类废话{
静态最终整数N=100;
静态最终int K=50;
公共静态void main(字符串[]args){
//初始化S
int[]S=新的int[N];

对于(int n=1;n诊断一般性能问题,I:

  • 获取一个基准时间或速率。最好创建一个只需要几秒钟的测试用例,因为分析器往往会使系统慢一点。您还需要经常迭代
  • 使用调试符号在发布模式下编译
  • 在分析器中运行代码。我在OSX上,所以我的主要选择是仪器,但我也使用valgrind
  • 找到最热门的代码路径,思考它为什么慢,尝试一些东西,测量
  • 最后一步是困难的部分


    在您的例子中,您有一个单独的实现,可以用作基线。比较这两个实现,我们可以看到您的数据结构不同。在Java中,您正在构建嵌套数组,但在Rust中,您使用的是ndarray板条箱。我知道板条箱有一个很好的维护人员,但我个人对此一无所知关于它的内部,或者它最适合什么用例

    因此,我使用标准库
    Vec
    重写了它

    我知道的另一件事是,直接数组访问不如使用迭代器快。这是因为数组访问需要执行边界检查,而迭代器将边界检查烘焙到自身中。很多时候这意味着使用
    迭代器上的方法

    另一个变化是在可能的情况下执行批量数据传输。不要逐个元素复制,而是使用
    copy\u from\u slice
    等方法移动整个切片

    通过这些更改,代码如下所示(为糟糕的变量名道歉,我相信您可以为它们找到语义名称):

    这将生成用于展开循环以及使用SIMD指令的程序集:

    +0x9b0    movdqu    -48(%rsi), %xmm0
    +0x9b5    movdqu    -48(%rcx), %xmm1
    +0x9ba    paddd     %xmm0, %xmm1
    +0x9be    movdqu    %xmm1, -48(%rsi)
    +0x9c3    movdqu    -32(%rsi), %xmm0
    +0x9c8    movdqu    -32(%rcx), %xmm1
    +0x9cd    paddd     %xmm0, %xmm1
    +0x9d1    movdqu    %xmm1, -32(%rsi)
    +0x9d6    movdqu    -16(%rsi), %xmm0
    +0x9db    movdqu    -16(%rcx), %xmm1
    +0x9e0    paddd     %xmm0, %xmm1
    +0x9e4    movdqu    %xmm1, -16(%rsi)
    +0x9e9    movdqu    (%rsi), %xmm0
    +0x9ed    movdqu    (%rcx), %xmm1
    +0x9f1    paddd     %xmm0, %xmm1
    +0x9f5    movdqu    %xmm1, (%rsi)
    +0x9f9    addq      $64, %rcx
    +0x9fd    addq      $64, %rsi
    +0xa01    addq      $-16, %rdx
    +0xa05    jne       "slow::main+0x9b0"
    

    1)你确定这大约需要7秒钟吗?在我的机器上,这只需要2秒钟。2)这里没有溢出的机会。你正在从2D数组y向2D数组x赋值,2D数组y充满了0,并且永远不会更新为任何其他值。因此,2D数组x也只有0。你到底想在这里做什么?我不知道I don’我看不到溢出。@MostafaAli 1)我能告诉你什么,我有一台旧电脑。7秒的时间是Java程序,Rust程序需要几分钟才能完成。2)关于溢出。最后的答案是~10^8,它小于2^31-1=2147483647。最后,你对零的看法是错误的。x和y不都是零。对不起,我错过了在计算和的代码的底部,使用了一些不同的逻辑。结果表明,在这种情况下,使用显式数组索引实际上更快;有关原因的讨论,请参阅。
    let xx = &mut current_x[e..e3];
    xx.copy_from_slice(&prev_y[0..e2]);
    
    let yy = &current_y[e..e3];
    for i in 0..(e3-e) {
        xx[i] += yy[i];
    }
    
    +0x9b0    movdqu    -48(%rsi), %xmm0
    +0x9b5    movdqu    -48(%rcx), %xmm1
    +0x9ba    paddd     %xmm0, %xmm1
    +0x9be    movdqu    %xmm1, -48(%rsi)
    +0x9c3    movdqu    -32(%rsi), %xmm0
    +0x9c8    movdqu    -32(%rcx), %xmm1
    +0x9cd    paddd     %xmm0, %xmm1
    +0x9d1    movdqu    %xmm1, -32(%rsi)
    +0x9d6    movdqu    -16(%rsi), %xmm0
    +0x9db    movdqu    -16(%rcx), %xmm1
    +0x9e0    paddd     %xmm0, %xmm1
    +0x9e4    movdqu    %xmm1, -16(%rsi)
    +0x9e9    movdqu    (%rsi), %xmm0
    +0x9ed    movdqu    (%rcx), %xmm1
    +0x9f1    paddd     %xmm0, %xmm1
    +0x9f5    movdqu    %xmm1, (%rsi)
    +0x9f9    addq      $64, %rcx
    +0x9fd    addq      $64, %rsi
    +0xa01    addq      $-16, %rdx
    +0xa05    jne       "slow::main+0x9b0"