This is an automated email from the ASF dual-hosted git repository.
agrove pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-comet.git
The following commit(s) were added to refs/heads/main by this push:
new c0ec49b2 perf: Add metric for time spent casting in native scan (#919)
c0ec49b2 is described below
commit c0ec49b23c9d214a499a6e5c0678f0d45dde3e58
Author: Andy Grove <[email protected]>
AuthorDate: Tue Sep 10 17:22:49 2024 -0600
perf: Add metric for time spent casting in native scan (#919)
* add native metric for time spent casting in native scan
* save progress
* save progress
* fix test
* address feedback
---
native/core/src/execution/operators/scan.rs | 13 +++++++++++--
.../apache/spark/sql/comet/CometMetricNode.scala | 9 +++++++++
.../org/apache/spark/sql/comet/CometScanExec.scala | 7 +++++--
.../org/apache/comet/exec/CometExecSuite.scala | 22 ++++++++++++++++++++++
4 files changed, 47 insertions(+), 4 deletions(-)
diff --git a/native/core/src/execution/operators/scan.rs
b/native/core/src/execution/operators/scan.rs
index 0816a5c1..7d75f7f1 100644
--- a/native/core/src/execution/operators/scan.rs
+++ b/native/core/src/execution/operators/scan.rs
@@ -39,7 +39,9 @@ use arrow_data::ffi::FFI_ArrowArray;
use arrow_data::ArrayData;
use arrow_schema::ffi::FFI_ArrowSchema;
use arrow_schema::{DataType, Field, Schema, SchemaRef};
-use datafusion::physical_plan::metrics::{BaselineMetrics,
ExecutionPlanMetricsSet, MetricsSet};
+use datafusion::physical_plan::metrics::{
+ BaselineMetrics, ExecutionPlanMetricsSet, MetricBuilder, MetricsSet, Time,
+};
use datafusion::{
execution::TaskContext,
physical_expr::*,
@@ -345,16 +347,20 @@ struct ScanStream<'a> {
baseline_metrics: BaselineMetrics,
/// Cast options
cast_options: CastOptions<'a>,
+ /// elapsed time for casting columns to different data types during scan
+ cast_time: Time,
}
impl<'a> ScanStream<'a> {
pub fn new(scan: ScanExec, schema: SchemaRef, partition: usize) -> Self {
let baseline_metrics = BaselineMetrics::new(&scan.metrics, partition);
+ let cast_time =
MetricBuilder::new(&scan.metrics).subset_time("cast_time", partition);
Self {
scan,
schema,
baseline_metrics,
cast_options: CastOptions::default(),
+ cast_time,
}
}
@@ -375,7 +381,10 @@ impl<'a> ScanStream<'a> {
.zip(schema_fields.iter())
.map(|(column, f)| {
if column.data_type() != f.data_type() {
- cast_with_options(column, f.data_type(),
&self.cast_options)
+ let mut timer = self.cast_time.timer();
+ let cast_array = cast_with_options(column, f.data_type(),
&self.cast_options);
+ timer.stop();
+ cast_array
} else {
Ok(Arc::clone(column))
}
diff --git
a/spark/src/main/scala/org/apache/spark/sql/comet/CometMetricNode.scala
b/spark/src/main/scala/org/apache/spark/sql/comet/CometMetricNode.scala
index 195a0fde..07173c30 100644
--- a/spark/src/main/scala/org/apache/spark/sql/comet/CometMetricNode.scala
+++ b/spark/src/main/scala/org/apache/spark/sql/comet/CometMetricNode.scala
@@ -79,6 +79,15 @@ object CometMetricNode {
"total time (in ms) spent in this operator"))
}
+ /**
+ * SQL Metrics for Comet native ScanExec
+ */
+ def scanMetrics(sc: SparkContext): Map[String, SQLMetric] = {
+ Map(
+ "cast_time" ->
+ SQLMetrics.createNanoTimingMetric(sc, "Total time for casting
columns"))
+ }
+
/**
* SQL Metrics for DataFusion HashJoin
*/
diff --git
a/spark/src/main/scala/org/apache/spark/sql/comet/CometScanExec.scala
b/spark/src/main/scala/org/apache/spark/sql/comet/CometScanExec.scala
index db36ce4b..2cbe8961 100644
--- a/spark/src/main/scala/org/apache/spark/sql/comet/CometScanExec.scala
+++ b/spark/src/main/scala/org/apache/spark/sql/comet/CometScanExec.scala
@@ -198,9 +198,12 @@ case class CometScanExec(
// Tracking scan time has overhead, we can't afford to do it for each row,
and can only do
// it for each batch.
if (supportsColumnar) {
- Some("scanTime" -> SQLMetrics.createNanoTimingMetric(sparkContext, "scan
time"))
+ Map(
+ "scanTime" -> SQLMetrics.createNanoTimingMetric(
+ sparkContext,
+ "scan time")) ++ CometMetricNode.scanMetrics(sparkContext)
} else {
- None
+ Map.empty
}
} ++ {
relation.fileFormat match {
diff --git a/spark/src/test/scala/org/apache/comet/exec/CometExecSuite.scala
b/spark/src/test/scala/org/apache/comet/exec/CometExecSuite.scala
index c26af28c..7e6334e0 100644
--- a/spark/src/test/scala/org/apache/comet/exec/CometExecSuite.scala
+++ b/spark/src/test/scala/org/apache/comet/exec/CometExecSuite.scala
@@ -517,6 +517,28 @@ class CometExecSuite extends CometTestBase {
}
}
+ test("Comet native metrics: scan") {
+ withSQLConf(CometConf.COMET_EXEC_ENABLED.key -> "true") {
+ withTempDir { dir =>
+ val path = new Path(dir.toURI.toString, "native-scan.parquet")
+ makeParquetFileAllTypes(path, dictionaryEnabled = true, 10000)
+ withParquetTable(path.toString, "tbl") {
+ val df = sql("SELECT * FROM tbl WHERE _2 > _3")
+ df.collect()
+
+ val metrics =
find(df.queryExecution.executedPlan)(_.isInstanceOf[CometScanExec])
+ .map(_.metrics)
+ .get
+
+ assert(metrics.contains("scanTime"))
+ assert(metrics.contains("cast_time"))
+ assert(metrics("scanTime").value > 0)
+ assert(metrics("cast_time").value > 0)
+ }
+ }
+ }
+ }
+
test("Comet native metrics: project and filter") {
withSQLConf(CometConf.COMET_EXEC_ENABLED.key -> "true") {
withParquetTable((0 until 5).map(i => (i, i + 1)), "tbl") {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]