You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add output_bytes metrics to Explain Analyze #16244
Is your feature request related to a problem or challenge?
Currently, using Explain Analyze seems to only provide the metric for output_rows. Is it possible to add a metric for the number of bytes output by each operator?
A quick reminder for someone who is willing to implement it: It's possible that multiple Arrays share the same underlying buffer -- those Arrays can be within the same batch or across batches.
The current memory accounting utilities only support detect buffer reuse within the batch (not across batches), so a extension to this might be needed.
I'd be interested in working on this, but I might need a little guidance since I'm new to the project.
Thank you! Here are some additional info
Each operator holds a BaselineMetrics inside for common metrics like output_rows, and this new output_bytes should also belong to BaselineMetrics.
When the operator output one batch, it will call record_poll() to update the BaselineMetrics
So I think the implementation would be adding a new field output_bytes (and other useful structures) into BaselineMetrics, and then update them inside record_poll(), the tricky part would be avoiding double-counting array buffers I mentioned above.
To see the expected result, run a explain analyze query using datafusion-cli, and this new metrics should show up inside metrics
> explain analyze select * from generate_series(1, 1000000) as t1(v1) order by v1 desc;
+-------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| plan_type | plan |
+-------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Plan with Metrics | SortExec: expr=[v1@0 DESC], preserve_partitioning=[false], metrics=[output_rows=1000000, elapsed_compute=91.856373ms, spill_count=0, spilled_bytes=0.0 B, spilled_rows=0] |
| | ProjectionExec: expr=[value@0 as v1], metrics=[output_rows=1000000, elapsed_compute=14.702µs] |
| | LazyMemoryExec: partitions=1, batch_generators=[generate_series: start=1, end=1000000, batch_size=8192], metrics=[] |
| | |
+-------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row(s) fetched.
Elapsed 0.039 seconds.
FYI, unfortunately I haven't been had the time to implement this yet and won't be around next week. I plan to pick this up afterward unless someone beats me to it.
A quick reminder for someone who is willing to implement it: It's possible that multiple Arrays share the same underlying buffer -- those Arrays can be within the same batch or across batches. The current memory accounting utilities only support detect buffer reuse within the batch (not across batches), so a extension to this might be needed.
I'm wondering about a good approach here. get_record_batch_memory_size uses the data pointers of the buffers to deduplicate. Within a single record batch, that doesn't seem problematic. I'm not sure if we can use the same approach across multiple record batches. If I understand correctly, those record batches do not have the same lifetime, so the same pointer could be allocated twice and filled with different data. (Can Buffer objects themselves be reused with different data?) In this case, we want to count the pointer/buffer twice. That being said, this scenario might happen infrequently enough for us to not care.
There's also some discussion around this going on over at apache/arrow-rs#6439 which makes it sound like accurately measuring bytes in this scenario is a bigger issue. @2010YOUY01, do you have thoughts on this?
An alternative approach could be to calculate output_bytes based on the actual number of bytes occupied on the buffer by the array. This should be accurate but might be expensive.
A quick reminder for someone who is willing to implement it: It's possible that multiple Arrays share the same underlying buffer -- those Arrays can be within the same batch or across batches. The current memory accounting utilities only support detect buffer reuse within the batch (not across batches), so a extension to this might be needed. datafusion/datafusion/physical-plan/src/spill/mod.rs
Line 239 in d68111d
pub fn get_record_batch_memory_size(batch: &RecordBatch) -> usize {
I'm wondering about a good approach here. get_record_batch_memory_size uses the data pointers of the buffers to deduplicate. Within a single record batch, that doesn't seem problematic. I'm not sure if we can use the same approach across multiple record batches. If I understand correctly, those record batches do not have the same lifetime, so the same pointer could be allocated twice and filled with different data. (Can Buffer objects themselves be reused with different data?) In this case, we want to count the pointer/buffer twice. That being said, this scenario might happen infrequently enough for us to not care.
There's also some discussion around this going on over at apache/arrow-rs#6439 which makes it sound like accurately measuring bytes in this scenario is a bigger issue. @2010YOUY01, do you have thoughts on this?
An alternative approach could be to calculate output_bytes based on the actual number of bytes occupied on the buffer by the array. This should be accurate but might be expensive.
I agree with the concerns about the buffer lifetime across batches. Another problem might be: if the input is very large this hashset-based solution might cause noticeable slowdown.
I think we need an arrow-side solution that better solve this issue. This refcount solution seems a good idea to me, but it requires more effort to move it forward apache/arrow-rs#6590
Now for datafusion, maybe the best thing to do is simply sum(get_record_batch_memory_size()), this should work for common cases, and open an github issue to explain the limitation and track future TODOs to make it accurate.
Now for datafusion, maybe the best thing to do is simply sum(get_record_batch_memory_size()), this should work for common cases, and open an github issue to explain the limitation and track future TODOs to make it accurate.
It looks like there are other sets of metrics that would benefit from adding output_bytes for improved data in EXPLAIN ANALYZE, namely UnnestMetrics, SortMergeJoinMetrics, StreamJoinMetrics, and BuildProbeJoinMetrics. I'm wondering whether we should add output_bytes to these structs or rather refactor them to make use of BaselineMetrics.
It looks like there are other sets of metrics that would benefit from adding output_bytes for improved data in EXPLAIN ANALYZE, namely UnnestMetrics, SortMergeJoinMetrics, StreamJoinMetrics, and BuildProbeJoinMetrics. I'm wondering whether we should add output_bytes to these structs or rather refactor them to make use of BaselineMetrics.
If they're the top-level metrics struct directly managed by an executor (xxExec), then it should be better to let then use BaselineMetrics.
I'll double-check and file tickets, thanks for the investigation.
Activity
2010YOUY01 commentedon Jun 4, 2025
It's a good idea.
A quick reminder for someone who is willing to implement it: It's possible that multiple
Arrays share the same underlying buffer -- thoseArrays can be within the same batch or across batches.The current memory accounting utilities only support detect buffer reuse within the batch (not across batches), so a extension to this might be needed.
datafusion/datafusion/physical-plan/src/spill/mod.rs
Line 239 in d68111d
hendrikmakait commentedon Jun 4, 2025
I'd be interested in working on this, but I might need a little guidance since I'm new to the project.
2010YOUY01 commentedon Jun 4, 2025
Thank you! Here are some additional info
Each operator holds a
BaselineMetricsinside for common metrics likeoutput_rows, and this newoutput_bytesshould also belong toBaselineMetrics.When the operator output one batch, it will call
record_poll()to update theBaselineMetricsdatafusion/datafusion/physical-plan/src/metrics/baseline.rs
Line 123 in 992d156
So I think the implementation would be adding a new field
output_bytes(and other useful structures) intoBaselineMetrics, and then update them insiderecord_poll(), the tricky part would be avoiding double-counting array buffers I mentioned above.To see the expected result, run a
explain analyzequery usingdatafusion-cli, and this new metrics should show up insidemetricshendrikmakait commentedon Jun 6, 2025
FYI, unfortunately I haven't been had the time to implement this yet and won't be around next week. I plan to pick this up afterward unless someone beats me to it.
hendrikmakait commentedon Jun 19, 2025
take
hendrikmakait commentedon Jun 19, 2025
I'm wondering about a good approach here.
get_record_batch_memory_sizeuses the data pointers of the buffers to deduplicate. Within a single record batch, that doesn't seem problematic. I'm not sure if we can use the same approach across multiple record batches. If I understand correctly, those record batches do not have the same lifetime, so the same pointer could be allocated twice and filled with different data. (Can Buffer objects themselves be reused with different data?) In this case, we want to count the pointer/buffer twice. That being said, this scenario might happen infrequently enough for us to not care.There's also some discussion around this going on over at apache/arrow-rs#6439 which makes it sound like accurately measuring bytes in this scenario is a bigger issue. @2010YOUY01, do you have thoughts on this?
An alternative approach could be to calculate
output_bytesbased on the actual number of bytes occupied on the buffer by the array. This should be accurate but might be expensive.2010YOUY01 commentedon Jun 20, 2025
I agree with the concerns about the buffer lifetime across batches. Another problem might be: if the input is very large this hashset-based solution might cause noticeable slowdown.
I think we need an arrow-side solution that better solve this issue. This refcount solution seems a good idea to me, but it requires more effort to move it forward apache/arrow-rs#6590
Now for datafusion, maybe the best thing to do is simply
sum(get_record_batch_memory_size()), this should work for common cases, and open an github issue to explain the limitation and track future TODOs to make it accurate.hendrikmakait commentedon Jun 20, 2025
Sounds like a good plan to me, I'll get started.
hendrikmakait commentedon Jun 20, 2025
It looks like there are other sets of metrics that would benefit from adding
output_bytesfor improved data inEXPLAIN ANALYZE, namelyUnnestMetrics,SortMergeJoinMetrics,StreamJoinMetrics, andBuildProbeJoinMetrics. I'm wondering whether we should addoutput_bytesto these structs or rather refactor them to make use ofBaselineMetrics.2010YOUY01 commentedon Jun 21, 2025
If they're the top-level metrics struct directly managed by an executor (
xxExec), then it should be better to let then useBaselineMetrics.I'll double-check and file tickets, thanks for the investigation.
feat: Add `output_bytes` to baseline metrics (#18268)
feat: Add `output_bytes` to baseline metrics (apache#18268)
feat: Add `output_bytes` to baseline metrics (apache#18268)