2015-10-03 47 views
6

我在尋找中寫入以下功能的有效方式,如another question討論:重複(x).take(n)性能?

fn dots(n: usize) -> String { 
    std::iter::repeat('.').take(n).collect() 
} 

是否鏽蝕產生的具體類型的通用結構類型的實例?是repeat('.').take(n)(該結構Take<Repeat<char>>)的結果相當於

struct Take_Repeat_char { 
    element: char, 
    n: usize 
} 

所有方法的實現內聯 - 會不會有中Take::next()已經Repeat::next()內聯中有一個版本?

什麼是檢查自己的好方法?檢查LLVM IR?

回答

12

是的,這是Rusty™就夠了。是的,如果您通過優化進行編譯(例如cargo build --release),LLVM將內聯整個項目。通過play.rust-lang.org檢查並查看生成的程序集。有問題的代碼是:

movb $46, (%rax) 
movb $46, 1(%rax) 
movb $46, 2(%rax) 
movb $46, 3(%rax) 
movb $46, 4(%rax) 

五個點。我相信有可能通過合併前四個點快速地去到一個

movd $x2e2e2e2e, (%rax) 

指示,但我不認爲這會令多大的差別。編輯:實際上取決於內存對齊,它可能會更快較慢:如果%rax是對齊的,它可能會快一點(取決於複雜的事情,如緩存,預取等),否則它可能會更慢因爲可能的陷阱)。

+1

我不得不-1,因爲它根本沒有性能不夠。我們不能斷然重複行「迭代器內嵌大」(他們這樣做)激勵的結論,如「它優化到好的代碼」,這是不正確的。 – bluss

+0

相關鏽PR即改善'BufWriter'建設:看到這個差異大塊頭(https://github.com/rust-lang/rust/pull/26849/files#diff-a074b6c6ae44d9ac353aa145411afb53L65) – bluss

+0

@bluss:不夠公平 - 請請注意,我並沒有說這在任何情況下都能正常工作,只是給出了具體的例子。 – llogiq

9

Rust是否爲泛型結構類型的實例生成具體類型?

是的,這就是所謂的monomorphization

方法實現是否內聯?

像許多語言一樣,這是一個堅實的「可能」。有hints you can provide the compiler來控制內部和內部的內聯,但通常由編譯器來做正確的事情。如上所述,如果某個函數使用泛型類型,則它可以自動用於單態化,這意味着將其內聯所需的信息在編譯後的箱子中可用。

什麼是檢查自己的好方法?

很多人會使用Rust Playground來查看LLVM IR或裝配。當然,您可以在本地查看rustc --emit [asm|llvm-ir]。當這樣做時,我把我感興趣的代碼放在一個永遠不會被內聯的函數中。這使得它更容易在裝配/ IR輸出發現:

#[inline(never)] 
fn dots(n: usize) -> String { 
    std::iter::repeat('.').take(n).collect() 
} 

正如llogiq已經指出的那樣,rustc和LLVM已通過你的整個執行看到和已經完全打開它。實現的變化取決於你想要的字符數。

辦法知道它是快剖析。引用llogiq:

我相信有可能通過合併前四個點快速地去到一個movd

我主張測試在現實世界中的任何這樣的代碼。彙編不是微不足道的,尤其是x64/x86_64變體。說明可能有奇怪的管線要求或可能導致CPU的其他部分不可用。

簡介,簡介,簡介!^_^

5

這不是一個真正高性能的,它是一種不好的。

const CAP: usize = 64 * 1024; 

#[bench] 
fn fill_string_repeat(b: &mut Bencher) { 
    b.iter(|| { 
     repeat('.').take(CAP).collect::<String>() 
    }); 
    b.bytes = CAP as u64; 
} 

#[bench] 
fn fill_string_vec(b: &mut Bencher) { 
    b.iter(|| { 
     String::from_utf8(vec![b'.'; CAP]) 
    }); 
    b.bytes = CAP as u64; 
} 

結果:

test fill_string_repeat    ... bench:  240,467 ns/iter (+/- 719) = 272 MB/s 
test fill_string_vec     ... bench:  106,885 ns/iter (+/- 224) = 613 MB/s 

vec!解決方案要好得多,這是包括UTF-8檢查開銷,其中占主導地位,使用String::from_utf8_unchecked並獲得:

test fill_string_vec_unchecked  ... bench:  29,354 ns/iter (+/- 503) = 2232 MB/s 

(這裏基本上只是memset的遺蹟。)

+0

內置釋放模式? – WiSaGaN

+0

當然,如果不這樣做的話,那也不會成功。 – bluss