blob: aded383c158b22f76848534eaba05bd33df11b2e [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include "util/summary-util.h"
#include <vector>
#include <boost/lexical_cast.hpp>
#include "common/logging.h"
#include "util/pretty-printer.h"
#include "util/redactor.h"
#include "util/table-printer.h"
#include "common/names.h"
using namespace impala;
// 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.
void PrintExecSummary(const TExecSummary& exec_summary, int indent_level,
int new_indent_level, int* node_idx,
vector<vector<string>>* result) {
DCHECK_LT(*node_idx, exec_summary.nodes.size());
const TPlanNodeExecSummary& node = exec_summary.nodes[*node_idx];
const TExecStats& est_stats = node.estimated_stats;
TExecStats agg_stats;
TExecStats max_stats;
#define COMPUTE_MAX_SUM_STATS(NAME)\
agg_stats.NAME += node.exec_stats[i].NAME;\
max_stats.NAME = std::max(max_stats.NAME, node.exec_stats[i].NAME)
// Compute avg and max of each used stat (cpu_time_ns is unused in the summary output).
for (int i = 0; i < node.exec_stats.size(); ++i) {
COMPUTE_MAX_SUM_STATS(latency_ns);
COMPUTE_MAX_SUM_STATS(cardinality);
COMPUTE_MAX_SUM_STATS(memory_used);
}
#undef COMPUTE_MAX_SUM_STATS
int64_t avg_time = node.exec_stats.size() == 0 ? 0 :
agg_stats.latency_ns / node.exec_stats.size();
// Print the level to indicate nesting with "|--"
stringstream label_ss;
if (indent_level != 0) {
label_ss << "|";
for (int i = 0; i < indent_level - 1; ++i) {
label_ss << " |";
}
label_ss << (new_indent_level ? "--" : " ");
}
label_ss << node.label;
vector<string> row;
row.push_back(label_ss.str());
row.push_back(lexical_cast<string>(node.num_hosts));
row.push_back(lexical_cast<string>(node.exec_stats.size())); // Num instances
row.push_back(PrettyPrinter::Print(avg_time, TUnit::TIME_NS));
row.push_back(PrettyPrinter::Print(max_stats.latency_ns, TUnit::TIME_NS));
if (node.node_id == -1) {
// Cardinality stats are not valid for sinks.
row.push_back("");
row.push_back("");
} else {
row.push_back(PrettyPrinter::Print(
node.is_broadcast ? max_stats.cardinality : agg_stats.cardinality, TUnit::UNIT));
row.push_back(PrettyPrinter::Print(est_stats.cardinality, TUnit::UNIT));
}
row.push_back(PrettyPrinter::Print(max_stats.memory_used, TUnit::BYTES));
row.push_back(PrettyPrinter::Print(est_stats.memory_used, TUnit::BYTES));
// Node "details" may contain exprs which should be redacted.
row.push_back(RedactCopy(node.label_detail));
result->push_back(row);
map<int, int>::const_iterator child_fragment_idx_it =
exec_summary.exch_to_sender_map.find(*node_idx);
if (child_fragment_idx_it != exec_summary.exch_to_sender_map.end()) {
DCHECK_EQ(node.num_children, 0);
int child_fragment_id = child_fragment_idx_it->second;
PrintExecSummary(exec_summary, indent_level, false, &child_fragment_id, result);
}
++*node_idx;
if (node.num_children == 0) return;
// Print the non-left children to the stream first.
vector<vector<string>> child0_result;
PrintExecSummary(exec_summary, indent_level, false, node_idx, &child0_result);
for (int i = 1; i < node.num_children; ++i) {
PrintExecSummary(exec_summary, indent_level + 1, true, node_idx, result);
}
for (int i = 0; i < child0_result.size(); ++i) {
result->push_back(child0_result[i]);
}
}
string impala::PrintExecSummary(const TExecSummary& exec_summary) {
// Bail if Coordinator::InitExecProfile() has not been called.
if (!exec_summary.__isset.nodes) return "";
TablePrinter printer;
printer.set_max_output_width(1000);
printer.AddColumn("Operator", true);
printer.AddColumn("#Hosts", false);
printer.AddColumn("#Inst", false);
printer.AddColumn("Avg Time", false);
printer.AddColumn("Max Time", false);
printer.AddColumn("#Rows", false);
printer.AddColumn("Est. #Rows", false);
printer.AddColumn("Peak Mem", false);
printer.AddColumn("Est. Peak Mem", false);
printer.AddColumn("Detail", true);
vector<vector<string>> rows;
int node_idx = 0;
::PrintExecSummary(exec_summary, 0, false, &node_idx, &rows);
for (int i = 0; i < rows.size(); ++i) {
printer.AddRow(rows[i]);
}
return printer.ToString("\n");
}