1#[macro_export]
21macro_rules! profile_block {
22 ($name:expr, $block:block) => {{
23 let _guard = $crate::cpu::ProfileScope::simple($name.to_string(), "block".to_string());
24 $block
25 }};
26 ($name:expr, $category:expr, $block:block) => {{
27 let _guard = $crate::cpu::ProfileScope::simple($name.to_string(), $category.to_string());
28 $block
29 }};
30}
31
32#[macro_export]
52macro_rules! profile_current_function {
53 () => {
54 let _guard = $crate::cpu::ProfileScope::simple(
55 format!("{}::function", module_path!()),
56 "function".to_string(),
57 );
58 };
59 ($category:expr) => {
60 let _guard = $crate::cpu::ProfileScope::simple(
61 format!("{}::function", module_path!()),
62 $category.to_string(),
63 );
64 };
65}
66
67#[macro_export]
83macro_rules! profile_closure {
84 ($name:expr, $closure:expr) => {{
85 let _guard = $crate::cpu::ProfileScope::simple($name.to_string(), "closure".to_string());
86 $closure()
87 }};
88 ($name:expr, $category:expr, $closure:expr) => {{
89 let _guard = $crate::cpu::ProfileScope::simple($name.to_string(), $category.to_string());
90 $closure()
91 }};
92}
93
94#[macro_export]
106macro_rules! profile_alloc {
107 ($name:expr, $block:block) => {{
108 let _guard = $crate::cpu::ProfileScope::simple($name.to_string(), "allocation".to_string());
109 $block
110 }};
111}
112
113#[macro_export]
126macro_rules! profile_cuda {
127 ($name:expr, $block:block) => {{
128 let _guard = $crate::cpu::ProfileScope::simple($name.to_string(), "cuda".to_string());
129 $block
130 }};
131}
132
133#[macro_export]
149macro_rules! profile_tensor_op {
150 ($name:expr, flops: $flops:expr, $block:block) => {{
151 let _guard = $crate::cpu::ProfileScope::simple($name.to_string(), "tensor_op".to_string());
152 $block
153 }};
154}
155
156#[macro_export]
174macro_rules! profile_if {
175 ($condition:expr, $name:expr, $block:block) => {{
176 if $condition {
177 let _guard =
178 $crate::cpu::ProfileScope::simple($name.to_string(), "conditional".to_string());
179 $block
180 } else {
181 $block
182 }
183 }};
184}
185
186#[macro_export]
204macro_rules! profile_with_metadata {
205 ($name:expr, { $($key:ident: $value:expr),* $(,)? }, $block:block) => {{
206 let _guard = $crate::cpu::ProfileScope::simple($name.to_string(), "metadata".to_string());
207 $block
208 }};
209}
210
211#[macro_export]
224macro_rules! profile_loop {
225 ($name:expr, for $item:ident in $iter:expr, $body:block) => {{
226 let _guard = $crate::cpu::ProfileScope::simple($name.to_string(), "loop".to_string());
227 for $item in $iter $body
228 }};
229}
230
231#[macro_export]
247macro_rules! profile_async {
248 ($name:expr, $future:expr) => {{
249 let _guard = $crate::cpu::ProfileScope::simple($name.to_string(), "async".to_string());
250 $future
251 }};
252}
253
254#[macro_export]
268macro_rules! profile_compare {
269 ($name:expr, { $($variant:expr => $block:block),* $(,)? }) => {{
270 let mut results = std::collections::HashMap::new();
271
272 $(
273 let start_time = std::time::Instant::now();
274 {
275 let _guard = $crate::cpu::ProfileScope::simple(
276 format!("{}_{}", $name, $variant),
277 "comparison".to_string()
278 );
279 $block
280 }
281 let duration = start_time.elapsed();
282 results.insert($variant.to_string(), duration);
283 )*
284
285 println!("Profile comparison for {}:", $name);
287 let mut sorted_results: Vec<_> = results.iter().collect();
288 sorted_results.sort_by(|a, b| a.1.cmp(b.1));
289
290 for (variant, duration) in sorted_results {
291 println!(" {}: {:?}", variant, duration);
292 }
293
294 results
295 }};
296}
297
298#[macro_export]
313macro_rules! profiling_scope {
314 ($name:expr) => {
315 let _profiling_guard =
316 $crate::cpu::ProfileScope::simple($name.to_string(), "scope".to_string());
317 };
318 ($name:expr, $category:expr) => {
319 let _profiling_guard =
320 $crate::cpu::ProfileScope::simple($name.to_string(), $category.to_string());
321 };
322}
323
324#[macro_export]
339macro_rules! profile_with_overhead {
340 ($name:expr, $block:block) => {{
341 let overhead_start = std::time::Instant::now();
342 let _guard =
343 $crate::cpu::ProfileScope::simple($name.to_string(), "overhead_measured".to_string());
344 let setup_overhead = overhead_start.elapsed();
345
346 let operation_start = std::time::Instant::now();
347 let result = $block;
348 let operation_duration = operation_start.elapsed();
349
350 let teardown_start = std::time::Instant::now();
351 drop(_guard);
352 let teardown_overhead = teardown_start.elapsed();
353
354 let total_overhead = setup_overhead + teardown_overhead;
355
356 (
357 ProfileResult {
358 result,
359 duration: operation_duration,
360 },
361 total_overhead,
362 )
363 }};
364}
365
366pub struct ProfileResult<T> {
368 pub result: T,
369 pub duration: std::time::Duration,
370}
371
372#[macro_export]
385macro_rules! profile_sampled {
386 ($name:expr, sample_rate: $rate:expr, $block:block) => {{
387 use std::sync::atomic::{AtomicUsize, Ordering};
388 static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
389
390 let call_num = CALL_COUNT.fetch_add(1, Ordering::Relaxed);
391
392 if call_num % $rate == 0 {
393 let _guard = $crate::cpu::ProfileScope::simple(
394 format!("{}_sample_{}", $name, call_num / $rate),
395 "sampled".to_string(),
396 );
397 $block
398 } else {
399 $block
400 }
401 }};
402}
403
404#[macro_export]
417macro_rules! profile_thread_local {
418 ($name:expr, $block:block) => {{
419 thread_local! {
420 static PROFILER: std::cell::RefCell<$crate::cpu::CpuProfiler> =
421 std::cell::RefCell::new($crate::cpu::CpuProfiler::new());
422 }
423
424 let start_time = std::time::Instant::now();
425 let result = $block;
426 let duration = start_time.elapsed();
427
428 PROFILER.with(|profiler| {
429 let mut profiler = profiler.borrow_mut();
430 let _ = profiler.record_event($name, "thread_local", duration);
431 });
432
433 result
434 }};
435}
436
437#[cfg(test)]
442mod tests {
443 use super::*;
444 use std::time::Duration;
445
446 #[test]
447 fn test_profile_block_macro() {
448 let result = profile_block!("test_block", {
449 std::thread::sleep(Duration::from_millis(1));
450 42
451 });
452 assert_eq!(result, 42);
453 }
454
455 #[test]
456 fn test_profile_closure_macro() {
457 let result = profile_closure!("test_closure", || {
458 std::thread::sleep(Duration::from_millis(1));
459 "success"
460 });
461 assert_eq!(result, "success");
462 }
463
464 #[test]
465 fn test_profile_if_macro() {
466 let result = profile_if!(true, "conditional_test", {
467 std::thread::sleep(Duration::from_millis(1));
468 "executed"
469 });
470 assert_eq!(result, "executed");
471
472 let result = profile_if!(false, "conditional_test", {
473 std::thread::sleep(Duration::from_millis(1));
474 "also_executed"
475 });
476 assert_eq!(result, "also_executed");
477 }
478
479 #[test]
480 fn test_profile_compare_macro() {
481 let mut data1 = vec![3, 1, 4, 1, 5, 9, 2, 6];
482 let mut data2 = data1.clone();
483
484 let results = profile_compare!("sorting_test", {
485 "sort" => { data1.sort(); },
486 "sort_unstable" => { data2.sort_unstable(); }
487 });
488
489 assert_eq!(results.len(), 2);
490 assert!(results.contains_key("sort"));
491 assert!(results.contains_key("sort_unstable"));
492 }
493
494 #[test]
495 fn test_profile_sampled_macro() {
496 let mut execution_count = 0;
497
498 for _ in 0..10 {
499 profile_sampled!("sampled_test", sample_rate: 3, {
500 execution_count += 1;
501 });
502 }
503
504 assert_eq!(execution_count, 10); }
506
507 #[test]
508 fn test_profile_with_overhead_macro() {
509 let (result, overhead) = profile_with_overhead!("overhead_test", {
510 std::thread::sleep(Duration::from_millis(1));
511 "test_result"
512 });
513
514 assert_eq!(result.result, "test_result");
515 assert!(result.duration >= Duration::from_millis(1));
516 assert!(overhead < Duration::from_millis(1)); }
518
519 #[test]
520 fn test_profiling_scope_macro() {
521 profiling_scope!("test_scope");
522
523 std::thread::sleep(Duration::from_millis(1));
525 }
526
527 #[test]
528 fn test_profile_thread_local_macro() {
529 let result = profile_thread_local!("thread_local_test", {
530 std::thread::sleep(Duration::from_millis(1));
531 "thread_result"
532 });
533
534 assert_eq!(result, "thread_result");
535 }
536
537 #[tokio::test]
538 async fn test_profile_async_macro() {
539 let result = profile_async!("async_test", async {
540 tokio::time::sleep(Duration::from_millis(1)).await;
541 "async_result"
542 })
543 .await;
544
545 assert_eq!(result, "async_result");
546 }
547}