私はこの非常に単純な Rust 関数を書きました:
fn iterate(nums: &Box<[i32]>) -> i32 {
let mut total = 0;
let len = nums.len();
for i in 0..len {
if nums[i] > 0 {
total += nums[i];
} else {
total -= nums[i];
}
}
total
}
順序付けられた配列とシャッフルされた配列を使用してメソッドを呼び出す基本的なベンチマークを作成しました。
fn criterion_benchmark(c: &mut Criterion) {
const SIZE: i32 = 1024 * 1024;
let mut group = c.benchmark_group("Branch Prediction");
// setup benchmarking for an ordered array
let mut ordered_nums: Vec<i32> = vec![];
for i in 0..SIZE {
ordered_nums.push(i - SIZE/2);
}
let ordered_nums = ordered_nums.into_boxed_slice();
group.bench_function("ordered", |b| b.iter(|| iterate(&ordered_nums)));
// setup benchmarking for a shuffled array
let mut shuffled_nums: Vec<i32> = vec![];
for i in 0..SIZE {
shuffled_nums.push(i - SIZE/2);
}
let mut rng = thread_rng();
let mut shuffled_nums = shuffled_nums.into_boxed_slice();
shuffled_nums.shuffle(&mut rng);
group.bench_function("shuffled", |b| b.iter(|| iterate(&shuffled_nums)));
group.finish();
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
2 つのベンチマークのランタイムがほぼ同じであることに驚いていますが、Java の同様のベンチマークでは、おそらくシャッフルされた場合の分岐予測の失敗が原因で、2 つの明確な違いが示されています。
条件付き移動命令についての言及を見てきましたがotool -tv
、実行可能ファイル (Mac で実行している) の場合、iterate
メソッドの出力には何も表示されません。
Rust で順序付けされたケースと順序付けられていないケースの間にパフォーマンスの違いが認識できない理由を誰かが明らかにすることはできますか?