cargo-profilerでRustのレイトレーシングのボトルネックがどこにあるのか探す
この比較はRayonの並列処理が入る前に調べたもの。
コミットハッシュ:0494dc8a2ec6e7a7be4cb8ded0502e1cd0edc993(ただしnx=300, ny=200に変更)
どこが一番呼び出されるのか?
sphere_hitableのhit()ということが分かった。
このhit()は球体にレイが衝突したのかしてないのかを判定するメソッド。レイと球体の成分を計算(判別式など)をしている。コードやプロファイリングの詳細は以下。
詳細
code:bash
Profiling ray-tracing-iow with callgrind...
Total Instructions...56,670,102,320
46,845,229,049 (82.7%) ???:<ray_tracing_iow::sphere_hitable
-----------------------------------------------------------------------
5,789,633,471 (10.2%) ???:ray_tracing_iow
-----------------------------------------------------------------------
3,566,713,925 (6.3%) ???:ray_tracing_iow
-----------------------------------------------------------------------
212,720,584 (0.4%) ???:ray_tracing_iow::camera::Camera
-----------------------------------------------------------------------
151,459,809 (0.3%) ???:<rand_hc::hc128
-----------------------------------------------------------------------
104,345,482 (0.2%) ???:ray_tracing_iow::util
-----------------------------------------------------------------------
Docker内(今回はUbuntuのはず)(Docker Desktop for Macを使った)
code:txt
root@9e7c2cb5cc91:/app# cargo profiler callgrind --bin ./target/release/ray-tracing-iow -n 10
Profiling ray-tracing-iow with callgrind...
Total Instructions...58,081,449,532
48,380,303,364 (83.3%) ???:_..ray_tracing_iow..sphere_hitable..SphereHitable..as..ray_tracing_iow..hitable..Hitable..::hit
-----------------------------------------------------------------------
5,778,193,594 (9.9%) ???:ray_tracing_iow::color
-----------------------------------------------------------------------
3,554,464,522 (6.1%) ???:ray_tracing_iow::color
-----------------------------------------------------------------------
215,284,471 (0.4%) ???:ray_tracing_iow::camera::Camera::get_ray
-----------------------------------------------------------------------
153,203,581 (0.3%) ???:_..rand_hc..hc128..Hc128Core..as..rand_core..block..BlockRngCore..::generate
-----------------------------------------------------------------------
以下がsphere_hitableのすべての実装。そのためhit()がボトルネックということだと思う。
code:src/sphere_hitable.rs
use crate::vec3::Vec3;
use crate::ray::Ray;
use crate::hitable::Hitable;
use crate::hitable::HitRecord;
use crate::material::Material;
use core::borrow::Borrow;
pub struct SphereHitable {
pub center: Vec3,
pub radius: f32,
pub material: Box<Material>
}
impl Hitable for SphereHitable {
fn hit(&self, r: &Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
let oc: Vec3 = &r.origin - &self.center;
let a : f32 = r.direction.dot(&r.direction);
let b : f32 = oc.dot(&r.direction);
let c : f32 = oc.dot(&oc) - self.radius*self.radius;
let discriminant: f32 = b * b - a * c;
let temp1: f32 = (-b - discriminant.sqrt()) / a;
let temp2: f32 = (-b + discriminant.sqrt()) / a;
let b1 : bool = t_min < temp1 && temp1 < t_max;
let b2 : bool = t_min < temp2 && temp2 < t_max;
if discriminant > 0.0 && (b1 || b2) {
let t: f32 = if b1 { temp1 } else {temp2};
let p: Vec3 = r.point_at_parameter(t);
let normal: Vec3 = &(&p - &self.center) / self.radius;
Some(HitRecord{ t, p, normal, material: self.material.borrow()})
} else {
None
}
}
}