Rust trial: write benchmark
This commit is contained in:
parent
6b0fad89dc
commit
0b3fe689cd
3
lang-trials/rust-benchmark/.gitignore
vendored
Normal file
3
lang-trials/rust-benchmark/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
target/*
|
||||||
|
dist/*
|
||||||
|
Cargo.lock
|
35
lang-trials/rust-benchmark/Cargo.toml
Normal file
35
lang-trials/rust-benchmark/Cargo.toml
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
[package]
|
||||||
|
name = "sycamore-trial"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Aaron"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["console_error_panic_hook"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
nalgebra = "0.33.0"
|
||||||
|
sycamore = "0.9.0-beta.2"
|
||||||
|
typenum = "1.17.0"
|
||||||
|
|
||||||
|
# The `console_error_panic_hook` crate provides better debugging of panics by
|
||||||
|
# logging them with `console.error`. This is great for development, but requires
|
||||||
|
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
|
||||||
|
# code size when deploying.
|
||||||
|
console_error_panic_hook = { version = "0.1.7", optional = true }
|
||||||
|
|
||||||
|
[dependencies.web-sys]
|
||||||
|
version = "0.3.69"
|
||||||
|
features = [
|
||||||
|
'CanvasRenderingContext2d',
|
||||||
|
'HtmlCanvasElement',
|
||||||
|
'Window',
|
||||||
|
'Performance'
|
||||||
|
]
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
wasm-bindgen-test = "0.3.34"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = "s" # optimize for small code size
|
||||||
|
debug = true # include debug symbols
|
9
lang-trials/rust-benchmark/index.html
Normal file
9
lang-trials/rust-benchmark/index.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<title>The circular law</title>
|
||||||
|
<link data-trunk rel="css" href="main.css"/>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
23
lang-trials/rust-benchmark/main.css
Normal file
23
lang-trials/rust-benchmark/main.css
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
body {
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
color: #fcfcfc;
|
||||||
|
background-color: #202020;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
float: left;
|
||||||
|
background-color: #020202;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
13
lang-trials/rust-benchmark/notes
Normal file
13
lang-trials/rust-benchmark/notes
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
in profiling, most time is being spent in the `reflect` method:
|
||||||
|
|
||||||
|
f64:
|
||||||
|
sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection<T,D,S>::reflect::h7899977a4ba0b1d3
|
||||||
|
sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection<T,D,S>::reflect::hc337c3cb6e3b4061
|
||||||
|
sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection<T,D,S>::reflect_rows::h43d0f6838d0c2833
|
||||||
|
|
||||||
|
f32:
|
||||||
|
sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection<T,D,S>::reflect::h0e8ec322f198f847
|
||||||
|
sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection<T,D,S>::reflect::h9928bdd5e72743ea
|
||||||
|
sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection<T,D,S>::reflect_rows::h49f571fd8fc9b0f2
|
||||||
|
|
||||||
|
in one test, we spent 4000 ms in "WASM closure", but the enveloping "VoidFunction" takes 1300 ms longer. in another test, though, there's no overhang; the 7000 ms we spent in `rand_eigval_series` accounts for basically the entire load time, and matches the clock timing
|
176
lang-trials/rust-benchmark/src/engine.rs
Normal file
176
lang-trials/rust-benchmark/src/engine.rs
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
use nalgebra::{*, allocator::Allocator};
|
||||||
|
use std::f64::consts::{PI, E};
|
||||||
|
use web_sys::console;
|
||||||
|
/*use std::ops::Sub;*/
|
||||||
|
/*use typenum::{B1, UInt, UTerm};*/
|
||||||
|
|
||||||
|
/*pub fn eigvals_rotated<N>(A: SMatrix<f64, N, N>, time: f64): complex_eigenvalues(&self) -> OVector<NumComplex<T>, D>*/
|
||||||
|
|
||||||
|
/* static matrices. should only be used when the dimension is really small */
|
||||||
|
/*pub fn rand_eigval_series<N>(time_res: usize) -> Vec<OVector<Complex<f64>, N>>
|
||||||
|
where
|
||||||
|
N: ToTypenum + DimName + DimSub<U1>,
|
||||||
|
DefaultAllocator:
|
||||||
|
Allocator<N> +
|
||||||
|
Allocator<N, N> +
|
||||||
|
Allocator<<N as DimSub<U1>>::Output> +
|
||||||
|
Allocator<N, <N as DimSub<U1>>::Output>
|
||||||
|
{
|
||||||
|
// initialize the random matrix
|
||||||
|
let dim = N::try_to_usize().unwrap();
|
||||||
|
console::log_1(&format!("dimension {dim}").into());
|
||||||
|
let mut rand_mat = OMatrix::<f64, N, N>::from_fn(|j, k| {
|
||||||
|
let n = j*dim + k;
|
||||||
|
E*((n*n) as f64) % 2.0 - 1.0
|
||||||
|
}) * (3.0 / (dim as f64)).sqrt();
|
||||||
|
/*let mut rand_mat = OMatrix::<f64, N, N>::identity();*/
|
||||||
|
|
||||||
|
// initialize the rotation step
|
||||||
|
let mut rot_step = OMatrix::<f64, N, N>::identity();
|
||||||
|
let max_freq = 4;
|
||||||
|
for n in (0..dim).step_by(2) {
|
||||||
|
let ang = PI * ((n % max_freq) as f64) / (time_res as f64);
|
||||||
|
let ang_cos = ang.cos();
|
||||||
|
let ang_sin = ang.sin();
|
||||||
|
rot_step[(n, n)] = ang_cos;
|
||||||
|
rot_step[(n+1, n)] = ang_sin;
|
||||||
|
rot_step[(n, n+1)] = -ang_sin;
|
||||||
|
rot_step[(n+1, n+1)] = ang_cos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the eigenvalues
|
||||||
|
let mut eigval_series = Vec::<OVector<Complex<f64>, N>>::with_capacity(time_res);
|
||||||
|
console::log_1(&"before engine eigenvalues".into());
|
||||||
|
eigval_series.push(rand_mat.complex_eigenvalues());
|
||||||
|
console::log_1(&"after engine eigenvalues".into());
|
||||||
|
for _ in 1..time_res {
|
||||||
|
rand_mat = &rot_step * rand_mat;
|
||||||
|
eigval_series.push(rand_mat.complex_eigenvalues());
|
||||||
|
}
|
||||||
|
eigval_series
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/* another attempt at static matrices. i couldn't get the types to work out */
|
||||||
|
/*pub fn random_eigval_series<const N: usize>(time_res: usize) -> Vec<OVector<Complex<f64>, Const<N>>>
|
||||||
|
where
|
||||||
|
Const<N>: ToTypenum,
|
||||||
|
<Const<N> as ToTypenum>::Typenum: Sub<UInt<UTerm, B1>>,
|
||||||
|
<<Const<N> as ToTypenum>::Typenum as Sub<UInt<UTerm, B1>>>::Output: ToConst
|
||||||
|
{
|
||||||
|
// initialize the random matrix
|
||||||
|
/*let mut rand_mat = SMatrix::<f64, N, N>::zeros();
|
||||||
|
for n in 0..N*N {
|
||||||
|
rand_mat[n] = E*((n*n) as f64) % 2.0 - 1.0;
|
||||||
|
}*/
|
||||||
|
let rand_mat = OMatrix::<f64, Const<N>, Const<N>>::from_fn(|j, k| {
|
||||||
|
let n = j*N + k;
|
||||||
|
E*((n*n) as f64) % 2.0 - 1.0
|
||||||
|
});
|
||||||
|
|
||||||
|
// initialize the rotation step
|
||||||
|
let mut rot_step = OMatrix::<f64, Const<N>, Const<N>>::identity();
|
||||||
|
let max_freq = 4;
|
||||||
|
for n in (0..N).step_by(2) {
|
||||||
|
let ang = PI * ((n % max_freq) as f64) / (time_res as f64);
|
||||||
|
let ang_cos = ang.cos();
|
||||||
|
let ang_sin = ang.sin();
|
||||||
|
rot_step[(n, n)] = ang_cos;
|
||||||
|
rot_step[(n+1, n)] = ang_sin;
|
||||||
|
rot_step[(n, n+1)] = -ang_sin;
|
||||||
|
rot_step[(n+1, n+1)] = ang_cos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the eigenvalues
|
||||||
|
let mut eigvals = Vec::<OVector<Complex<f64>, Const<N>>>::with_capacity(time_res);
|
||||||
|
unsafe { eigvals.set_len(time_res); }
|
||||||
|
for t in 0..time_res {
|
||||||
|
eigvals[t] = rand_mat.complex_eigenvalues();
|
||||||
|
}
|
||||||
|
eigvals
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/* dynamic matrices */
|
||||||
|
pub fn rand_eigval_series<N>(time_res: usize) -> Vec<OVector<Complex<f64>, Dyn>>
|
||||||
|
where
|
||||||
|
N: ToTypenum + DimName + DimSub<U1>,
|
||||||
|
DefaultAllocator:
|
||||||
|
Allocator<N> +
|
||||||
|
Allocator<N, N> +
|
||||||
|
Allocator<<N as DimSub<U1>>::Output> +
|
||||||
|
Allocator<N, <N as DimSub<U1>>::Output>
|
||||||
|
{
|
||||||
|
// initialize the random matrix
|
||||||
|
let dim = N::try_to_usize().unwrap();
|
||||||
|
console::log_1(&format!("dimension {dim}").into());
|
||||||
|
let mut rand_mat = DMatrix::<f64>::from_fn(dim, dim, |j, k| {
|
||||||
|
let n = j*dim + k;
|
||||||
|
E*((n*n) as f64) % 2.0 - 1.0
|
||||||
|
}) * (3.0 / (dim as f64)).sqrt();
|
||||||
|
|
||||||
|
// initialize the rotation step
|
||||||
|
let mut rot_step = DMatrix::<f64>::identity(dim, dim);
|
||||||
|
let max_freq = 4;
|
||||||
|
for n in (0..dim).step_by(2) {
|
||||||
|
let ang = PI * ((n % max_freq) as f64) / (time_res as f64);
|
||||||
|
let ang_cos = ang.cos();
|
||||||
|
let ang_sin = ang.sin();
|
||||||
|
rot_step[(n, n)] = ang_cos;
|
||||||
|
rot_step[(n+1, n)] = ang_sin;
|
||||||
|
rot_step[(n, n+1)] = -ang_sin;
|
||||||
|
rot_step[(n+1, n+1)] = ang_cos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the eigenvalues
|
||||||
|
let mut eigval_series = Vec::<OVector<Complex<f64>, Dyn>>::with_capacity(time_res);
|
||||||
|
console::log_1(&"before engine eigenvalues".into());
|
||||||
|
eigval_series.push(rand_mat.complex_eigenvalues());
|
||||||
|
console::log_1(&"after engine eigenvalues".into());
|
||||||
|
for _ in 1..time_res {
|
||||||
|
rand_mat = &rot_step * rand_mat;
|
||||||
|
eigval_series.push(rand_mat.complex_eigenvalues());
|
||||||
|
}
|
||||||
|
eigval_series
|
||||||
|
}
|
||||||
|
|
||||||
|
/* dynamic single float matrices */
|
||||||
|
/*pub fn rand_eigval_series<N>(time_res: usize) -> Vec<OVector<Complex<f32>, Dyn>>
|
||||||
|
where
|
||||||
|
N: ToTypenum + DimName + DimSub<U1>,
|
||||||
|
DefaultAllocator:
|
||||||
|
Allocator<N> +
|
||||||
|
Allocator<N, N> +
|
||||||
|
Allocator<<N as DimSub<U1>>::Output> +
|
||||||
|
Allocator<N, <N as DimSub<U1>>::Output>
|
||||||
|
{
|
||||||
|
// initialize the random matrix
|
||||||
|
let dim = N::try_to_usize().unwrap();
|
||||||
|
console::log_1(&format!("dimension {dim}").into());
|
||||||
|
let mut rand_mat = DMatrix::<f32>::from_fn(dim, dim, |j, k| {
|
||||||
|
let n = j*dim + k;
|
||||||
|
(E as f32)*((n*n) as f32) % 2.0_f32 - 1.0_f32
|
||||||
|
}) * (3.0_f32 / (dim as f32)).sqrt();
|
||||||
|
|
||||||
|
// initialize the rotation step
|
||||||
|
let mut rot_step = DMatrix::<f32>::identity(dim, dim);
|
||||||
|
let max_freq = 4;
|
||||||
|
for n in (0..dim).step_by(2) {
|
||||||
|
let ang = (PI as f32) * ((n % max_freq) as f32) / (time_res as f32);
|
||||||
|
let ang_cos = ang.cos();
|
||||||
|
let ang_sin = ang.sin();
|
||||||
|
rot_step[(n, n)] = ang_cos;
|
||||||
|
rot_step[(n+1, n)] = ang_sin;
|
||||||
|
rot_step[(n, n+1)] = -ang_sin;
|
||||||
|
rot_step[(n+1, n+1)] = ang_cos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the eigenvalues
|
||||||
|
let mut eigval_series = Vec::<OVector<Complex<f32>, Dyn>>::with_capacity(time_res);
|
||||||
|
console::log_1(&"before engine eigenvalues".into());
|
||||||
|
eigval_series.push(rand_mat.complex_eigenvalues());
|
||||||
|
console::log_1(&"after engine eigenvalues".into());
|
||||||
|
for _ in 1..time_res {
|
||||||
|
rand_mat = &rot_step * rand_mat;
|
||||||
|
eigval_series.push(rand_mat.complex_eigenvalues());
|
||||||
|
}
|
||||||
|
eigval_series
|
||||||
|
}*/
|
86
lang-trials/rust-benchmark/src/main.rs
Normal file
86
lang-trials/rust-benchmark/src/main.rs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
use nalgebra::*;
|
||||||
|
use std::f64::consts::PI as PI;
|
||||||
|
use sycamore::{prelude::*, rt::{JsCast, JsValue}};
|
||||||
|
use web_sys::{console, window};
|
||||||
|
|
||||||
|
mod engine;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// set up a config option that forwards panic messages to `console.error`
|
||||||
|
#[cfg(feature = "console_error_panic_hook")]
|
||||||
|
console_error_panic_hook::set_once();
|
||||||
|
|
||||||
|
/*console::log_1(&"before test schur 60".into());*/
|
||||||
|
/*let test_rand_mat = OMatrix::<f64, U60, U60>::identity();*/
|
||||||
|
/*let test_rot_step = OMatrix::<f64, U56, U56>::identity();*/
|
||||||
|
/*let test_schur = test_rand_mat.schur();
|
||||||
|
console::log_1(&format!("after test schur").into());
|
||||||
|
let test_eigvals = test_schur.complex_eigenvalues();
|
||||||
|
console::log_1(&format!("after test eigenvalues").into());*/
|
||||||
|
|
||||||
|
sycamore::render(|| {
|
||||||
|
let time_res: usize = 100;
|
||||||
|
let time_step = create_signal(0.0);
|
||||||
|
let run_time_report = create_signal(-1.0);
|
||||||
|
let display = create_node_ref();
|
||||||
|
|
||||||
|
on_mount(move || {
|
||||||
|
let performance = window().unwrap().performance().unwrap();
|
||||||
|
let start_time = performance.now();
|
||||||
|
let eigval_series = engine::rand_eigval_series::<U60>(time_res);
|
||||||
|
let run_time = performance.now() - start_time;
|
||||||
|
run_time_report.set(run_time);
|
||||||
|
|
||||||
|
let canvas = display
|
||||||
|
.get::<DomNode>()
|
||||||
|
.unchecked_into::<web_sys::HtmlCanvasElement>();
|
||||||
|
let ctx = canvas
|
||||||
|
.get_context("2d")
|
||||||
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.dyn_into::<web_sys::CanvasRenderingContext2d>()
|
||||||
|
.unwrap();
|
||||||
|
ctx.set_fill_style(&JsValue::from("white"));
|
||||||
|
|
||||||
|
create_effect(move || {
|
||||||
|
// center and normalize the coordinate system
|
||||||
|
let width = canvas.width() as f64;
|
||||||
|
let height = canvas.height() as f64;
|
||||||
|
ctx.set_transform(1.0, 0.0, 0.0, -1.0, 0.5*width, 0.5*height).unwrap();
|
||||||
|
|
||||||
|
// clear the previous frame
|
||||||
|
ctx.clear_rect(-0.5*width, -0.5*width, width, height);
|
||||||
|
|
||||||
|
// find the resolution
|
||||||
|
const R_DISP: f64 = 1.5;
|
||||||
|
let res = width / (2.0*R_DISP);
|
||||||
|
|
||||||
|
// draw the eigenvalues
|
||||||
|
let eigvals = &eigval_series[time_step.get() as usize];
|
||||||
|
for n in 0..eigvals.len() {
|
||||||
|
ctx.begin_path();
|
||||||
|
ctx.arc(
|
||||||
|
/* typecast only needed for single float version */
|
||||||
|
res * f64::from(eigvals[n].re),
|
||||||
|
res * f64::from(eigvals[n].im),
|
||||||
|
3.0,
|
||||||
|
0.0, 2.0*PI
|
||||||
|
).unwrap();
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
view! {
|
||||||
|
div(id="app") {
|
||||||
|
div { (run_time_report.get()) " ms" }
|
||||||
|
canvas(ref=display, width="600", height="600")
|
||||||
|
input(
|
||||||
|
type="range",
|
||||||
|
max=(time_res - 1).to_string(),
|
||||||
|
bind:valueAsNumber=time_step
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user