Skip to content

Commit d070129

Browse files
brianrobdrewnoakes
andauthored
Add Support for Selecting Process Trees (#2195)
* Add support for selecting process trees * Child --> Descendant Update checkbox text. Co-authored-by: Drew Noakes <git@drewnoakes.com> --------- Co-authored-by: Drew Noakes <git@drewnoakes.com>
1 parent 5dc7b2b commit d070129

3 files changed

Lines changed: 87 additions & 4 deletions

File tree

build.cmd

100644100755
File mode changed.

src/PerfView/Dialogs/SelectProcess.xaml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
</Grid>
4242
<Grid DockPanel.Dock="Bottom" Background="{DynamicResource BackgroundColour}" >
4343
<Grid.ColumnDefinitions>
44+
<ColumnDefinition Width="Auto"/>
4445
<ColumnDefinition Width="*"/>
4546
<ColumnDefinition Width="Auto"/>
4647
<ColumnDefinition Width="*"/>
@@ -50,10 +51,12 @@
5051
<ColumnDefinition Width="*"/>
5152
<ColumnDefinition Width="Auto"/>
5253
</Grid.ColumnDefinitions>
53-
<Button Name="OKButton" Margin="5,4" Grid.Column="1" MinWidth="80" Content="OK" Click="OKClicked" IsDefault="True" />
54-
<Button Name="AllProcsButton" Margin="5,4" Grid.Column="3" MinWidth="80" Content="All Procs" Click="AllProcsClicked"
54+
<CheckBox Name="IncludeChildProcessesCheckBox" Grid.Column="0" Margin="5,0,0,0" VerticalAlignment="Center"
55+
ToolTip="Include all descendant processes of selected processes">Include descendant processes</CheckBox>
56+
<Button Name="OKButton" Margin="5,4" Grid.Column="2" MinWidth="80" Content="OK" Click="OKClicked" IsDefault="True" />
57+
<Button Name="AllProcsButton" Margin="5,4" Grid.Column="4" MinWidth="80" Content="All Procs" Click="AllProcsClicked"
5558
ToolTip="Investigate all processes"/>
56-
<Button Margin="5,4" Grid.Column="5" MinWidth="80" Content="Cancel" Click="CancelClicked" IsCancel="True" />
59+
<Button Margin="5,4" Grid.Column="6" MinWidth="80" Content="Cancel" Click="CancelClicked" IsCancel="True" />
5760
</Grid>
5861
<Grid PreviewKeyDown="GridKeyDownHander">
5962
<WPFToolKit:DataGrid Name="Grid"

src/PerfView/Dialogs/SelectProcess.xaml.cs

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,15 +132,95 @@ internal void OKClicked(object sender, RoutedEventArgs e)
132132
SystemSounds.Beep.Play();
133133
return;
134134
}
135+
135136
var ret = new List<IProcess>();
137+
var selectedProcesses = new List<IProcess>();
138+
139+
// Add explicitly selected processes
136140
foreach (var item in items)
137141
{
138-
ret.Add((IProcess)item);
142+
var process = (IProcess)item;
143+
selectedProcesses.Add(process);
144+
ret.Add(process);
145+
}
146+
147+
// If checkbox is checked, add child processes
148+
if (IncludeChildProcessesCheckBox.IsChecked == true)
149+
{
150+
// Build dictionaries for process lookup
151+
Dictionary<int, IProcess> processById = new Dictionary<int, IProcess>();
152+
Dictionary<int, List<int>> childrenByParentId = new Dictionary<int, List<int>>();
153+
154+
// First pass: build process ID mapping
155+
foreach (var process in m_processes)
156+
{
157+
processById[process.ProcessID] = process;
158+
159+
// Initialize empty children list for each parent
160+
if (!childrenByParentId.ContainsKey(process.ParentID))
161+
{
162+
childrenByParentId[process.ParentID] = new List<int>();
163+
}
164+
165+
// Add this process as a child of its parent
166+
childrenByParentId[process.ParentID].Add(process.ProcessID);
167+
}
168+
169+
// Add all transitive children of selected processes
170+
HashSet<int> addedProcessIds = new HashSet<int>();
171+
foreach (var process in selectedProcesses)
172+
{
173+
addedProcessIds.Add(process.ProcessID); // Mark selected processes as already added
174+
}
175+
176+
// For each selected process, add all its descendants
177+
foreach (var process in selectedProcesses)
178+
{
179+
AddChildProcesses(process.ProcessID, processById, childrenByParentId, ret, addedProcessIds);
180+
}
139181
}
140182

141183
m_action(ret);
142184
Close();
143185
}
186+
187+
private void AddChildProcesses(
188+
int processId,
189+
Dictionary<int, IProcess> processById,
190+
Dictionary<int, List<int>> childrenByParentId,
191+
List<IProcess> resultList,
192+
HashSet<int> addedProcessIds)
193+
{
194+
// Check if this parent has any children
195+
if (!childrenByParentId.ContainsKey(processId))
196+
{
197+
return;
198+
}
199+
200+
// For each child process
201+
foreach (var childId in childrenByParentId[processId])
202+
{
203+
// Skip if already added (prevents potential infinite recursion if process tree has cycles)
204+
if (addedProcessIds.Contains(childId))
205+
{
206+
continue;
207+
}
208+
209+
// Skip if the process doesn't exist in our dictionary (shouldn't happen)
210+
if (!processById.ContainsKey(childId))
211+
{
212+
continue;
213+
}
214+
215+
// Add the child process to the result list
216+
var childProcess = processById[childId];
217+
resultList.Add(childProcess);
218+
addedProcessIds.Add(childId);
219+
220+
// Recursively add its children
221+
AddChildProcesses(childId, processById, childrenByParentId, resultList, addedProcessIds);
222+
}
223+
}
144224
private void DoHyperlinkHelp(object sender, ExecutedRoutedEventArgs e)
145225
{
146226
MainWindow.DisplayUsersGuide(e.Parameter as string);

0 commit comments

Comments
 (0)