diff --git a/shared/source/device_binary_format/yaml/yaml_parser.cpp b/shared/source/device_binary_format/yaml/yaml_parser.cpp index 20bbc36843..10b14e06a7 100644 --- a/shared/source/device_binary_format/yaml/yaml_parser.cpp +++ b/shared/source/device_binary_format/yaml/yaml_parser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Intel Corporation + * Copyright (C) 2020-2021 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -22,6 +22,7 @@ std::string constructYamlError(size_t lineNumber, const char *lineBeg, const cha } inline Node &addNode(NodesCache &outNodes, Node &parent) { + UNRECOVERABLE_IF(outNodes.size() >= outNodes.capacity()); // resize must not grow parent.firstChildId = static_cast(outNodes.size()); parent.lastChildId = static_cast(outNodes.size()); outNodes.resize(outNodes.size() + 1); @@ -33,6 +34,7 @@ inline Node &addNode(NodesCache &outNodes, Node &parent) { } inline Node &addNode(NodesCache &outNodes, Node &prevSibling, Node &parent) { + UNRECOVERABLE_IF(outNodes.size() >= outNodes.capacity()); // resize must not grow prevSibling.nextSiblingId = static_cast(outNodes.size()); outNodes.resize(outNodes.size() + 1); auto &curr = *outNodes.rbegin(); @@ -116,6 +118,7 @@ bool tokenize(ConstStringRef text, LinesCache &outLines, TokensCache &outTokens, context.isParsingIdent = true; while (context.pos < context.end) { + reserveBasedOnEstimates(outTokens, text.begin(), text.end(), context.pos); switch (context.pos[0]) { case ' ': context.lineIndent += context.isParsingIdent ? 1 : 0; @@ -149,6 +152,7 @@ bool tokenize(ConstStringRef text, LinesCache &outLines, TokensCache &outTokens, break; } case '\n': { + reserveBasedOnEstimates(outLines, text.begin(), text.end(), context.pos); if (false == tokenizeEndLine(text, outLines, outTokens, outErrReason, outWarning, context)) { return false; } @@ -245,6 +249,7 @@ bool tokenize(ConstStringRef text, LinesCache &outLines, TokensCache &outTokens, } void finalizeNode(NodeId nodeId, const TokensCache &tokens, NodesCache &outNodes, std::string &outErrReason, std::string &outWarning) { + outNodes.reserve(outNodes.size() + 1); auto &node = outNodes[nodeId]; if (invalidTokenId != node.key) { return; @@ -290,14 +295,17 @@ bool buildTree(const LinesCache &lines, const TokensCache &tokens, NodesCache &o ++lineId; continue; } + reserveBasedOnEstimates(outNodes, static_cast(0), static_cast(tokens.size()), lines[lineId].first); auto currLineIndent = lines[lineId].indent; if (currLineIndent == outNodes.rbegin()->indent) { + outNodes.reserve(outNodes.size() + 1); auto &prev = *outNodes.rbegin(); auto &parent = outNodes[*nesting.rbegin()]; auto &curr = addNode(outNodes, prev, parent); curr.indent = currLineIndent; } else if (currLineIndent > outNodes.rbegin()->indent) { + outNodes.reserve(outNodes.size() + 1); auto &parent = *outNodes.rbegin(); auto &curr = addNode(outNodes, parent); curr.indent = currLineIndent; @@ -313,6 +321,7 @@ bool buildTree(const LinesCache &lines, const TokensCache &tokens, NodesCache &o outErrReason = constructYamlError(lineId, tokens[lines[lineId].first].pos, tokens[lines[lineId].first].pos + 1, "Invalid indentation"); return false; } else { + outNodes.reserve(outNodes.size() + 1); auto &prev = outNodes[*nesting.rbegin()]; auto &parent = outNodes[prev.parentId]; auto &curr = addNode(outNodes, prev, parent); diff --git a/shared/source/device_binary_format/yaml/yaml_parser.h b/shared/source/device_binary_format/yaml/yaml_parser.h index b18c08000c..b9331b71be 100644 --- a/shared/source/device_binary_format/yaml/yaml_parser.h +++ b/shared/source/device_binary_format/yaml/yaml_parser.h @@ -236,6 +236,18 @@ struct Line { }; static_assert(sizeof(Line) == 12, ""); +template +inline bool reserveBasedOnEstimates(T &container, It beg, It end, It pos) { + if ((container.size() < container.capacity()) || (pos == beg)) { + return false; + } + DEBUG_BREAK_IF((beg > end) || (pos < beg)); + auto normalizedPosInv = float(end - beg) / float(pos - beg); + auto estimatedTotalElements = static_cast(container.size() * normalizedPosInv); + container.reserve(estimatedTotalElements); + return true; +} + using TokensCache = StackVec; using LinesCache = StackVec; @@ -243,18 +255,18 @@ std::string constructYamlError(size_t lineNumber, const char *lineBeg, const cha bool tokenize(ConstStringRef text, LinesCache &outLines, TokensCache &outTokens, std::string &outErrReason, std::string &outWarning); -using NodeId = uint16_t; +using NodeId = uint32_t; static constexpr NodeId invalidNodeID = std::numeric_limits::max(); -struct Node { +struct alignas(32) Node { TokenId key = invalidTokenId; TokenId value = invalidTokenId; - uint32_t indent = 0; NodeId id = invalidNodeID; NodeId parentId = invalidNodeID; NodeId firstChildId = invalidNodeID; NodeId lastChildId = invalidNodeID; NodeId nextSiblingId = invalidNodeID; + uint16_t indent = 0; uint16_t numChildren = 0U; Node() = default; @@ -262,7 +274,7 @@ struct Node { explicit Node(uint32_t indent) : indent(indent) { } }; -static_assert(sizeof(Node) == 24, ""); +static_assert(sizeof(Node) == 32, ""); using NodesCache = StackVec; constexpr bool isUnused(Line::LineType lineType) { diff --git a/shared/test/unit_test/device_binary_format/yaml/yaml_parser_tests.cpp b/shared/test/unit_test/device_binary_format/yaml/yaml_parser_tests.cpp index df98445afc..b90c655a48 100644 --- a/shared/test/unit_test/device_binary_format/yaml/yaml_parser_tests.cpp +++ b/shared/test/unit_test/device_binary_format/yaml/yaml_parser_tests.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Intel Corporation + * Copyright (C) 2020-2021 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -2886,4 +2886,38 @@ kernels: EXPECT_EQ(0U, argIndex); } } -} \ No newline at end of file +} + +TEST(ReserveBasedOnEstimates, WhenContainerNotFullThenDontGrow) { + StackVec container; + size_t beg = 0U; + size_t pos = 10U; + size_t end = 1000U; + bool reservedAdditionalMem = reserveBasedOnEstimates(container, beg, end, pos); + EXPECT_FALSE(reservedAdditionalMem); + EXPECT_EQ(7U, container.capacity()); +} + +TEST(ReserveBasedOnEstimates, WhenContainerFullButPosIsBegThenDontGrow) { + StackVec container; + container.resize(7U); + ASSERT_EQ(container.capacity(), container.size()); + size_t beg = 0U; + size_t pos = 0U; + size_t end = 1000U; + bool reservedAdditionalMem = reserveBasedOnEstimates(container, beg, end, pos); + EXPECT_FALSE(reservedAdditionalMem); + EXPECT_EQ(7U, container.capacity()); +} + +TEST(ReserveBasedOnEstimates, WhenContainerFullThenGrowBasedOnPos) { + StackVec container; + container.resize(7U); + ASSERT_EQ(container.capacity(), container.size()); + size_t beg = 0U; + size_t pos = 25U; + size_t end = 1000U; + bool reservedAdditionalMem = reserveBasedOnEstimates(container, beg, end, pos); + EXPECT_TRUE(reservedAdditionalMem); + EXPECT_EQ(280U, container.capacity()); +}