// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 //! Zero-overhead macros for compute task execution with optional validation //! //! These macros provide size-aware execution strategies: //! - `compute_small!`: Direct inline execution for tasks <100μs //! - `compute_medium!`: Semaphore-guarded block_in_place for tasks 100μs-1ms //! - `compute_large!`: Rayon offload for tasks >1ms //! //! When the `compute-validation` feature is enabled, these macros will //! time execution and emit warnings if tasks are misclassified. /// Execute a small compute task (<100μs) directly inline. /// /// This macro has zero overhead and simply executes the expression directly. /// When validation is enabled, it will warn if the task takes >100μs. /// /// # Example /// ``` /// # use dynamo_runtime::compute_small; /// let result = compute_small!(2 + 2); /// assert_eq!(result, 4); /// ``` #[macro_export] macro_rules! compute_small { ($expr:expr) => {{ #[cfg(feature = "compute-validation")] let _start = std::time::Instant::now(); let result = $expr; // Direct execution, zero overhead #[cfg(feature = "compute-validation")] $crate::compute::validation::validate_small(_start.elapsed()); result }}; } /// Execute a medium compute task (100μs-1ms) with intelligent scheduling. /// /// This macro first tries to use thread-local context if available (on Tokio worker threads). /// If no thread-local context, it requires a pool parameter. /// /// # Example /// ```ignore /// # use dynamo_runtime::{compute_medium, compute::ComputePool}; /// # async fn example(pool: &ComputePool) { /// // With thread-local context (on worker thread) /// let result = compute_medium!({ /// (0..1000).map(|i| i * 2).sum::() /// }).await; /// /// // Or with explicit pool (fallback) /// let result = compute_medium!(pool, { /// (0..1000).map(|i| i * 2).sum::() /// }).await; /// # } /// ``` #[macro_export] macro_rules! compute_medium { // Thread-local version (no pool parameter) ($expr:expr) => {{ #[cfg(feature = "compute-validation")] let _start = std::time::Instant::now(); let result = async { // Try thread-local context first if let Ok(_permit) = $crate::compute::thread_local::try_acquire_block_permit() { // Got permit - use block_in_place Ok(tokio::task::block_in_place(|| { let r = $expr; drop(_permit); // Release ASAP r })) } else if let Some(pool) = $crate::compute::thread_local::get_pool() { // No permit but have pool - offload pool.execute(|| $expr).await } else { // No context available - fall back to inline execution // This may block the async runtime but ensures the macro always works tracing::warn!("compute_medium: No thread-local context, executing inline (may block async runtime)"); Ok($expr) } } .await?; #[cfg(feature = "compute-validation")] $crate::compute::validation::validate_medium(_start.elapsed()); result }}; // Explicit pool version (fallback) ($pool:expr, $expr:expr) => {{ #[cfg(feature = "compute-validation")] let _start = std::time::Instant::now(); let result = async { // Try thread-local permits first, fall back to pool if let Ok(_permit) = $crate::compute::thread_local::try_acquire_block_permit() { // Got permit - use block_in_place Ok(tokio::task::block_in_place(|| { let r = $expr; drop(_permit); // Release ASAP r })) } else { // No permit available - offload to provided pool $pool.execute(|| $expr).await } } .await?; #[cfg(feature = "compute-validation")] $crate::compute::validation::validate_medium(_start.elapsed()); result }}; } /// Execute a large compute task (>1ms) on the Rayon thread pool. /// /// This macro always offloads to Rayon as the overhead is negligible /// compared to the computation time. /// /// # Example /// ```ignore /// # use dynamo_runtime::{compute_large, compute::ComputePool}; /// # async fn example(pool: &ComputePool) { /// // With thread-local context /// let result = compute_large!({ /// expensive_matrix_multiplication() /// }).await; /// /// // Or with explicit pool /// let result = compute_large!(pool, { /// expensive_matrix_multiplication() /// }).await; /// # } /// ``` #[macro_export] macro_rules! compute_large { // Thread-local version ($expr:expr) => {{ #[cfg(feature = "compute-validation")] let _start = std::time::Instant::now(); let result = async { if let Some(pool) = $crate::compute::thread_local::get_pool() { pool.execute(|| $expr).await } else { // No pool available - fall back to inline execution // Warning: Large tasks inline will severely block the async runtime tracing::warn!("compute_large: No thread-local context, executing inline (will block async runtime!)"); Ok($expr) } } .await?; #[cfg(feature = "compute-validation")] $crate::compute::validation::validate_large(_start.elapsed()); result }}; // Explicit pool version ($pool:expr, $expr:expr) => {{ #[cfg(feature = "compute-validation")] let _start = std::time::Instant::now(); let result = $pool.execute(|| $expr).await?; #[cfg(feature = "compute-validation")] $crate::compute::validation::validate_large(_start.elapsed()); result }}; }