in www/scripts/query_timeline/fragment_diagram.js [451:659]
export function collectFragmentEventsFromProfile() {
rownum = 0;
let max_namelen = 0;
fragments = [];
const all_nodes = [];
const receiver_nodes = [];
let color_idx = 0;
try {
// First pass: compute sizes
const execution_profile = profile.child_profiles[2];
const EXECUTION_PROFILE_NAME = execution_profile.profile_name.split(" ").slice(0,2)
.join(" ");
console.assert(EXECUTION_PROFILE_NAME === "Execution Profile");
execution_profile.child_profiles.forEach((fp) => {
if (fp.child_profiles !== undefined &&
fp.child_profiles[0].event_sequences !== undefined) {
let cp = fp.child_profiles[0];
const fevents = fp.child_profiles[0].event_sequences[0].events;
// Build list of timestamps that spans instances for each event
for (let en = 0; en < fevents.length; ++en) {
if (fevents[en].label.includes("AsyncCodegen")) {
fevents[en].no_bar = true;
continue;
}
fevents[en].ts_list = [ fevents[en].timestamp ];
}
for (let instance = 1; instance < fp.child_profiles.length; ++instance) {
if (fp.child_profiles[instance].event_sequences !== undefined) {
if (fp.child_profiles[instance].event_sequences[0].events.length ==
fevents.length) {
for (let en = 0; en < fevents.length; ++en) {
if (fevents[en].no_bar) continue;
fevents[en].ts_list.push(
fp.child_profiles[instance].event_sequences[0].events[en].timestamp);
}
} else {
let en = 0, i = 0;
while(i < fevents.length && en < fp.child_profiles[instance]
.event_sequences[0].events.length) {
if (fevents[i].no_bar) {
if (fevents[i].label === fp.child_profiles[instance]
.event_sequences[0].events[en].label) { en++; }
} else if (fp.child_profiles[instance].event_sequences[0]
.events[en].label === fevents[i].label) {
fevents[i].ts_list.push(fp.child_profiles[instance].event_sequences[0]
.events[en].timestamp);
++en;
}
++i;
}
}
}
}
const fragment = {
name: fp.profile_name,
events: fevents,
nodes: [ ],
color: fragment_colors[color_idx]
}
// Pick a new color for each plan fragment
color_idx = (color_idx + 1) % fragment_colors.length;
set_maxts(Math.max(maxts, fevents[fevents.length - 1].timestamp));
max_namelen = Math.max(max_namelen, fp.profile_name.length);
const node_path = [];
const node_stack = [];
let node_name;
cp.child_profiles.forEach(function get_plan_nodes(pp, index) {
if (pp.node_metadata === undefined) return;
node_path.push(index);
// pp.profile_name : "AGGREGATION_NODE (id=52)"
let name_flds = pp.profile_name.split(/[()]/);
// name_flds : ["AGGREGATION_NODE ", "id=52", ""]
let node_type = name_flds[0].trim();
// node_type: "AGGREGATION_NODE"
let node_id = name_flds.length > 1 ?
parseInt(name_flds[1].split(/[=]/)[1]) : 0;
// node_id: 52
node_name = pp.profile_name.replace("_NODE", "").replace("_", " ")
.replace("KrpcDataStreamSender", "SENDER")
.replace("Hash Join Builder", "JOIN BUILD")
.replace("join node_", "");
if (node_type.indexOf("SCAN_NODE") >= 0) {
let table_name = pp.info_strings.find(({ key }) => key === "Table Name")
.value.split(/[.]/);
node_name = node_name.replace("SCAN",
`SCAN [${table_name[table_name.length - 1]}]`);
}
const IS_RECEIVER = node_type === "EXCHANGE_NODE" ||
(node_type === "HASH_JOIN_NODE" && pp.num_children < 3);
const IS_SENDER = (node_type === "Hash Join Builder" ||
node_type === "KrpcDataStreamSender");
let parent_node;
if (node_type === "PLAN_ROOT_SINK") {}
else if (pp.node_metadata.data_sink_id !== undefined) {
parent_node = receiver_nodes[node_id]; // Exchange sender dst
} else if (pp.node_metadata.join_build_id !== undefined) {
parent_node = receiver_nodes[node_id]; // Join sender dst
} else if (node_stack.length > 0) {
parent_node = node_stack[node_stack.length - 1];
} else if (all_nodes.length) {
parent_node = all_nodes[all_nodes.length - 1];
}
max_namelen = Math.max(max_namelen, node_name.length + node_stack.length + 1);
let node_events;
if (pp.event_sequences !== undefined) {
node_events = pp.event_sequences[0].events;
// Start the instance event list for each event with timestamps
// from this instance
for (let en = 0; en < node_events.length; ++en) {
node_events[en].ts_list = [ node_events[en].timestamp ];
if ((node_type === "HASH_JOIN_NODE" ||
node_type === "NESTED_LOOP_JOIN_NODE") && (en === 1 || en === 2)) {
node_events[en].no_bar = true;
}
}
}
let node = {
name: node_name,
type: node_type,
node_id: node_id,
num_children: 0,
child_index: 0,
metadata: pp.node_metadata,
parent_node: parent_node,
events: node_events,
path: node_path.slice(0),
is_receiver: IS_RECEIVER,
is_sender: IS_SENDER
}
if (IS_SENDER) {
node.parent_node.sender_frag_index = fragments.length;
}
if (IS_RECEIVER) {
receiver_nodes[node_id] = node;
}
if (parent_node !== undefined) {
node.child_index = parent_node.num_children++;
}
all_nodes.push(node);
fragment.nodes.push(node);
if (pp.child_profiles !== undefined) {
node_stack.push(node);
pp.child_profiles.forEach(get_plan_nodes);
node = node_stack.pop();
}
rownum++;
node_path.pop();
});
// For each node, retrieve the instance timestamps for the remaining instances
for (let ni = 0; ni < fragment.nodes.length; ++ni) {
const node = fragment.nodes[ni];
for (let cpn = 1; cpn < fp.child_profiles.length; ++cpn) {
cp = fp.child_profiles[cpn];
// Use the saved node path to traverse to the same position in this instance
for (let pi = 0; pi < node.path.length; ++pi) {
cp = cp.child_profiles[node.path[pi]];
}
console.assert(cp.node_metadata.data_sink_id === undefined ||
cp.profile_name.indexOf(`(dst_id=${node.node_id})`));
console.assert(cp.node_metadata.plan_node_id === undefined ||
cp.node_metadata.plan_node_id === node.node_id);
// Add instance events to this node
if (cp.event_sequences !== undefined) {
if (node.events.length === cp.event_sequences[0].events.length) {
for (let en = 0; en < node.events.length; ++en) {
node.events[en].ts_list.push(cp.event_sequences[0].events[en].timestamp);
}
} else {
let i = 0, en = 0;
while(i < node.events.length && en < cp.event_sequences[0].events.length) {
if (node.events[i].label === cp.event_sequences[0].events[en].label) {
node.events[i].ts_list.push(cp.event_sequences[0].events[en].timestamp);
++en; ++i;
} else {
++i;
}
}
}
}
}
}
fragments.push(fragment);
}
});
frag_name_width = (Math.max(2, (fragments.length - 1).toString().length) + 3)
* CHAR_WIDTH;
name_width = max_namelen * CHAR_WIDTH + (frag_name_width + 2);
fragment_events_parse_successful = true;
} catch(e) {
fragment_events_parse_successful = false;
console.log(e);
}
}