diff --git a/third_party/proton/csrc/lib/Data/TreeData.cpp b/third_party/proton/csrc/lib/Data/TreeData.cpp index 4b395a77edd8..6ed0b67a80d5 100644 --- a/third_party/proton/csrc/lib/Data/TreeData.cpp +++ b/third_party/proton/csrc/lib/Data/TreeData.cpp @@ -712,10 +712,22 @@ TreeData::buildHatchetMsgPack(TreeData::Tree *tree, } } } - writer.packFixStrLiteral("children"); - writer.packArray(static_cast(virtualNode.children.size())); + // Linked flexible metrics attached to generated helper leaves are promoted + // into the parent metrics map above. Once promoted, a helper leaf with no + // linked fixed metrics and no children carries no information in Hatchet. + std::vector linkedChildren; + linkedChildren.reserve(virtualNode.children.size()); for (const auto &child : virtualNode.children) { - packLinkedVirtualNode(packLinkedVirtualNode, treeNode, child.id); + const auto &childNode = virtualTree->getNode(child.id); + if (!childNode.children.empty() || + linkedMetrics.find(child.id) != linkedMetrics.end()) { + linkedChildren.push_back(child.id); + } + } + writer.packFixStrLiteral("children"); + writer.packArray(static_cast(linkedChildren.size())); + for (auto childId : linkedChildren) { + packLinkedVirtualNode(packLinkedVirtualNode, treeNode, childId); } }; auto packNode = [&](auto &&packNode, @@ -737,11 +749,27 @@ TreeData::buildHatchetMsgPack(TreeData::Tree *tree, hasLinkedTargets ? static_cast(virtualRootNode.children.size()) : 0; + // CUDA stream capture can create concrete launch-name leaves before the + // launch callback exits early without correlating metrics. Graph replay + // metrics are attached through linked virtual nodes instead, so a concrete + // leaf with no metrics, linked metrics, flexible metrics, or children adds + // no Hatchet information. + std::vector concreteChildren; + concreteChildren.reserve(treeNode.children.size()); + for (const auto &child : treeNode.children) { + auto &childNode = tree->getNode(child.id); + if (!childNode.children.empty() || !childNode.metricSet.metrics.empty() || + !childNode.metricSet.flexibleMetrics.empty() || + !childNode.metricSet.linkedMetrics.empty() || + !childNode.metricSet.linkedFlexibleMetrics.empty()) { + concreteChildren.push_back(&childNode); + } + } writer.packFixStrLiteral("children"); - writer.packArray(static_cast(treeNode.children.size()) + + writer.packArray(static_cast(concreteChildren.size()) + linkedChildCount); - for (const auto &child : treeNode.children) { - packNode(packNode, tree->getNode(child.id)); + for (auto *childNode : concreteChildren) { + packNode(packNode, *childNode); } if (hasLinkedTargets) { for (const auto &virtualChild : virtualRootNode.children) {