質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

Q&A

解決済

1回答

2218閲覧

RustのSlice操作は遅いのか

namuyan

総合スコア76

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

0グッド

0クリップ

投稿2019/02/21 01:28

Rustのチュートリアルが終わったばかりの初心者です。
pyo3を常用する関係でrustc 1.34.0-nightlyを使用しております。
ArrayとSlice操作を使用している時に妙な速度低下がみられました。
そこで下記のようなプログラムを使用しベンチマーク取りました。

rust

1fn slicing() { 2 let now = Instant::now(); 3 println!("{:?}mSec", now.elapsed().as_micros() as f32 / 1000f32); 4 let s = [0u8; 1024]; 5 println!("{:?}mSec", now.elapsed().as_micros() as f32 / 1000f32); 6 let s1 = &s[..64]; 7 println!("{:?}mSec", now.elapsed().as_micros() as f32 / 1000f32); 8} 9 10fn main() { 11 slicing(); 12}

output

1>cargo run --release 2 Finished release [optimized] target(s) in 0.04s 3 Running `target\release\rust-test.exe` 40.0mSec 50.453mSec 60.789mSec

結果としてはSlice操作を行うと遅いという結果となりましたが正しい計測なのかわかりません。
実際に遅いのか、遅いならばどんな別の手段を用いればいいのか、なにか分かる方は回答の方を宜しくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

結果としてはSlice操作を行うと遅いという結果となりましたが正しい計測なのかわかりません。

残念ながら正しい計測にはなってないです。Compiler Explorerというサイトのこのページでコンパイル結果のアセンブリコードを見られるようにしましたが、以下のようになっています。

  • 配列sおよびスライスs1は全く作られていない。(値を読み出してないので、最適化により削除されています)
  • 結果としてprintln!の実行に費やした時間が表示されている

実際に遅いのか、遅いならばどんな別の手段を用いればいいのか、なにか分かる方は回答の方を宜しくお願いします。

sliceの作成はファットポインタ(fat pointer)と呼ばれる軽量なデータ構造を作るだけですので、非常に軽い処理になります。ファットポインタの内容は、1) データの先頭アドレスを指すポインタ(64ビット環境なら8バイト)と、2) データの長さ(要素数)を示すusize値 だけです。ですから遅いことはまず考えられません。

そのことをベンチマークで正しく計測するのは結構大変なので、そのような作業はお勧めしません。私がやるときはコンパイル後のアセンブリコードが期待通りになるまでRustコードを修正しながら試行錯誤する感じです。コマンドラインからの入力を元に配列を作成して、その配列を使った計算結果を出力するようにすると大体うまくいきます。(参考

あと、余談ですが上のCompiler Explorerのリンク先のページですが、コードの保存期限とかがあって見られなくなるかもしれません(いままでこのサイトでコードを共有したことがないので、よくわかってません) 一応、使い方を説明しておきます。

  • Editorのフレーム内の設定をRustに切り替えて、以下のコードをコピー&ペーストする
    • 関数にpubをつけないと結果が表示されないので注意

rust

1pub fn slicing() { 2 use std::time::Instant; 3 let now = Instant::now(); 4 println!("{:?}mSec", now.elapsed().as_micros() as f32 / 1000f32); 5 let s = [4u8; 1024]; 6 println!("{:?}mSec", now.elapsed().as_micros() as f32 / 1000f32); 7 let s1 = &s[..64]; 8 println!("{:?}mSec", now.elapsed().as_micros() as f32 / 1000f32); 9}
  • Compilerのフレームの設定を変更する
    • Rustコンパイラのバージョン:上のコードはunstableな機能を使っているのでnightlyを選択
    • コンパイラオプションの欄:-C opt-level=3

投稿2019/02/21 02:11

編集2019/02/21 02:35
tatsuya6502

総合スコア2035

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yohhoy

2019/02/21 03:57 編集

念のため補足:elapsed関数は「Instantが作られてからの経過時間」を返します。 https://doc.rust-lang.org/std/time/struct.Instant.html#method.elapsed 質問中にある値の解釈としては、0.453 と (0.789-0.453=) 0.336 とを比較すべきですね。ただしtatsuya6502さん回答の通り、質問者さんが本当に知りたい値にはなっていません。 この手のマイクロベンチマークは相当注意深く行わないと、誤った結論を導いてしまうことがあります。性能計測したい場合は、プログラムに実際に計算させたい処理を直接測ることから始めるのをおすすめします。
namuyan

2019/02/21 05:27

解答していただき有難うございます。さっそくツールを使用してみました。https://godbolt.org/z/UF72nY アセンブラをある程度理解できるようになりたいですね。
tatsuya6502

2019/02/21 05:49

yohhoyさん、補足していただき、ありがとうございました!
tatsuya6502

2019/02/21 05:54 編集

namuyan さん、そのツール、便利ですよね。コンパイル結果を見てみましたが、最適化後はforループやzipなどのRustのコードが消え去って、libcの`memcpy`の呼び出しに置き換わっているようです。Rustがコンパイラバックエンドとして使っているLLVMにそういう最適化がパターンとして入っているんでしょうね。面白いです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問