near_performance_metrics_macros/lib.rs
1extern crate proc_macro;
2extern crate syn;
3
4use proc_macro::TokenStream;
5use quote::quote;
6
7/// Wrap the method call with near_performance_metrics::stats::measure_performance function.
8///
9/// This derive can be used to provide performance metrics to method calls with Actors. Currently
10/// we print performance stats per thread every minute, and we print a warning whenever a function
11/// call exceeds took more than given time limit. It should have no performance impact unless
12/// `performance_stats` feature is enabled.
13///
14/// This function assumes it wraps around a method with `&mut self, msg: NetworkClientMessages,
15/// ctx: &mut Self::Context<Self>` as arguments. There is currently a requirement that the second
16/// argument is called msg.
17///
18/// # Examples
19/// ```ignore
20///
21/// pub enum MyMessage {
22/// ExampleMessage()
23/// }
24///
25/// pub struct ExampleResponse {}
26/// use actix::Context;
27/// impl Handler<NetworkClientMessages> for ClientActor {
28/// type Result = ExampleResponse;
29///
30/// #[perf]
31/// fn handle(&mut self, msg: NetworkClientMessages, ctx: &mut Self::Context<Self>) -> Self::Result {
32/// ExampleResponse{}
33/// }
34/// }
35/// ```
36#[proc_macro_attribute]
37pub fn perf(_attr: TokenStream, item: TokenStream) -> TokenStream {
38 perf_internal(_attr, item, false)
39}
40
41/// Wrap the method call with near_performance_metrics::stats::measure_performance_with_debug function.
42///
43/// This derive can be used to provide performance metrics to method calls with Actors. Currently
44/// we print performance stats per thread every minute, and we print a warning whenever a function
45/// call exceeds took more than given time limit. It should have no performance impact unless
46/// `performance_stats` feature is enabled. In addition to prints provided by `perf`,
47/// `perf_with_debug` prints enum variant type of the message.
48///
49/// This function assumes it wraps around a method with `&mut self, msg: NetworkClientMessages,
50/// ctx: &mut Self::Context<Self>` as arguments. There is currently a requirement that the second
51/// argument is called msg. There is an assumption that the argument called `msg` is an enum, which
52/// has `#[derive(AsStaticStr)]`.
53///
54/// # Examples
55/// ```ignore
56/// use strum::AsStaticStr;
57///
58/// #[derive(AsStaticStr)]
59/// pub enum MyMessage {
60/// ExampleMessage()
61/// }
62///
63/// pub struct ExampleResponse {}
64/// impl Handler<NetworkClientMessages> for ClientActor {
65/// type Result = ExampleResponse;
66///
67/// #[perf_with_debug]
68/// fn handle(&mut self, msg: NetworkClientMessages, ctx: &mut Self::Context<Self>) -> Self::Result {
69/// ExampleResponse{}
70/// }
71/// }
72/// ```
73#[proc_macro_attribute]
74pub fn perf_with_debug(_attr: TokenStream, item: TokenStream) -> TokenStream {
75 perf_internal(_attr, item, true)
76}
77
78fn perf_internal(_attr: TokenStream, item: TokenStream, debug: bool) -> TokenStream {
79 let item: syn::Item = syn::parse(item).expect("failed to parse input");
80
81 if let syn::Item::Fn(mut func) = item.clone() {
82 let block = func.clone().block;
83
84 let function_body = quote! { #block };
85
86 let new_body: TokenStream = if debug {
87 let b: TokenStream = quote! {
88 fn xxx() {
89 use near_performance_metrics::stats::measure_performance_with_debug;
90 near_performance_metrics::stats::measure_performance_with_debug(std::any::type_name::<Self>(), msg, move |msg| {
91 #function_body
92 })
93 }
94 }.into();
95 b
96 } else {
97 let b: TokenStream = quote! {
98 fn xxx() {
99 use near_performance_metrics::stats::measure_performance;
100 near_performance_metrics::stats::measure_performance(std::any::type_name::<Self>(), msg, move |msg| {
101 #function_body
102 })
103 }
104 }.into();
105 b
106 };
107
108 if let syn::Item::Fn(func2) = syn::parse(new_body).expect("failed to parse input") {
109 func.block = func2.block;
110 } else {
111 panic!("failed to parse example function");
112 }
113
114 let result_item = syn::Item::Fn(func);
115 let output = quote! { #result_item };
116 output.into()
117 } else {
118 panic!("not a function");
119 }
120}