Skip to main content

dynamo_runtime/compute/
macros.rs

1// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Zero-overhead macros for compute task execution with optional validation
5//!
6//! These macros provide size-aware execution strategies:
7//! - `compute_small!`: Direct inline execution for tasks <100μs
8//! - `compute_medium!`: Semaphore-guarded block_in_place for tasks 100μs-1ms
9//! - `compute_large!`: Rayon offload for tasks >1ms
10//!
11//! When the `compute-validation` feature is enabled, these macros will
12//! time execution and emit warnings if tasks are misclassified.
13
14/// Execute a small compute task (<100μs) directly inline.
15///
16/// This macro has zero overhead and simply executes the expression directly.
17/// When validation is enabled, it will warn if the task takes >100μs.
18///
19/// # Example
20/// ```
21/// # use dynamo_runtime::compute_small;
22/// let result = compute_small!(2 + 2);
23/// assert_eq!(result, 4);
24/// ```
25#[macro_export]
26macro_rules! compute_small {
27    ($expr:expr) => {{
28        #[cfg(feature = "compute-validation")]
29        let _start = std::time::Instant::now();
30
31        let result = $expr; // Direct execution, zero overhead
32
33        #[cfg(feature = "compute-validation")]
34        $crate::compute::validation::validate_small(_start.elapsed());
35
36        result
37    }};
38}
39
40/// Execute a medium compute task (100μs-1ms) with intelligent scheduling.
41///
42/// This macro first tries to use thread-local context if available (on Tokio worker threads).
43/// If no thread-local context, it requires a pool parameter.
44///
45/// # Example
46/// ```ignore
47/// # use dynamo_runtime::{compute_medium, compute::ComputePool};
48/// # async fn example(pool: &ComputePool) {
49/// // With thread-local context (on worker thread)
50/// let result = compute_medium!({
51///     (0..1000).map(|i| i * 2).sum::<i32>()
52/// }).await;
53///
54/// // Or with explicit pool (fallback)
55/// let result = compute_medium!(pool, {
56///     (0..1000).map(|i| i * 2).sum::<i32>()
57/// }).await;
58/// # }
59/// ```
60#[macro_export]
61macro_rules! compute_medium {
62    // Thread-local version (no pool parameter)
63    ($expr:expr) => {{
64        #[cfg(feature = "compute-validation")]
65        let _start = std::time::Instant::now();
66
67        let result = async {
68            // Try thread-local context first
69            if let Ok(_permit) = $crate::compute::thread_local::try_acquire_block_permit() {
70                // Got permit - use block_in_place
71                Ok(tokio::task::block_in_place(|| {
72                    let r = $expr;
73                    drop(_permit); // Release ASAP
74                    r
75                }))
76            } else if let Some(pool) = $crate::compute::thread_local::get_pool() {
77                // No permit but have pool - offload
78                pool.execute(|| $expr).await
79            } else {
80                // No context available - fall back to inline execution
81                // This may block the async runtime but ensures the macro always works
82                tracing::warn!("compute_medium: No thread-local context, executing inline (may block async runtime)");
83                Ok($expr)
84            }
85        }
86        .await?;
87
88        #[cfg(feature = "compute-validation")]
89        $crate::compute::validation::validate_medium(_start.elapsed());
90
91        result
92    }};
93
94    // Explicit pool version (fallback)
95    ($pool:expr, $expr:expr) => {{
96        #[cfg(feature = "compute-validation")]
97        let _start = std::time::Instant::now();
98
99        let result = async {
100            // Try thread-local permits first, fall back to pool
101            if let Ok(_permit) = $crate::compute::thread_local::try_acquire_block_permit() {
102                // Got permit - use block_in_place
103                Ok(tokio::task::block_in_place(|| {
104                    let r = $expr;
105                    drop(_permit); // Release ASAP
106                    r
107                }))
108            } else {
109                // No permit available - offload to provided pool
110                $pool.execute(|| $expr).await
111            }
112        }
113        .await?;
114
115        #[cfg(feature = "compute-validation")]
116        $crate::compute::validation::validate_medium(_start.elapsed());
117
118        result
119    }};
120}
121
122/// Execute a large compute task (>1ms) on the Rayon thread pool.
123///
124/// This macro always offloads to Rayon as the overhead is negligible
125/// compared to the computation time.
126///
127/// # Example
128/// ```ignore
129/// # use dynamo_runtime::{compute_large, compute::ComputePool};
130/// # async fn example(pool: &ComputePool) {
131/// // With thread-local context
132/// let result = compute_large!({
133///     expensive_matrix_multiplication()
134/// }).await;
135///
136/// // Or with explicit pool
137/// let result = compute_large!(pool, {
138///     expensive_matrix_multiplication()
139/// }).await;
140/// # }
141/// ```
142#[macro_export]
143macro_rules! compute_large {
144    // Thread-local version
145    ($expr:expr) => {{
146        #[cfg(feature = "compute-validation")]
147        let _start = std::time::Instant::now();
148
149        let result = async {
150            if let Some(pool) = $crate::compute::thread_local::get_pool() {
151                pool.execute(|| $expr).await
152            } else {
153                // No pool available - fall back to inline execution
154                // Warning: Large tasks inline will severely block the async runtime
155                tracing::warn!("compute_large: No thread-local context, executing inline (will block async runtime!)");
156                Ok($expr)
157            }
158        }
159        .await?;
160
161        #[cfg(feature = "compute-validation")]
162        $crate::compute::validation::validate_large(_start.elapsed());
163
164        result
165    }};
166
167    // Explicit pool version
168    ($pool:expr, $expr:expr) => {{
169        #[cfg(feature = "compute-validation")]
170        let _start = std::time::Instant::now();
171
172        let result = $pool.execute(|| $expr).await?;
173
174        #[cfg(feature = "compute-validation")]
175        $crate::compute::validation::validate_large(_start.elapsed());
176
177        result
178    }};
179}