Helper function for PrintExecSummary() that walks the exec summary recursively. Output for this node is appended to *result. Each value in *result should contain the statistics for a single exec summary node. node_idx is an in/out parameter. It is called with the idx (into exec_summary_.nodes) for the current node and on return, will contain the id of the next node.
| 35 | // node_idx is an in/out parameter. It is called with the idx (into exec_summary_.nodes) |
| 36 | // for the current node and on return, will contain the id of the next node. |
| 37 | void PrintExecSummary(const TExecSummary& exec_summary, int indent_level, |
| 38 | int new_indent_level, int* node_idx, |
| 39 | vector<vector<string>>* result) { |
| 40 | DCHECK_LT(*node_idx, exec_summary.nodes.size()); |
| 41 | const TPlanNodeExecSummary& node = exec_summary.nodes[*node_idx]; |
| 42 | const TExecStats& est_stats = node.estimated_stats; |
| 43 | |
| 44 | TExecStats agg_stats; |
| 45 | TExecStats max_stats; |
| 46 | |
| 47 | #define COMPUTE_MAX_SUM_STATS(NAME)\ |
| 48 | agg_stats.NAME += node.exec_stats[i].NAME;\ |
| 49 | max_stats.NAME = std::max(max_stats.NAME, node.exec_stats[i].NAME) |
| 50 | |
| 51 | // Compute avg and max of each used stat (cpu_time_ns is unused in the summary output). |
| 52 | for (int i = 0; i < node.exec_stats.size(); ++i) { |
| 53 | COMPUTE_MAX_SUM_STATS(latency_ns); |
| 54 | COMPUTE_MAX_SUM_STATS(cardinality); |
| 55 | COMPUTE_MAX_SUM_STATS(memory_used); |
| 56 | } |
| 57 | #undef COMPUTE_MAX_SUM_STATS |
| 58 | |
| 59 | int64_t avg_time = node.exec_stats.size() == 0 ? 0 : |
| 60 | agg_stats.latency_ns / node.exec_stats.size(); |
| 61 | |
| 62 | // Print the level to indicate nesting with "|--" |
| 63 | stringstream label_ss; |
| 64 | if (indent_level != 0) { |
| 65 | label_ss << "|"; |
| 66 | for (int i = 0; i < indent_level - 1; ++i) { |
| 67 | label_ss << " |"; |
| 68 | } |
| 69 | label_ss << (new_indent_level ? "--" : " "); |
| 70 | } |
| 71 | |
| 72 | label_ss << node.label; |
| 73 | |
| 74 | vector<string> row; |
| 75 | row.push_back(label_ss.str()); |
| 76 | row.push_back(lexical_cast<string>(node.num_hosts)); |
| 77 | row.push_back(lexical_cast<string>(node.exec_stats.size())); // Num instances |
| 78 | row.push_back(PrettyPrinter::Print(avg_time, TUnit::TIME_NS)); |
| 79 | row.push_back(PrettyPrinter::Print(max_stats.latency_ns, TUnit::TIME_NS)); |
| 80 | if (node.node_id == SINK_NODE_ID) { |
| 81 | // Cardinality stats are not valid for sinks. |
| 82 | row.push_back(""); |
| 83 | row.push_back(""); |
| 84 | } else { |
| 85 | row.push_back(PrettyPrinter::Print( |
| 86 | node.is_broadcast ? max_stats.cardinality : agg_stats.cardinality, TUnit::UNIT)); |
| 87 | row.push_back(PrettyPrinter::Print(est_stats.cardinality, TUnit::UNIT)); |
| 88 | } |
| 89 | row.push_back(PrettyPrinter::Print(max_stats.memory_used, TUnit::BYTES)); |
| 90 | row.push_back(PrettyPrinter::Print(est_stats.memory_used, TUnit::BYTES)); |
| 91 | // Node "details" may contain exprs which should be redacted. |
| 92 | row.push_back(RedactCopy(node.label_detail)); |
| 93 | result->push_back(row); |
| 94 |