From 87e93676b2b3dd9f0595a81a603ed1f726a42f9b Mon Sep 17 00:00:00 2001 From: Jokeren Date: Tue, 26 May 2026 17:49:53 -0400 Subject: [PATCH 1/6] Cache long Proton MsgPack frame headers --- .../csrc/include/Utility/MsgPackWriter.h | 1 + third_party/proton/csrc/lib/Data/TreeData.cpp | 37 +++++++++++++++---- .../proton/csrc/lib/Utility/MsgPackWriter.cpp | 6 +++ 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/third_party/proton/csrc/include/Utility/MsgPackWriter.h b/third_party/proton/csrc/include/Utility/MsgPackWriter.h index b37e3efbe954..a7472fb4177d 100644 --- a/third_party/proton/csrc/include/Utility/MsgPackWriter.h +++ b/third_party/proton/csrc/include/Utility/MsgPackWriter.h @@ -15,6 +15,7 @@ class MsgPackWriter { void reserve(size_t bytes); std::vector take() &&; + void appendBytes(const std::vector &bytes); void packNil(); void packBool(bool value); diff --git a/third_party/proton/csrc/lib/Data/TreeData.cpp b/third_party/proton/csrc/lib/Data/TreeData.cpp index 16a92c1c972c..d4be66ec6a85 100644 --- a/third_party/proton/csrc/lib/Data/TreeData.cpp +++ b/third_party/proton/csrc/lib/Data/TreeData.cpp @@ -461,15 +461,36 @@ TreeData::buildHatchetMsgPack(TreeData::Tree *tree, } }); const auto &virtualRootNode = virtualTree->getNode(Tree::TreeNode::RootId); + auto packUncachedHatchetFrameHeader = [](MsgPackWriter &out, + std::string_view name) { + out.packMap(3); + out.packFixStrLiteral("frame"); + out.packMap(2); + out.packFixStrLiteral("name"); + out.packStr(name); + out.packFixStrLiteral("type"); + out.packFixStrLiteral("function"); + out.packFixStrLiteral("metrics"); + }; + // Names that fit in MsgPack fixstr are cheap enough to encode directly. Cache + // only longer headers so repeated linked virtual frames can skip the larger + // string copy without adding hash-table overhead to every small frame name. + constexpr size_t kCachedFrameHeaderMinNameBytes = 32; + std::unordered_map> frameHeaderCache; auto packHatchetFrameHeader = [&](std::string_view name) { - writer.packMap(3); - writer.packFixStrLiteral("frame"); - writer.packMap(2); - writer.packFixStrLiteral("name"); - writer.packStr(name); - writer.packFixStrLiteral("type"); - writer.packFixStrLiteral("function"); - writer.packFixStrLiteral("metrics"); + if (name.size() < kCachedFrameHeaderMinNameBytes) { + packUncachedHatchetFrameHeader(writer, name); + return; + } + + auto it = frameHeaderCache.find(name); + if (it == frameHeaderCache.end()) { + MsgPackWriter headerWriter; + headerWriter.reserve(32 + name.size()); + packUncachedHatchetFrameHeader(headerWriter, name); + it = frameHeaderCache.emplace(name, std::move(headerWriter).take()).first; + } + writer.appendBytes(it->second); }; // Root metrics only carry inclusive aggregate fields. Non-root metrics also diff --git a/third_party/proton/csrc/lib/Utility/MsgPackWriter.cpp b/third_party/proton/csrc/lib/Utility/MsgPackWriter.cpp index 8d89dbe9c3f3..d22943bdbd01 100644 --- a/third_party/proton/csrc/lib/Utility/MsgPackWriter.cpp +++ b/third_party/proton/csrc/lib/Utility/MsgPackWriter.cpp @@ -22,6 +22,12 @@ void MsgPackWriter::reserve(size_t bytes) { out.reserve(bytes); } std::vector MsgPackWriter::take() && { return std::move(out); } +void MsgPackWriter::appendBytes(const std::vector &bytes) { + const auto offset = out.size(); + out.resize(offset + bytes.size()); + std::memcpy(out.data() + offset, bytes.data(), bytes.size()); +} + void MsgPackWriter::packNil() { out.push_back(0xc0); } void MsgPackWriter::packBool(bool value) { out.push_back(value ? 0xc3 : 0xc2); } From 07056fb09510c617fb49d081bea6b66455d022c4 Mon Sep 17 00:00:00 2001 From: Jokeren Date: Tue, 26 May 2026 18:24:45 -0400 Subject: [PATCH 2/6] Avoid extra writer for cached frame headers --- .../proton/csrc/include/Utility/MsgPackWriter.h | 2 ++ third_party/proton/csrc/lib/Data/TreeData.cpp | 17 +++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/third_party/proton/csrc/include/Utility/MsgPackWriter.h b/third_party/proton/csrc/include/Utility/MsgPackWriter.h index a7472fb4177d..b5fa242a2a11 100644 --- a/third_party/proton/csrc/include/Utility/MsgPackWriter.h +++ b/third_party/proton/csrc/include/Utility/MsgPackWriter.h @@ -13,6 +13,8 @@ namespace proton { class MsgPackWriter { public: void reserve(size_t bytes); + size_t size() const { return out.size(); } + const uint8_t *data() const { return out.data(); } std::vector take() &&; void appendBytes(const std::vector &bytes); diff --git a/third_party/proton/csrc/lib/Data/TreeData.cpp b/third_party/proton/csrc/lib/Data/TreeData.cpp index d4be66ec6a85..9ef59d424b6f 100644 --- a/third_party/proton/csrc/lib/Data/TreeData.cpp +++ b/third_party/proton/csrc/lib/Data/TreeData.cpp @@ -484,13 +484,18 @@ TreeData::buildHatchetMsgPack(TreeData::Tree *tree, } auto it = frameHeaderCache.find(name); - if (it == frameHeaderCache.end()) { - MsgPackWriter headerWriter; - headerWriter.reserve(32 + name.size()); - packUncachedHatchetFrameHeader(headerWriter, name); - it = frameHeaderCache.emplace(name, std::move(headerWriter).take()).first; + if (it != frameHeaderCache.end()) { + writer.appendBytes(it->second); + return; } - writer.appendBytes(it->second); + + const auto offset = writer.size(); + packUncachedHatchetFrameHeader(writer, name); + std::vector headerBytes; + headerBytes.reserve(kCachedFrameHeaderMinNameBytes + name.size()); + headerBytes.insert(headerBytes.end(), writer.data() + offset, + writer.data() + writer.size()); + frameHeaderCache.emplace(name, std::move(headerBytes)); }; // Root metrics only carry inclusive aggregate fields. Non-root metrics also From c12379167aeb4da808910ecd9400c116b9f80f6a Mon Sep 17 00:00:00 2001 From: Jokeren Date: Tue, 26 May 2026 18:35:17 -0400 Subject: [PATCH 3/6] Tune Proton frame header cache threshold --- third_party/proton/csrc/lib/Data/TreeData.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/proton/csrc/lib/Data/TreeData.cpp b/third_party/proton/csrc/lib/Data/TreeData.cpp index 9ef59d424b6f..6a763c8b02bb 100644 --- a/third_party/proton/csrc/lib/Data/TreeData.cpp +++ b/third_party/proton/csrc/lib/Data/TreeData.cpp @@ -475,7 +475,7 @@ TreeData::buildHatchetMsgPack(TreeData::Tree *tree, // Names that fit in MsgPack fixstr are cheap enough to encode directly. Cache // only longer headers so repeated linked virtual frames can skip the larger // string copy without adding hash-table overhead to every small frame name. - constexpr size_t kCachedFrameHeaderMinNameBytes = 32; + constexpr size_t kCachedFrameHeaderMinNameBytes = 64; std::unordered_map> frameHeaderCache; auto packHatchetFrameHeader = [&](std::string_view name) { if (name.size() < kCachedFrameHeaderMinNameBytes) { From f5d3c4ee7432a7bae688f8d669931aa599246fae Mon Sep 17 00:00:00 2001 From: Jokeren Date: Tue, 26 May 2026 18:37:22 -0400 Subject: [PATCH 4/6] Hoist linked virtual node MsgPack lambda --- third_party/proton/csrc/lib/Data/TreeData.cpp | 87 +++++++++---------- 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/third_party/proton/csrc/lib/Data/TreeData.cpp b/third_party/proton/csrc/lib/Data/TreeData.cpp index 6a763c8b02bb..9a8ee19d3515 100644 --- a/third_party/proton/csrc/lib/Data/TreeData.cpp +++ b/third_party/proton/csrc/lib/Data/TreeData.cpp @@ -693,6 +693,48 @@ TreeData::buildHatchetMsgPack(TreeData::Tree *tree, flexibleMetric.getValues()[0]); } }; + auto packLinkedVirtualNode = [&](auto &&packLinkedVirtualNode, + const TreeData::Tree::TreeNode &treeNode, + size_t virtualNodeId) -> void { + const auto &virtualNode = virtualTree->getNode(virtualNodeId); + const auto &linkedMetrics = treeNode.metricSet.linkedMetrics; + const auto &linkedFlexibleMetrics = treeNode.metricSet.linkedFlexibleMetrics; + // Write the header + packHatchetFrameHeader(virtualNode.name); + // Count linked metrics + auto metricEntries = 0u; + const auto metricsIt = linkedMetrics.find(virtualNodeId); + if (metricsIt != linkedMetrics.end()) { + metricEntries += countMetricEntries(metricsIt->second, /*isRoot=*/false); + } + // Count linked flexible metrics exist in the child helpers + if (!linkedFlexibleMetrics.empty()) { + for (const auto &child : virtualNode.children) { + auto it = linkedFlexibleMetrics.find(child.id); + if (it != linkedFlexibleMetrics.end()) { + metricEntries += static_cast(it->second.size()); + } + } + } + // Pack + writer.packMap(metricEntries); + if (metricsIt != linkedMetrics.end()) { + packMetrics(metricsIt->second, /*isRoot=*/false); + } + if (!linkedFlexibleMetrics.empty()) { + for (const auto &child : virtualNode.children) { + auto it = linkedFlexibleMetrics.find(child.id); + if (it != linkedFlexibleMetrics.end()) { + packFlexibleMetrics(it->second); + } + } + } + writer.packFixStrLiteral("children"); + writer.packArray(static_cast(virtualNode.children.size())); + for (const auto &child : virtualNode.children) { + packLinkedVirtualNode(packLinkedVirtualNode, treeNode, child.id); + } + }; auto packNode = [&](auto &&packNode, TreeData::Tree::TreeNode &treeNode) -> void { // Write the header @@ -705,49 +747,6 @@ TreeData::buildHatchetMsgPack(TreeData::Tree *tree, packMetrics(treeNode.metricSet.metrics, isRoot); packFlexibleMetrics(treeNode.metricSet.flexibleMetrics); - auto packLinkedVirtualNode = [&](auto &&packLinkedVirtualNode, - size_t virtualNodeId) -> void { - const auto &virtualNode = virtualTree->getNode(virtualNodeId); - auto &linkedMetrics = treeNode.metricSet.linkedMetrics; - auto &linkedFlexibleMetrics = treeNode.metricSet.linkedFlexibleMetrics; - // Write the header - packHatchetFrameHeader(virtualNode.name); - // Count linked metrics - auto metricEntries = 0u; - const auto metricsIt = linkedMetrics.find(virtualNodeId); - if (metricsIt != linkedMetrics.end()) { - metricEntries += - countMetricEntries(metricsIt->second, /*isRoot=*/false); - } - // Count linked flexible metrics exist in the child helpers - if (!linkedFlexibleMetrics.empty()) { - for (const auto &child : virtualNode.children) { - auto it = linkedFlexibleMetrics.find(child.id); - if (it != linkedFlexibleMetrics.end()) { - metricEntries += static_cast(it->second.size()); - } - } - } - // Pack - writer.packMap(metricEntries); - if (metricsIt != treeNode.metricSet.linkedMetrics.end()) { - packMetrics(metricsIt->second, /*isRoot=*/false); - } - if (!linkedFlexibleMetrics.empty()) { - for (const auto &child : virtualNode.children) { - auto it = linkedFlexibleMetrics.find(child.id); - if (it != linkedFlexibleMetrics.end()) { - packFlexibleMetrics(it->second); - } - } - } - writer.packFixStrLiteral("children"); - writer.packArray(static_cast(virtualNode.children.size())); - for (const auto &child : virtualNode.children) { - packLinkedVirtualNode(packLinkedVirtualNode, child.id); - } - }; - const bool hasLinkedTargets = !treeNode.metricSet.linkedMetrics.empty() || !treeNode.metricSet.linkedFlexibleMetrics.empty(); @@ -763,7 +762,7 @@ TreeData::buildHatchetMsgPack(TreeData::Tree *tree, } if (hasLinkedTargets) { for (const auto &virtualChild : virtualRootNode.children) { - packLinkedVirtualNode(packLinkedVirtualNode, virtualChild.id); + packLinkedVirtualNode(packLinkedVirtualNode, treeNode, virtualChild.id); } } }; From 7258673e04738d2992286adde774b207e0ffce45 Mon Sep 17 00:00:00 2001 From: Jokeren Date: Tue, 26 May 2026 18:49:23 -0400 Subject: [PATCH 5/6] Pack Proton frame header literals in bulk --- .../csrc/include/Utility/MsgPackWriter.h | 5 +++++ third_party/proton/csrc/lib/Data/TreeData.cpp | 18 +++++++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/third_party/proton/csrc/include/Utility/MsgPackWriter.h b/third_party/proton/csrc/include/Utility/MsgPackWriter.h index b5fa242a2a11..b3c42e025b51 100644 --- a/third_party/proton/csrc/include/Utility/MsgPackWriter.h +++ b/third_party/proton/csrc/include/Utility/MsgPackWriter.h @@ -18,6 +18,11 @@ class MsgPackWriter { std::vector take() &&; void appendBytes(const std::vector &bytes); + template void appendBytes(const uint8_t (&bytes)[N]) { + const auto offset = out.size(); + out.resize(offset + N); + std::memcpy(out.data() + offset, bytes, N); + } void packNil(); void packBool(bool value); diff --git a/third_party/proton/csrc/lib/Data/TreeData.cpp b/third_party/proton/csrc/lib/Data/TreeData.cpp index 9a8ee19d3515..67ab7a7b5638 100644 --- a/third_party/proton/csrc/lib/Data/TreeData.cpp +++ b/third_party/proton/csrc/lib/Data/TreeData.cpp @@ -463,14 +463,18 @@ TreeData::buildHatchetMsgPack(TreeData::Tree *tree, const auto &virtualRootNode = virtualTree->getNode(Tree::TreeNode::RootId); auto packUncachedHatchetFrameHeader = [](MsgPackWriter &out, std::string_view name) { - out.packMap(3); - out.packFixStrLiteral("frame"); - out.packMap(2); - out.packFixStrLiteral("name"); + static constexpr uint8_t kHatchetFrameHeaderPrefix[] = { + 0x83, // map(3) + 0xa5, 'f', 'r', 'a', 'm', 'e', + 0x82, // map(2) + 0xa4, 'n', 'a', 'm', 'e'}; + static constexpr uint8_t kHatchetFrameHeaderSuffix[] = { + 0xa4, 't', 'y', 'p', 'e', + 0xa8, 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n', + 0xa7, 'm', 'e', 't', 'r', 'i', 'c', 's'}; + out.appendBytes(kHatchetFrameHeaderPrefix); out.packStr(name); - out.packFixStrLiteral("type"); - out.packFixStrLiteral("function"); - out.packFixStrLiteral("metrics"); + out.appendBytes(kHatchetFrameHeaderSuffix); }; // Names that fit in MsgPack fixstr are cheap enough to encode directly. Cache // only longer headers so repeated linked virtual frames can skip the larger From 9e8bb1e6de3820a50ab5b63182c15e15f67a2eae Mon Sep 17 00:00:00 2001 From: Jokeren Date: Wed, 27 May 2026 11:42:39 -0400 Subject: [PATCH 6/6] Apply Proton cache formatting fixes --- third_party/proton/csrc/lib/Data/TreeData.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/third_party/proton/csrc/lib/Data/TreeData.cpp b/third_party/proton/csrc/lib/Data/TreeData.cpp index 67ab7a7b5638..9f4126fbc31d 100644 --- a/third_party/proton/csrc/lib/Data/TreeData.cpp +++ b/third_party/proton/csrc/lib/Data/TreeData.cpp @@ -464,14 +464,13 @@ TreeData::buildHatchetMsgPack(TreeData::Tree *tree, auto packUncachedHatchetFrameHeader = [](MsgPackWriter &out, std::string_view name) { static constexpr uint8_t kHatchetFrameHeaderPrefix[] = { - 0x83, // map(3) - 0xa5, 'f', 'r', 'a', 'm', 'e', - 0x82, // map(2) - 0xa4, 'n', 'a', 'm', 'e'}; + 0x83, // map(3) + 0xa5, 'f', 'r', 'a', 'm', 'e', + 0x82, // map(2) + 0xa4, 'n', 'a', 'm', 'e'}; static constexpr uint8_t kHatchetFrameHeaderSuffix[] = { - 0xa4, 't', 'y', 'p', 'e', - 0xa8, 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n', - 0xa7, 'm', 'e', 't', 'r', 'i', 'c', 's'}; + 0xa4, 't', 'y', 'p', 'e', 0xa8, 'f', 'u', 'n', 'c', 't', + 'i', 'o', 'n', 0xa7, 'm', 'e', 't', 'r', 'i', 'c', 's'}; out.appendBytes(kHatchetFrameHeaderPrefix); out.packStr(name); out.appendBytes(kHatchetFrameHeaderSuffix); @@ -702,7 +701,8 @@ TreeData::buildHatchetMsgPack(TreeData::Tree *tree, size_t virtualNodeId) -> void { const auto &virtualNode = virtualTree->getNode(virtualNodeId); const auto &linkedMetrics = treeNode.metricSet.linkedMetrics; - const auto &linkedFlexibleMetrics = treeNode.metricSet.linkedFlexibleMetrics; + const auto &linkedFlexibleMetrics = + treeNode.metricSet.linkedFlexibleMetrics; // Write the header packHatchetFrameHeader(virtualNode.name); // Count linked metrics