From 5a189628352869e86aa8f06554fd40b9ea72268c Mon Sep 17 00:00:00 2001 From: wj32 Date: Sat, 5 Sep 2009 04:16:46 +0000 Subject: [PATCH] partially rewrote the process tree model; improves memory and CPU usage git-svn-id: svn://svn.code.sf.net/p/processhacker/code@1846 21ef857c-d57f-4fe0-8362-d861dc6d29cd --- trunk/CHANGELOG.txt | 1 + .../Components/ProcessTree/ProcessNode.cs | 30 +++++ .../ProcessTree/ProcessTreeModel.cs | 103 +++++++++--------- .../Providers/ProcessSystemProvider.cs | 2 +- 4 files changed, 81 insertions(+), 55 deletions(-) diff --git a/trunk/CHANGELOG.txt b/trunk/CHANGELOG.txt index 10763b6c1..f8d5f5011 100644 --- a/trunk/CHANGELOG.txt +++ b/trunk/CHANGELOG.txt @@ -10,6 +10,7 @@ Process Hacker * Two new terminator tests: W1 (send WM_DESTROY messages) and W2 (send WM_QUIT messages) * Elevation prompt when attempting to view process properties + * Decreased memory and CPU usage * FIXED: * #2820170 - "System.ArgumentOutOfRangeException in network list" * #2845427 - "Indicator integer overflow" diff --git a/trunk/ProcessHacker/Components/ProcessTree/ProcessNode.cs b/trunk/ProcessHacker/Components/ProcessTree/ProcessNode.cs index 3127dfe58..c54c76ba2 100644 --- a/trunk/ProcessHacker/Components/ProcessTree/ProcessNode.cs +++ b/trunk/ProcessHacker/Components/ProcessTree/ProcessNode.cs @@ -34,7 +34,10 @@ namespace ProcessHacker { public class ProcessNode : Node, IDisposable { + private ProcessNode _parent = null; private List _children = new List(); + private TreePath _treePath = null; + private ProcessItem _pitem; private bool _wasNoIcon = false; private Bitmap _icon; @@ -108,11 +111,38 @@ namespace ProcessHacker } } + public ProcessNode Parent + { + get { return _parent; } + set { _parent = value; } + } + public List Children { get { return _children; } } + public TreePath TreePath + { + get { return _treePath; } + } + + public TreePath RefreshTreePath() + { + ProcessNode currentNode = this; + Stack stack = new Stack(); + + while (currentNode != null) + { + stack.Push(currentNode); + currentNode = currentNode.Parent; + } + + _treePath = new TreePath(stack.ToArray()); + + return _treePath; + } + public ProcessHacker.Components.NodePlotter.PlotterInfo CpuHistory { get diff --git a/trunk/ProcessHacker/Components/ProcessTree/ProcessTreeModel.cs b/trunk/ProcessHacker/Components/ProcessTree/ProcessTreeModel.cs index eee8afb96..be26ae727 100644 --- a/trunk/ProcessHacker/Components/ProcessTree/ProcessTreeModel.cs +++ b/trunk/ProcessHacker/Components/ProcessTree/ProcessTreeModel.cs @@ -50,10 +50,16 @@ namespace ProcessHacker { ProcessNode itemNode = new ProcessNode(item); + // Add the process to the list of all processes. + _processes.Add(item.Pid, itemNode); + // Find the process' parent and add the process to it if we found it. if (item.HasParent && _processes.ContainsKey(item.ParentPid)) { - _processes[item.ParentPid].Children.Add(itemNode); + ProcessNode parent = _processes[item.ParentPid]; + + parent.Children.Add(itemNode); + itemNode.Parent = parent; } else { @@ -61,18 +67,27 @@ namespace ProcessHacker _roots.Add(itemNode); } - // Add the process to the list of all processes. - _processes.Add(item.Pid, itemNode); + itemNode.RefreshTreePath(); - // Find this process' children and add them. + // Find this process' children and fix them up. + + // We need to create a copy of the array because we may need + // to modify the roots list. ProcessNode[] roots = _roots.ToArray(); foreach (ProcessNode node in roots) { - if (node.ProcessItem.HasParent && node.PPid == item.Pid) + // Notice that we don't replace a node's parent if it + // already has one. This is to break potential cyclic + // references. + if (node.Parent == null && node.ProcessItem.HasParent && node.PPid == item.Pid) { + // Remove the node from the root list and add it to our + // process' child list. _roots.Remove(node); itemNode.Children.Add(node); + node.Parent = itemNode; + node.RefreshTreePath(); } } @@ -93,35 +108,31 @@ namespace ProcessHacker public void Remove(ProcessItem item) { - ProcessNode targetNode = _processes[item.Pid]; - ProcessNode[] targetChildren = null; + ProcessNode itemNode = _processes[item.Pid]; + ProcessNode[] itemChildren = null; // Dispose of the process node we're removing. - targetNode.Dispose(); + itemNode.Dispose(); - // Check if the process is a root. - ProcessNode rootNode = _roots.Find(node => node.Pid == item.Pid); + itemChildren = itemNode.Children.ToArray(); - if (rootNode != null) + // Check if the node has a parent. + if (itemNode.Parent == null) { - // Remove the process from the roots and make its children root nodes. - _roots.Remove(rootNode); - this.MoveChildrenToRoot(rootNode); + if (_roots.Contains(itemNode)) + { + // Remove the process from the roots and make its children root nodes. + _roots.Remove(itemNode); + this.MoveChildrenToRoot(itemNode); + } } else { - // The process isn't a root, so we have to search for the process' parent. - if (targetNode.ProcessItem.HasParent && _processes.ContainsKey(targetNode.PPid)) + if (itemNode.Parent.Children.Contains(itemNode)) { - ProcessNode parentNode = _processes[targetNode.PPid]; - - if (parentNode != null) - { - // Remove the node from its parent and make its children root nodes. - parentNode.Children.Remove(targetNode); - targetChildren = targetNode.Children.ToArray(); - this.MoveChildrenToRoot(targetNode); - } + // Remove the node from its parent and make its children root nodes. + itemNode.Parent.Children.Remove(itemNode); + this.MoveChildrenToRoot(itemNode); } } @@ -130,9 +141,9 @@ namespace ProcessHacker this.StructureChanged(this, new TreePathEventArgs(new TreePath())); // Expand the children because TreeViewAdv collapses them by default. - if (targetChildren != null) + if (itemChildren != null) { - foreach (ProcessNode n in targetChildren) + foreach (ProcessNode n in itemChildren) { try { @@ -150,38 +161,16 @@ namespace ProcessHacker public TreePath GetPath(ProcessNode node) { - if (this.GetSortColumn() != "") - return new TreePath(node); - if (node == null) - { return TreePath.Empty; + + if (this.GetSortColumn() != "") + { + return new TreePath(node); } else { - ProcessNode currentNode = node; - Stack stack = new Stack(); - - while (true) - { - stack.Push(currentNode); - - if (currentNode.ProcessItem.HasParent && _processes.ContainsKey(currentNode.PPid)) - { - ProcessNode newNode = _processes[currentNode.PPid]; - - if (newNode == currentNode) - break; - - currentNode = newNode; - } - else - { - break; - } - } - - return new TreePath(stack.ToArray()); + return node.TreePath; } } @@ -189,6 +178,12 @@ namespace ProcessHacker { ProcessNode[] children = node.Children.ToArray(); + foreach (ProcessNode child in children) + { + child.Parent = null; + child.RefreshTreePath(); + } + _roots.AddRange(children); } diff --git a/trunk/ProcessHacker/Providers/ProcessSystemProvider.cs b/trunk/ProcessHacker/Providers/ProcessSystemProvider.cs index 42212c3d1..484d1ceaa 100644 --- a/trunk/ProcessHacker/Providers/ProcessSystemProvider.cs +++ b/trunk/ProcessHacker/Providers/ProcessSystemProvider.cs @@ -949,7 +949,7 @@ namespace ProcessHacker item.ParentPid = processInfo.InheritedFromProcessId; item.HasParent = true; - if (!procs.ContainsKey(item.ParentPid)) + if (!procs.ContainsKey(item.ParentPid) || item.ParentPid == pid) { item.HasParent = false; }