Capture query plan in pds-h output - #21315
Conversation
Currently, pds-h benchmarks will optionally print out the query plan if `--explain` is passed. With this PR, we'll also persist the query plan in the `pdsh_results.jsonl` file. This will facilitate downstream analysis. To make it easier for downstream tools to work with, we persist a structured version of the query plan, rather than the tree-like textual representation.
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
| cudf_polars.dsl.ir.IR node. | ||
| """ | ||
|
|
||
| id: str |
There was a problem hiding this comment.
ir.get_stable_id() returns an integer. But everything in in this module uses string IDs, since they end up as keys inside DAG.nodes, and JSON requires string keys.
|
In case it's helpful to see where this is (potentially) going, https://github.com/TomAugspurger/pygdf/tree/tom/structured-plans%2Btracing adds some additional things to our structlog records (similar to #21316). With the changes there, we can run Q1 and capture the plan: And then reconstruct it (with the annotations, like number of chunks) from the serialized JSON: none of that work is vetted yet, but I'm hopeful that it shows we can get some (and hopefully all) of the information we want out of these logs. |
use this serialize when logging.
|
Just a note that I was planning to review this much earlier, but keep getting distracted. That said, I'm on board with the general changes - Nothin big is jumping out at me. |
rjzamora
left a comment
There was a problem hiding this comment.
Thanks Tom! I left minor comments, but this should be good after the test conflict is resolved.
|
/merge |
Description
Currently, pds-h benchmarks will optionally print out the query plan if
--explainis passed. With this PR, we'll also persist the query plan in thepdsh_results.jsonlfile, underRunConfig.plans, a dict mapping query ID to (serialized) query plan. This will facilitate downstream analysis.To make it easier for downstream tools to work with, we persist a structured version of the query plan, rather than the tree-like textual representation.
Here's an example:
giving
Details
{ "roots": [ "1598104009" ], "nodes": { "1598104009": { "id": "1598104009", "children": [ "2141244145" ], "schema": { "l_returnflag": "STRING", "l_linestatus": "STRING", "sum_qty": "FLOAT64", "sum_base_price": "FLOAT64", "sum_disc_price": "FLOAT64", "sum_charge": "FLOAT64", "avg_qty": "FLOAT64", "avg_price": "FLOAT64", "avg_disc": "FLOAT64", "count_order": "UINT32" }, "properties": { "by": [ "l_returnflag", "l_linestatus" ], "order": [ "ASCENDING", "ASCENDING" ] }, "type": "Sort" }, "2141244145": { "id": "2141244145", "children": [ "3011781837" ], "schema": { "l_returnflag": "STRING", "l_linestatus": "STRING", "sum_qty": "FLOAT64", "sum_base_price": "FLOAT64", "sum_disc_price": "FLOAT64", "sum_charge": "FLOAT64", "avg_qty": "FLOAT64", "avg_price": "FLOAT64", "avg_disc": "FLOAT64", "count_order": "UINT32" }, "properties": { "columns": [ "l_returnflag", "l_linestatus", "sum_qty", "sum_base_price", "sum_disc_price", "sum_charge", "avg_qty", "avg_price", "avg_disc", "count_order" ] }, "type": "Select" }, "3011781837": { "id": "3011781837", "children": [ "3056697853" ], "schema": { "l_returnflag": "STRING", "l_linestatus": "STRING", "sum_qty": "FLOAT64", "sum_base_price": "FLOAT64", "sum_disc_price": "FLOAT64", "sum_charge": "FLOAT64", "avg_qty": "FLOAT64", "avg_price": "FLOAT64", "avg_disc": "FLOAT64", "______________11": "UINT32" }, "properties": { "columns": [ "l_returnflag", "l_linestatus", "sum_qty", "sum_base_price", "sum_disc_price", "sum_charge", "avg_qty", "avg_price", "avg_disc", "______________11" ] }, "type": "Select" }, "3056697853": { "id": "3056697853", "children": [ "3958692417" ], "schema": { "l_returnflag": "STRING", "l_linestatus": "STRING", "sum_qty": "FLOAT64", "sum_base_price": "FLOAT64", "sum_disc_price": "FLOAT64", "sum_charge": "FLOAT64", "________________0__mean_sum": "FLOAT64", "________________1__mean_count": "INT32", "________________2__mean_sum": "FLOAT64", "________________3__mean_count": "INT32", "________________4__mean_sum": "FLOAT64", "________________5__mean_count": "INT32", "______________11": "UINT32" }, "properties": { "keys": [ "l_returnflag", "l_linestatus" ] }, "type": "GroupBy" }, "3958692417": { "id": "3958692417", "children": [ "2166696742" ], "schema": { "l_returnflag": "STRING", "l_linestatus": "STRING", "sum_qty": "FLOAT64", "sum_base_price": "FLOAT64", "sum_disc_price": "FLOAT64", "sum_charge": "FLOAT64", "________________0__mean_sum": "FLOAT64", "________________1__mean_count": "INT32", "________________2__mean_sum": "FLOAT64", "________________3__mean_count": "INT32", "________________4__mean_sum": "FLOAT64", "________________5__mean_count": "INT32", "______________11": "UINT32" }, "properties": {}, "type": "Repartition" }, "2166696742": { "id": "2166696742", "children": [ "101741285" ], "schema": { "l_returnflag": "STRING", "l_linestatus": "STRING", "sum_qty": "FLOAT64", "sum_base_price": "FLOAT64", "sum_disc_price": "FLOAT64", "sum_charge": "FLOAT64", "________________0__mean_sum": "FLOAT64", "________________1__mean_count": "INT32", "________________2__mean_sum": "FLOAT64", "________________3__mean_count": "INT32", "________________4__mean_sum": "FLOAT64", "________________5__mean_count": "INT32", "______________11": "UINT32" }, "properties": { "keys": [ "l_returnflag", "l_linestatus" ] }, "type": "GroupBy" }, "101741285": { "id": "101741285", "children": [ "3768794358" ], "schema": { "l_quantity": "FLOAT64", "l_extendedprice": "FLOAT64", "l_discount": "FLOAT64", "l_tax": "FLOAT64", "l_returnflag": "STRING", "l_linestatus": "STRING", "l_shipdate": "TIMESTAMP_MILLISECONDS", "__POLARS_CSER_0x2d17d531a95f17f3": "FLOAT64" }, "properties": { "columns": [ "__POLARS_CSER_0x2d17d531a95f17f3" ] }, "type": "HStack" }, "3768794358": { "id": "3768794358", "children": [], "schema": { "l_quantity": "FLOAT64", "l_extendedprice": "FLOAT64", "l_discount": "FLOAT64", "l_tax": "FLOAT64", "l_returnflag": "STRING", "l_linestatus": "STRING", "l_shipdate": "TIMESTAMP_MILLISECONDS" }, "properties": { "typ": "parquet", "paths": [ "/datasets/toaugspurger/tpch-rs/scale-10//lineitem/part.0.parquet" ] }, "type": "Scan" } }, "partition_info": { "1598104009": { "count": 1, "partitioned_on": [ "l_returnflag", "l_linestatus" ] }, "2141244145": { "count": 1, "partitioned_on": [ "l_returnflag", "l_linestatus" ] }, "3011781837": { "count": 1, "partitioned_on": [ "l_returnflag", "l_linestatus" ] }, "3056697853": { "count": 1, "partitioned_on": [] }, "3958692417": { "count": 1, "partitioned_on": [] }, "2166696742": { "count": 3, "partitioned_on": [] }, "101741285": { "count": 3, "partitioned_on": [] }, "3768794358": { "count": 3, "partitioned_on": [] } } }One design note: I've flattened the query plan for serialization. See the updated overview.md, but the serialized object has a
nodeskey that's a mapping from node ID to node for all the nodes in the query plan. That seemed easier to work with than having to traverse the tree. Therootskey gives you the root node ID(s), and you can build the tree from there by inspecting thechildrenon each node.