< 返回版块

Neutron3529 发表于 2020-11-23 20:00

在论坛里安利Rust的时候惨遭打脸 用的是这个程序:

fn calc_n(n:u64){
    print!("N={},",n);
    let now=std::time::Instant::now();
    let mut ans=0u64;
    let (mut r1,mut r2,mut r3,mut r4,mut r5,mut r6);
    for a1 in 1..=n>>3{
        r1=n-a1;
        for a2 in a1..=r1/7{
            r2=r1-a2;
            for a3 in a2..=r2/6{
                r3=r2-a3;
                for a4 in a3..=r3/5{
                    r4=r3-a4;
                    for a5 in a4..=r4>>2{
                        r5=r4-a5;
                        for a6 in a5..=r5/3{
                            r6=r5-a6;
                            for a7 in a6..=r6>>1{
                                ans+=a1^a2^a3^a4^a5^a6^a7^(r6-a7);
                            }
                        }
                    }
                }
            }
        }
    }
    println!("{}, cost={:?}",ans,now.elapsed());
}
fn main(){
    calc_n(100);
    calc_n(160);
    calc_n(300);
    calc_n(400);
    calc_n(500);
    calc_n(600);
}

有人给出了julia版本:

function calcN(n::Int64)
    t1 = time()
    ans::Int64 = 0
   
    for a1=1:div(n, 8)
        r1 = n - a1
        for a2=a1:div(r1, 7)
            r2 = r1 - a2
            for a3=a2:div(r2, 6)
                r3 = r2 - a3
                for a4=a3:div(r3, 5)
                    r4 = r3 - a4
                    for a5=a4:div(r4, 4)
                        r5 = r4 - a5
                        for a6=a5:div(r5, 3)
                            r6 = r5 - a6
                            for a7=a6:div(r6, 2)
                                a8=r6 - a7
                                ans += xor(xor(xor(a1, a2), xor(a3, a4)), xor(xor(a5, a6), xor(a7, a8)))
                            end
                        end
                    end
                end
            end
        end
    end
    println("n=$n, ans = $ans, cost = $(time() -t1)")
end

在我的笔记本(i7-8750H, 5.8.18-1-MANJARO)上测试,

julia


julia> calcN(100);
n=100, ans = 29892426, cost = 0.0006000995635986328

julia> calcN(160);
n=160, ans = 901994896, cost = 0.009427070617675781

julia> calcN(300);
n=300, ans = 109638857854, cost = 0.4203529357910156

julia> calcN(400);
n=400, ans = 1260273347474, cost = 2.5435290336608887

julia> calcN(500);
n=500, ans = 6722928203618, cost = 10.702456951141357

julia> calcN(600);
n=600, ans = 25125831176186, cost = 34.18349599838257

rust,使用指令rustc test.rs -O && ./test编译&&运行

N=100,29892426, cost=1.616831ms
N=160,901994896, cost=30.246651ms
N=300,109638857854, cost=1.737976853s
N=400,1260273347474, cost=11.636545741s
N=500,6722928203618, cost=51.702947067s
N=600,25125831176186, cost=177.460155807s

想问一下rust究竟出了什么问题,导致Rust的耗时是Julia的5倍

不知哪位大神能抽空解答一下

不胜感激。


update:国外网友的尝试:

a..=b改成a..b+1,会获得一个显著的提速

更多的脑洞,可以看https://users.rust-lang.org/t/a-performance-problem-compared-with-julia/51871/15

虽然目前rust还是不如julia快(有人汇报过更快的结果但是没有复现用代码)……不过已经很接近了。


我做过的尝试:

使用top,两个程序都占用100%的CPU,没有哪个偷偷开多核

输出一致,两个程序应该没有漏掉某个计算。+xor同时出现的话,编译器应该不会借助数学公式优化掉某个循环

在julia里面用ans += xor(xor(xor(a1, a2), xor(a3, a4)), xor(xor(a5, a6), xor(a7, a8)))+1替代原计算程序,耗时略有增加,这证明了julia大概没有特别优化这几个xor判断

评论区

写评论
lithbitren 2023-01-26 02:30

搜别的东西不小心搜进来了,看了官方论坛帖子的solution,我只想说,局部变量牛逼!

Ge777 2020-11-28 07:46

最后结果怎么样

👇
Neutron3529: ……多谢告知

看来是我记错了。

--
👇
shaitao: 我看了 rustc --help, 怎么 -O 是 O2 -O Equivalent to -C opt-level=2

--
👇
Neutron3529: 关于优化等级,rustc里面-O就是O3啊

以及,就算println宏再耗时……每次调用函数只执行一次println!啊,总不能一次println!花好几秒吧……

--
👇
tian-deng: 首先应该是编译器优化的等级不一样, 其次就是rust的println宏相比较计算更耗费性能, 做了很多复杂的工作.

作者 Neutron3529 2020-11-28 00:43

……多谢告知

看来是我记错了。

--
👇
shaitao: 我看了 rustc --help, 怎么 -O 是 O2 -O Equivalent to -C opt-level=2

--
👇
Neutron3529: 关于优化等级,rustc里面-O就是O3啊

以及,就算println宏再耗时……每次调用函数只执行一次println!啊,总不能一次println!花好几秒吧……

--
👇
tian-deng: 首先应该是编译器优化的等级不一样, 其次就是rust的println宏相比较计算更耗费性能, 做了很多复杂的工作.

shaitao 2020-11-27 09:55

我看了 rustc --help, 怎么 -O 是 O2 -O Equivalent to -C opt-level=2

--
👇
Neutron3529: 关于优化等级,rustc里面-O就是O3啊

以及,就算println宏再耗时……每次调用函数只执行一次println!啊,总不能一次println!花好几秒吧……

--
👇
tian-deng: 首先应该是编译器优化的等级不一样, 其次就是rust的println宏相比较计算更耗费性能, 做了很多复杂的工作.

simoin 2020-11-25 16:51

照着那个帖子,测试了最内的两层for成for_each的代码,加上avx2加速后,和julia性能差不多

作者 Neutron3529 2020-11-25 15:56

关于优化等级,rustc里面-O就是O3啊

以及,就算println宏再耗时……每次调用函数只执行一次println!啊,总不能一次println!花好几秒吧……

--
👇
tian-deng: 首先应该是编译器优化的等级不一样, 其次就是rust的println宏相比较计算更耗费性能, 做了很多复杂的工作.

tian-deng 2020-11-25 11:27

首先应该是编译器优化的等级不一样, 其次就是rust的println宏相比较计算更耗费性能, 做了很多复杂的工作.

dongdong 2020-11-25 00:03

马克流明,关注后续。

Nalleyer 2020-11-24 22:08

mark,关注一下后续。

作者 Neutron3529 2020-11-24 17:19

https://users.rust-lang.org/t/a-performance-problem-compared-with-julia/51871/3

even with -C target-feature=+avx2,+fma, the cost of Rust keeps the same.


👇
dollarkillerx: 你这没有开编译器优化把

👇
shaitao: rustc -C opt-level=3 --target-cpus 试试呢

7sDream 2020-11-24 11:19

https://rust-lang.github.io/packed_simd/perf-guide/target-feature/rustflags.html

可以看看这个~

WorldLink 2020-11-24 11:14

你这没有开编译器优化把

shaitao 2020-11-24 10:35

rustc -C opt-level=3 --target-cpus 试试呢

作者 Neutron3529 2020-11-24 04:21

发现一个BUG

n=600为例

就算avx2产生了4倍加速

把这个4倍加速去掉,32*4仍然小于177s

我用

    n=n+34359738368
    for a1=4294967297:div(n, 8)

保证了Julia只能按照64bit算接下来的运算

总不能是我的8750H下载了intel的微码无师自通AVX512(于是获得8倍提速)了吧……

--
👇
gwy15: 看了下 julia 编译出来的代码,用了大量高级指令集的指令

; │┌ @ int.jl:85 within `-'
        vpsubq  %ymm3, %ymm4, %ymm9
        vpsubq  %ymm8, %ymm4, %ymm10
; │└
; │ @ REPL[36]:18 within `f'
; │┌ @ int.jl:332 within `xor'
        vpxor   %ymm3, %ymm6, %ymm11
        vpxor   %ymm9, %ymm11, %ymm9
; │└
; │┌ @ int.jl:86 within `+'
        vpaddq  %ymm5, %ymm9, %ymm5
; │└
; │┌ @ int.jl:332 within `xor'
        vpxor   %ymm8, %ymm6, %ymm8
        vpxor   %ymm10, %ymm8, %ymm8

作为对比, rust 编译出来的结果并没有用到啥高级指令集,基本上全是 AMD64 指令集,慢是正常的。

具体我也不知道怎么让 rust 强行使用高级指令集 = =

作者 Neutron3529 2020-11-24 04:00

感谢回复

明明两边都是输出llvm中间码……

不由得想起之前发现rustf64/f64i32/i32还快的情况了……

--
👇
gwy15: 看了下 julia 编译出来的代码,用了大量高级指令集的指令

; │┌ @ int.jl:85 within `-'
        vpsubq  %ymm3, %ymm4, %ymm9
        vpsubq  %ymm8, %ymm4, %ymm10
; │└
; │ @ REPL[36]:18 within `f'
; │┌ @ int.jl:332 within `xor'
        vpxor   %ymm3, %ymm6, %ymm11
        vpxor   %ymm9, %ymm11, %ymm9
; │└
; │┌ @ int.jl:86 within `+'
        vpaddq  %ymm5, %ymm9, %ymm5
; │└
; │┌ @ int.jl:332 within `xor'
        vpxor   %ymm8, %ymm6, %ymm8
        vpxor   %ymm10, %ymm8, %ymm8

作为对比, rust 编译出来的结果并没有用到啥高级指令集,基本上全是 AMD64 指令集,慢是正常的。

具体我也不知道怎么让 rust 强行使用高级指令集 = =

gwy15 2020-11-23 23:30

看了下 julia 编译出来的代码,用了大量高级指令集的指令

; │┌ @ int.jl:85 within `-'
        vpsubq  %ymm3, %ymm4, %ymm9
        vpsubq  %ymm8, %ymm4, %ymm10
; │└
; │ @ REPL[36]:18 within `f'
; │┌ @ int.jl:332 within `xor'
        vpxor   %ymm3, %ymm6, %ymm11
        vpxor   %ymm9, %ymm11, %ymm9
; │└
; │┌ @ int.jl:86 within `+'
        vpaddq  %ymm5, %ymm9, %ymm5
; │└
; │┌ @ int.jl:332 within `xor'
        vpxor   %ymm8, %ymm6, %ymm8
        vpxor   %ymm10, %ymm8, %ymm8

作为对比, rust 编译出来的结果并没有用到啥高级指令集,基本上全是 AMD64 指令集,慢是正常的。

具体我也不知道怎么让 rust 强行使用高级指令集 = =

1 共 16 条评论, 1 页