diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index e4ec421..4f6d7ef 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -32,6 +32,9 @@ jobs: matrix: ${{fromJSON(needs.checks-matrix.outputs.matrix)}} steps: - uses: actions/checkout@v4 + with: + lfs: true + submodules: 'recursive' - uses: DeterminateSystems/nix-installer-action@main - uses: DeterminateSystems/magic-nix-cache-action@main - run: nix build -L '.#${{ matrix.attr }}' @@ -44,6 +47,9 @@ jobs: steps: - uses: actions/checkout@v4 + with: + lfs: true + submodules: 'recursive' - uses: DeterminateSystems/nix-installer-action@main - uses: DeterminateSystems/magic-nix-cache-action@main diff --git a/Cargo.lock b/Cargo.lock index 5763cad..dce3756 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -491,9 +491,7 @@ dependencies = [ "divan", "dunce", "error-stack", - "libc", "mnn-sys", - "oneshot", "thiserror", "tracing", ] diff --git a/Cargo.toml b/Cargo.toml index 9634e38..10b8b31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,11 +18,12 @@ mnn = { version = "0.3.0", path = "." } error-stack = { version = "0.5" } [dependencies] -libc = "0.2" -mnn-sys = { version = "0.2", path = "mnn-sys", features = [] } +mnn-sys = { version = "0.2", path = "mnn-sys", default-features = false, features = [ + "mnn-threadpool", + "sparse-compute", +] } thiserror = "2" error-stack.workspace = true -oneshot = "0.1" tracing = { version = "0.1.40", optional = true } dunce = "1.0.5" @@ -32,13 +33,16 @@ opencl = ["mnn-sys/opencl"] metal = ["mnn-sys/metal"] coreml = ["mnn-sys/coreml"] +vulkan = [] # This is currently unimplemented + crt_static = ["mnn-sys/crt_static"] -# Disable mnn-threadpool to enable this -mnn-threadpool = ["mnn-sys/mnn-threadpool"] + tracing = ["dep:tracing"] profile = ["tracing"] -default = ["mnn-threadpool"] +simd = ["mnn-sys/simd"] + +default = ["simd"] [dev-dependencies] diff --git a/mnn-sys/Cargo.toml b/mnn-sys/Cargo.toml index 396024b..3ab1079 100644 --- a/mnn-sys/Cargo.toml +++ b/mnn-sys/Cargo.toml @@ -43,10 +43,13 @@ sparse-compute = [] arm82 = [] bf16 = [] cpu-weight-dequant-gemm = [] + # Disable if you don't plan to use cpu backend and want quicker compilation sse = [] avx512 = [] neon = [] +simd = ["sse", "avx512", "neon"] + low-memory = [] -default = ["mnn-threadpool", "sparse-compute", "sse", "neon", "opencl"] +default = ["mnn-threadpool", "sparse-compute", "opencl", "simd"] diff --git a/mnn-sys/build.rs b/mnn-sys/build.rs index 0f6d21a..9f2ac1b 100644 --- a/mnn-sys/build.rs +++ b/mnn-sys/build.rs @@ -31,9 +31,11 @@ static TARGET_FEATURES: LazyLock> = LazyLock::new(|| { static TARGET_OS: LazyLock = LazyLock::new(|| std::env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS not set")); + static TARGET_ARCH: LazyLock = LazyLock::new(|| { std::env::var("CARGO_CFG_TARGET_ARCH").expect("CARGO_CFG_TARGET_ARCH not found") }); + static EMSCRIPTEN_CACHE: LazyLock = LazyLock::new(|| { let emscripten_cache = std::process::Command::new("em-config") .arg("CACHE") @@ -180,7 +182,6 @@ fn _main() -> Result<()> { } } if is_emscripten() { - // println!("cargo:rustc-link-lib=static=stdc++"); let emscripten_cache = std::process::Command::new("em-config") .arg("CACHE") .output() @@ -526,7 +527,7 @@ fn read_dir(input: impl AsRef) -> impl Iterator { ignore::WalkBuilder::new(input) .max_depth(Some(1)) .build() - .filter_map(Result::ok) + .flatten() .map(|e| e.into_path()) } @@ -559,12 +560,11 @@ pub fn build_cpp_build(vendor: impl AsRef) -> Result<()> { let core_files_dir = vendor.join("source").join("core"); let core_files = ignore::Walk::new(&core_files_dir) - .filter_map(Result::ok) + .flatten() .filter(|e| e.path().extension() == Some(OsStr::new("cpp"))) .map(|e| e.into_path()); build.files(core_files); - // #[cfg(feature = "cpu")] { let cpu_files_dir = vendor.join("source").join("backend").join("cpu"); let cpu_files = ignore::WalkBuilder::new(&cpu_files_dir) @@ -573,7 +573,7 @@ pub fn build_cpp_build(vendor: impl AsRef) -> Result<()> { .add_custom_ignore_filename("CPUImageProcess.hpp") .add_custom_ignore_filename("CPUImageProcess.cpp") .build() - .filter_map(Result::ok) + .flatten() .filter(|e| e.path().extension() == Some(OsStr::new("cpp"))) .map(|e| e.into_path()); @@ -597,7 +597,7 @@ pub fn build_cpp_build(vendor: impl AsRef) -> Result<()> { { let cv_files_dir = vendor.join("source").join("cv"); let cv_files = ignore::Walk::new(&cv_files_dir) - .filter_map(Result::ok) + .flatten() .filter(|e| e.path().extension() == Some(OsStr::new("cpp"))) .map(|e| e.into_path()); // build.include(cv_files_dir.join("schema").join("current")); @@ -613,8 +613,8 @@ pub fn build_cpp_build(vendor: impl AsRef) -> Result<()> { .add(vendor.join("source").join("geometry")) .add(vendor.join("source").join("utils")) .build() - .filter_map(Result::ok) - .filter(|e| e.path().extension() == Some(OsStr::new("cpp"))) + .flatten() + .filter(|p| cpp_filter(p.path())) .map(|e| e.into_path()); build.files(extra_files); } @@ -623,7 +623,7 @@ pub fn build_cpp_build(vendor: impl AsRef) -> Result<()> { { let opencl_files_dir = vendor.join("source").join("backend").join("opencl"); let opencl_files = ignore::Walk::new(&opencl_files_dir) - .filter_map(Result::ok) + .flatten() .filter(|e| e.path().extension() == Some(OsStr::new("cpp"))) .map(|e| e.into_path()); let ocl_includes = opencl_files_dir.join("schema").join("current"); @@ -654,7 +654,7 @@ fn arm(build: &mut cc::Build, arm_dir: impl AsRef) -> Result<&mut cc::Buil if *TARGET_POINTER_WIDTH == 64 { let arm64_sources_dir = arm_source_dir.join("arm64"); let arm64_sources = ignore::Walk::new(&arm64_sources_dir) - .filter_map(Result::ok) + .flatten() .filter(|e| { e.path().extension() == Some(OsStr::new("S")) || e.path().extension() == Some(OsStr::new("s")) @@ -672,7 +672,7 @@ fn arm(build: &mut cc::Build, arm_dir: impl AsRef) -> Result<&mut cc::Buil } else if *TARGET_POINTER_WIDTH == 32 { let arm32_sources_dir = arm_source_dir.join("arm32"); let arm32_sources = ignore::Walk::new(&arm32_sources_dir) - .filter_map(Result::ok) + .flatten() .filter(|e| { e.path().extension() == Some(OsStr::new("S")) || e.path().extension() == Some(OsStr::new("s")) diff --git a/src/interpreter.rs b/src/interpreter.rs index f78e10d..0a8d1c5 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -241,9 +241,9 @@ impl Interpreter { /// /// return: the created session pub fn create_session( - &mut self, + &self, schedule: crate::ScheduleConfig, - ) -> Result { + ) -> Result> { profile!("Creating session"; { let session = unsafe { mnn_sys::Interpreter_createSession(self.inner, schedule.inner) }; assert!(!session.is_null()); @@ -270,7 +270,7 @@ impl Interpreter { /// /// return: the created session pub fn create_multipath_session( - &mut self, + &self, schedule: impl IntoIterator, ) -> Result { profile!("Creating multipath session"; { @@ -436,7 +436,7 @@ impl Interpreter { } /// Run a session - pub fn run_session(&mut self, session: &crate::session::Session) -> Result<()> { + pub fn run_session(&self, session: &crate::session::Session) -> Result<()> { profile!("Running session"; { let ret = unsafe { mnn_sys::Interpreter_runSession(self.inner, session.inner) }; ensure!( @@ -457,7 +457,7 @@ impl Interpreter { /// /// `sync` : synchronously wait for finish of execution or not. pub fn run_session_with_callback( - &mut self, + &self, session: &crate::session::Session, before: impl Fn(&[RawTensor], OperatorInfo) -> bool + 'static, end: impl Fn(&[RawTensor], OperatorInfo) -> bool + 'static, @@ -510,7 +510,7 @@ impl Interpreter { } /// Update cache file - pub fn update_cache_file(&mut self, session: &mut crate::session::Session) -> Result<()> { + pub fn update_cache_file(&self, session: &mut crate::session::Session) -> Result<()> { MNNError::from_error_code(unsafe { mnn_sys::Interpreter_updateCacheFile(self.inner, session.inner) }); @@ -820,7 +820,6 @@ impl OperatorInfo<'_> { } #[test] -#[ignore = "This test doesn't work in CI"] fn test_run_session_with_callback_info_api() { let file = Path::new("tests/assets/realesr.mnn") .canonicalize() @@ -838,7 +837,6 @@ fn test_run_session_with_callback_info_api() { } #[test] -#[ignore = "This test doesn't work in CI"] fn check_whether_sync_actually_works() { let file = Path::new("tests/assets/realesr.mnn") .canonicalize() @@ -868,14 +866,14 @@ fn check_whether_sync_actually_works() { assert!((time - time2) > std::time::Duration::from_millis(50)); } -#[test] -#[ignore = "Fails on CI"] -fn try_to_drop_interpreter_before_session() { - let file = Path::new("tests/assets/realesr.mnn") - .canonicalize() - .unwrap(); - let mut interpreter = Interpreter::from_file(&file).unwrap(); - let session = interpreter.create_session(ScheduleConfig::new()).unwrap(); - drop(interpreter); - drop(session); -} +// Impossible to compile +// #[test] +// fn try_to_drop_interpreter_before_session() { +// let file = Path::new("tests/assets/realesr.mnn") +// .canonicalize() +// .unwrap(); +// let mut interpreter = Interpreter::from_file(&file).unwrap(); +// let session = interpreter.create_session(ScheduleConfig::new()).unwrap(); +// drop(interpreter); +// drop(session); +// } diff --git a/src/schedule.rs b/src/schedule.rs index 875ec67..ebfb21c 100644 --- a/src/schedule.rs +++ b/src/schedule.rs @@ -16,7 +16,6 @@ use crate::{prelude::*, BackendConfig}; /// - `CPU`: Use the CPU for computation. /// - `Metal`: Use the Metal backend for computation (requires the `metal` feature). /// - `OpenCL`: Use the OpenCL backend for computation (requires the `opencl` feature). -/// - `OpenGL`: Use the OpenGL backend for computation (requires the `opengl` feature). /// - `Vulkan`: Use the Vulkan backend for computation (requires the `vulkan` feature). /// - `CoreML`: Use the CoreML backend for computation (requires the `coreml` feature). /// @@ -43,8 +42,6 @@ pub enum ForwardType { Metal, #[cfg(feature = "opencl")] OpenCL, - #[cfg(feature = "opengl")] - OpenGL, #[cfg(feature = "vulkan")] Vulkan, #[cfg(feature = "coreml")] @@ -62,8 +59,6 @@ impl ForwardType { ForwardType::Metal => MNNForwardType::MNN_FORWARD_METAL, #[cfg(feature = "opencl")] ForwardType::OpenCL => MNNForwardType::MNN_FORWARD_OPENCL, - #[cfg(feature = "opengl")] - ForwardType::OpenGL => MNNForwardType::MNN_FORWARD_OPENGL, #[cfg(feature = "vulkan")] ForwardType::Vulkan => MNNForwardType::MNN_FORWARD_VULKAN, #[cfg(feature = "coreml")] @@ -80,8 +75,6 @@ impl ForwardType { "metal", #[cfg(feature = "opencl")] "opencl", - #[cfg(feature = "opengl")] - "opengl", #[cfg(feature = "vulkan")] "vulkan", #[cfg(feature = "coreml")] @@ -102,8 +95,6 @@ impl core::str::FromStr for ForwardType { "metal" => Ok(ForwardType::Metal), #[cfg(feature = "opencl")] "opencl" => Ok(ForwardType::OpenCL), - #[cfg(feature = "opengl")] - "opengl" => Ok(ForwardType::OpenGL), #[cfg(feature = "vulkan")] "vulkan" => Ok(ForwardType::Vulkan), #[cfg(feature = "coreml")] diff --git a/src/session.rs b/src/session.rs index 5be36db..20865a6 100644 --- a/src/session.rs +++ b/src/session.rs @@ -4,7 +4,7 @@ use crate::prelude::*; /// /// Inference unit. multiple sessions could share one net/interpreter. #[derive(Debug)] -pub struct Session { +pub struct Session<'i> { /// Pointer to the underlying MNN session. pub(crate) inner: *mut mnn_sys::Session, /// Pointer to the underlying MNN interpreter @@ -17,7 +17,7 @@ pub struct Session { /// Internal session configurations. pub(crate) __session_internals: crate::SessionInternals, /// Marker to ensure the struct is not Send or Sync. - pub(crate) __marker: PhantomData<()>, + pub(crate) __marker: PhantomData<&'i ()>, } /// Enum representing the internal configurations of a session. @@ -29,7 +29,7 @@ pub enum SessionInternals { MultiSession(crate::ScheduleConfigs), } -impl Session { +impl Session<'_> { // pub unsafe fn from_ptr(session: *mut mnn_sys::Session) -> Self { // Self { // session, @@ -49,7 +49,7 @@ impl Session { } } -impl Drop for Session { +impl Drop for Session<'_> { /// Custom drop implementation to ensure the underlying MNN session is properly destroyed. fn drop(&mut self) { self.destroy(); diff --git a/tests/basic.rs b/tests/basic.rs index 420ab95..bc04727 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -6,15 +6,15 @@ use mnn::ForwardType; fn test_basic_cpu() { test_basic(ForwardType::CPU).unwrap(); } + #[cfg(feature = "metal")] #[test] -#[ignore = "Doesn't work on ci"] fn test_basic_metal() { test_basic(ForwardType::Metal).unwrap(); } + #[cfg(feature = "opencl")] #[test] -#[ignore = "Doesn't work on ci"] fn test_basic_opencl() -> Result<(), Box> { let backend = ForwardType::OpenCL; let realesr = std::path::Path::new("tests/assets/realesr.mnn"); @@ -46,16 +46,12 @@ fn test_basic_opencl() -> Result<(), Box> { // drop(net); Ok(()) } + #[cfg(feature = "coreml")] #[test] fn test_basic_coreml() { test_basic(ForwardType::CoreML).unwrap(); } -#[cfg(feature = "opengl")] -#[test] -fn test_basic_opengl() { - test_basic(ForwardType::OpenGL).unwrap(); -} #[test] #[ignore = "takes too long and unreliable on CI"] diff --git a/tests/resizing.rs b/tests/resizing.rs index f3e4753..69afa31 100644 --- a/tests/resizing.rs +++ b/tests/resizing.rs @@ -6,9 +6,11 @@ pub fn test_resizing() -> Result<()> { let model = std::fs::read("tests/assets/resizing.mnn").expect("No resizing model"); let mut net = Interpreter::from_bytes(&model).unwrap(); net.set_cache_file("resizing.cache", 128)?; - let config = ScheduleConfig::default(); + let mut config = ScheduleConfig::default(); #[cfg(feature = "opencl")] config.set_type(ForwardType::OpenCL); + #[cfg(not(feature = "opencl"))] + config.set_type(ForwardType::CPU); let mut session = net.create_session(config).unwrap(); net.update_cache_file(&mut session)?; diff --git a/tests/segfault.rs b/tests/segfault.rs index d061941..63a2f83 100644 --- a/tests/segfault.rs +++ b/tests/segfault.rs @@ -28,43 +28,40 @@ fn test_segfault_case_1_() -> Result<(), Box> { } #[test] -#[ignore] -pub fn test_resizing() { +pub fn test_segfault_case_2_() { use mnn::*; let model = std::fs::read("tests/assets/resizing.mnn").expect("No resizing model"); let mut net = Interpreter::from_bytes(&model).unwrap(); let config = ScheduleConfig::default(); let mut session = net.create_session(config).unwrap(); - loop { - let inputs = net.inputs(&session); - for tensor_info in inputs.iter() { - let mut tensor = unsafe { tensor_info.tensor_unresized::() }.unwrap(); - let mut shape = tensor.shape().as_ref().to_vec(); - dbg!(&shape); - shape.iter_mut().for_each(|v| { - if *v == -1 { - *v = 3; - } - }); - dbg!(&shape); - net.resize_tensor(&mut tensor, &shape); - } - drop(inputs); + let inputs = net.inputs(&session); + for tensor_info in inputs.iter() { + let mut tensor = unsafe { tensor_info.tensor_unresized::() }.unwrap(); + let mut shape = tensor.shape().as_ref().to_vec(); + dbg!(&shape); + shape.iter_mut().for_each(|v| { + if *v == -1 { + *v = 3; + } + }); + dbg!(&shape); + net.resize_tensor(&mut tensor, &shape); + } + drop(inputs); - net.resize_session(&mut session); - let inputs = net.inputs(&session); - for tensor_info in inputs.iter() { - let tensor = tensor_info.tensor::().unwrap(); - println!( - "{:13}: {:>13}", - tensor_info.name(), - format!("{:?}", tensor.shape()) - ); - let mut host = tensor.create_host_tensor_from_device(false); - host.host_mut().fill(1.0); - } - drop(inputs); - net.run_session(&session).unwrap(); + net.resize_session(&mut session); + let inputs = net.inputs(&session); + for tensor_info in inputs.iter() { + let tensor = tensor_info.tensor::().unwrap(); + println!( + "{:13}: {:>13}", + tensor_info.name(), + format!("{:?}", tensor.shape()) + ); + let mut host = tensor.create_host_tensor_from_device(false); + host.host_mut().fill(1.0); } + drop(inputs); + net.run_session(&session).unwrap(); }