From c13b49262d5ee5049d34d2781d319fbc9ac578d8 Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Thu, 30 Dec 2021 01:47:45 +0000 Subject: [PATCH] Renderers: Make appending rows massively more efficient Previously we were generating the list of children (for most likely the root node) for every single append statement, during which we were recalculating the length of the list, twice. In plugins that output a lot of rows this would add an enourmous overhead (that likely grew as the length of the output grew). Without this overhead, the time taken for the TreeGrid._append method went from 1230.0s to 2.4s. --- volatility3/framework/renderers/__init__.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/volatility3/framework/renderers/__init__.py b/volatility3/framework/renderers/__init__.py index de1b14c91..5773861d9 100644 --- a/volatility3/framework/renderers/__init__.py +++ b/volatility3/framework/renderers/__init__.py @@ -272,20 +272,26 @@ class TreeGrid(interfaces.renderers.TreeGrid): def _append(self, parent: Optional[interfaces.renderers.TreeNode], values: Any) -> TreeNode: """Adds a new node at the top level if parent is None, or under the parent node otherwise, after all other children.""" - children = self.children(parent) - return self._insert(parent, len(children), values) + return self._insert(parent, None, values) - def _insert(self, parent: Optional[interfaces.renderers.TreeNode], position: int, values: Any) -> TreeNode: + def _insert(self, parent: Optional[interfaces.renderers.TreeNode], position: Optional[int], values: Any) -> TreeNode: """Inserts an element into the tree at a specific position.""" parent_path = "" children = self._find_children(parent) if parent is not None: parent_path = parent.path + self.path_sep - newpath = parent_path + str(position) + if position is None: + newpath = parent_path + str(len(children)) + else: + newpath = parent_path + str(position) + for node, _ in children[position:]: + self.visit(node, lambda child, _: child.path_changed(newpath, True), None) + tree_item = TreeNode(newpath, self, parent, values) - for node, _ in children[position:]: - self.visit(node, lambda child, _: child.path_changed(newpath, True), None) - children.insert(position, (tree_item, [])) + if position is None: + children.append((tree_item, [])) + else: + children.insert(position, (tree_item, [])) return tree_item def is_ancestor(self, node, descendant):