datafusion_physical_expr_common/metrics/
expression.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Metrics helpers for expression evaluation.
19
20use super::{ExecutionPlanMetricsSet, MetricBuilder, MetricType, ScopedTimerGuard, Time};
21
22/// Tracks evaluation time for a sequence of expressions.
23///
24/// # Example
25/// Given SQL query:
26///     EXPLAIN ANALYZE
27///     SELECT a+1, pow(a,2)
28///     FROM generate_series(1, 1000000) as t1(a)
29///
30/// This struct holds two time metrics for the projection expressions
31/// `a+1` and `pow(a,2)`, respectively.
32///
33/// The output reads:
34/// `ProjectionExec: expr=[a@0 + 1 as t1.a + Int64(1), power(CAST(a@0 AS Float64), 2) as pow(t1.a,Int64(2))], metrics=[... expr_0_eval_time=9.23ms, expr_1_eval_time=32.35ms...]`
35#[derive(Debug, Clone)]
36pub struct ExpressionEvaluatorMetrics {
37    expression_times: Vec<Time>,
38}
39
40impl ExpressionEvaluatorMetrics {
41    /// Create metrics for a collection of expressions.
42    ///
43    /// # Args
44    /// - metrics: see `MetricBuilder` for details.
45    /// - partition: see `MetricBuilder` for details.
46    /// - expression_labels: unique identifier for each metric, so that the metric
47    ///   can get aggregated across multiple partitions. It is not the name showed
48    ///   in the `EXPLAIN ANALYZE`, the metric name will be `expr_{idx}_eval_time`
49    ///   according to the expression order.
50    pub fn new<T>(
51        metrics: &ExecutionPlanMetricsSet,
52        partition: usize,
53        expression_labels: impl IntoIterator<Item = T>,
54    ) -> Self
55    where
56        T: Into<String>,
57    {
58        let expression_times = expression_labels
59            .into_iter()
60            .enumerate()
61            .map(|(idx, label)| {
62                MetricBuilder::new(metrics)
63                    .with_new_label("expr", label.into())
64                    .with_type(MetricType::DEV)
65                    // Existing PhysicalExpr formatter is a bit verbose, so use simple name
66                    .subset_time(format!("expr_{idx}_eval_time"), partition)
67            })
68            .collect();
69
70        Self { expression_times }
71    }
72
73    /// Returns a timer guard for the expression at `index`, if present.
74    #[inline]
75    pub fn scoped_timer(&self, index: usize) -> Option<ScopedTimerGuard<'_>> {
76        self.expression_times.get(index).map(Time::timer)
77    }
78
79    /// The number of tracked expressions.
80    pub fn len(&self) -> usize {
81        self.expression_times.len()
82    }
83
84    /// True when no expressions are tracked.
85    pub fn is_empty(&self) -> bool {
86        self.expression_times.is_empty()
87    }
88}