1+ //! Vortex table provider metrics.
12use std:: sync:: Arc ;
2- use std:: time:: Duration ;
33
44use datafusion_physical_plan:: metrics:: {
55 Count , ExecutionPlanMetricsSet , Gauge , Label as DatafusionLabel ,
6- MetricValue as DatafusionMetricValue , MetricsSet , Time ,
6+ MetricValue as DatafusionMetricValue , MetricsSet ,
7+ } ;
8+ use datafusion_physical_plan:: {
9+ accept, ExecutionPlan , ExecutionPlanVisitor , Metric as DatafusionMetric ,
710} ;
8- use datafusion_physical_plan:: Metric as DatafusionMetric ;
911use vortex_metrics:: { DefaultTags , Metric , MetricId , Tags , VortexMetrics } ;
1012
11- pub static PARTITION_LABEL : & str = "partition" ;
13+ use super :: execution:: VortexExec ;
14+
15+ pub ( crate ) static PARTITION_LABEL : & str = "partition" ;
16+
17+ /// Extracts datafusion metrics from all VortexExec instances in
18+ /// a given physical plan.
19+ #[ derive( Default ) ]
20+ pub struct VortexMetricsFinder ( Vec < MetricsSet > ) ;
21+
22+ impl VortexMetricsFinder {
23+ /// find all metrics for VortexExec nodes.
24+ pub fn find_all ( plan : & dyn ExecutionPlan ) -> Vec < MetricsSet > {
25+ let mut finder = Self :: default ( ) ;
26+ match accept ( plan, & mut finder) {
27+ Ok ( ( ) ) => finder. 0 ,
28+ Err ( _) => Vec :: new ( ) ,
29+ }
30+ }
31+ }
32+
33+ impl ExecutionPlanVisitor for VortexMetricsFinder {
34+ type Error = std:: convert:: Infallible ;
35+ fn pre_visit ( & mut self , plan : & dyn ExecutionPlan ) -> Result < bool , Self :: Error > {
36+ if let Some ( metrics) = plan
37+ . as_any ( )
38+ . downcast_ref :: < VortexExec > ( )
39+ . and_then ( |exec| exec. metrics ( ) )
40+ {
41+ self . 0 . push ( metrics) ;
42+ }
43+ Ok ( true )
44+ }
45+ }
1246
1347#[ derive( Clone , Debug , Default ) ]
14- pub struct VortexExecMetrics {
48+ pub ( crate ) struct VortexExecMetrics {
1549 pub vortex : VortexMetrics ,
1650 pub execution_plan : ExecutionPlanMetricsSet ,
1751}
@@ -91,16 +125,17 @@ fn metric_value_to_datafusion(name: &str, metric: &Metric) -> Vec<DatafusionMetr
91125 }
92126 let snapshot = timer. snapshot ( ) ;
93127 if let Ok ( max) = snapshot. max ( ) . try_into ( ) {
94- res. push ( df_time ( format ! ( "{name}_max" ) , max) ) ;
128+ // NOTE(os): unlike Time metrics, gauges allow custom aggregation
129+ res. push ( df_gauge ( format ! ( "{name}_max" ) , max) ) ;
95130 }
96131 if let Ok ( min) = snapshot. min ( ) . try_into ( ) {
97- res. push ( df_time ( format ! ( "{name}_min" ) , min) ) ;
132+ res. push ( df_gauge ( format ! ( "{name}_min" ) , min) ) ;
98133 }
99134 if let Some ( p95) = f_to_u ( snapshot. value ( 0.95 ) ) {
100- res. push ( df_time ( format ! ( "{name}_p95" ) , p95 as u64 ) ) ;
135+ res. push ( df_gauge ( format ! ( "{name}_p95" ) , p95) ) ;
101136 }
102137 if let Some ( p99) = f_to_u ( snapshot. value ( 0.95 ) ) {
103- res. push ( df_time ( format ! ( "{name}_p99" ) , p99 as u64 ) ) ;
138+ res. push ( df_gauge ( format ! ( "{name}_p99" ) , p99) ) ;
104139 }
105140 res
106141 }
@@ -127,15 +162,6 @@ fn df_gauge(name: String, value: usize) -> DatafusionMetricValue {
127162 }
128163}
129164
130- fn df_time ( name : String , nanos : u64 ) -> DatafusionMetricValue {
131- let time = Time :: new ( ) ;
132- time. add_duration ( Duration :: from_nanos ( nanos) ) ;
133- DatafusionMetricValue :: Time {
134- name : name. into ( ) ,
135- time,
136- }
137- }
138-
139165fn f_to_u ( f : f64 ) -> Option < usize > {
140166 ( f. is_finite ( ) && f >= usize:: MIN as f64 && f <= usize:: MAX as f64 ) . then ( || f. trunc ( ) as usize )
141167}
0 commit comments