20 *
21 * 3. Neither the name of the copyright holder nor the names of its contributors may be used to
22 * endorse or promote products derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
26 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
31 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 package org.openjdk.jmc.flightrecorder.ui.pages;
34
35 import java.text.MessageFormat;
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.Collection;
39 import java.util.List;
40 import java.util.function.Predicate;
41 import java.util.function.Supplier;
42 import java.util.function.ToDoubleFunction;
43
44 import org.eclipse.jface.action.GroupMarker;
45 import org.eclipse.jface.action.IAction;
46 import org.eclipse.jface.action.MenuManager;
47 import org.eclipse.jface.resource.ImageDescriptor;
48 import org.eclipse.jface.viewers.ITreeContentProvider;
49 import org.eclipse.jface.viewers.TreeSelection;
50 import org.eclipse.jface.viewers.TreeViewer;
51 import org.eclipse.jface.viewers.Viewer;
52 import org.eclipse.swt.SWT;
53 import org.eclipse.swt.custom.SashForm;
54 import org.eclipse.swt.graphics.Color;
55 import org.eclipse.swt.graphics.RGB;
56 import org.eclipse.swt.layout.GridData;
57 import org.eclipse.swt.layout.GridLayout;
58 import org.eclipse.swt.widgets.Composite;
59 import org.eclipse.swt.widgets.Display;
121 return FlightRecorderUI.getDefault().getMCImageDescriptor(ImageConstants.PAGE_HEAP);
122 }
123
124 @Override
125 public String[] getTopics(IState state) {
126 return new String[] {JfrRuleTopics.MEMORY_LEAK_TOPIC};
127 }
128
129 @Override
130 public IDisplayablePage createPage(IPageDefinition definition, StreamModel items, IPageContainer editor) {
131 return new MemoryLeakPage(definition, items, editor);
132 }
133
134 }
135
136 private static class ReferenceTreeContentProvider extends AbstractStructuredContentProvider
137 implements ITreeContentProvider {
138
139 IRange<IQuantity> timeRange = null;
140
141 private final Predicate<ReferenceTreeObject> withinTimeRangePredicate = rto -> {
142 if (timeRange != null) {
143 return rto.getTimestamp().compareTo(timeRange.getStart()) >= 0
144 && rto.getTimestamp().compareTo(timeRange.getEnd()) <= 0;
145 }
146 return true;
147 };
148
149 @Override
150 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
151 }
152
153 @Override
154 public void dispose() {
155 }
156
157 @Override
158 public boolean hasChildren(Object element) {
159 if (element instanceof ReferenceTreeObject) {
160 ReferenceTreeObject object = (ReferenceTreeObject) element;
161 List<ReferenceTreeObject> children = object.getChildren();
162 if (timeRange != null) {
163 return children.stream().anyMatch(withinTimeRangePredicate);
164 }
165 return !children.isEmpty();
166 }
167 return false;
168 }
169
170 @Override
171 public Object getParent(Object element) {
172 if (element instanceof ReferenceTreeObject) {
173 return ((ReferenceTreeObject) element).getParent();
174 }
175 return null;
176 }
177
178 @SuppressWarnings("unchecked")
179 @Override
180 public Object[] getElements(Object inputElement) {
181 if (inputElement instanceof Collection<?>) {
182 Collection<ReferenceTreeObject> collection = (Collection<ReferenceTreeObject>) inputElement;
183 if (timeRange != null) {
184 return collection.stream().filter(withinTimeRangePredicate).toArray();
185 }
186 return collection.toArray();
187 }
188 return new Object[0];
189 }
190
191 @Override
192 public Object[] getChildren(Object element) {
193 if (element instanceof ReferenceTreeObject) {
194 ReferenceTreeObject object = (ReferenceTreeObject) element;
195 List<ReferenceTreeObject> children = object.getChildren();
196 if (timeRange != null) {
197 return children.stream().filter(withinTimeRangePredicate).toArray();
198 }
199 return children.toArray();
200 }
201 return new Object[0];
202 }
203 }
204
205 private static final IItemFilter TABLE_ITEMS = ItemFilters.type(JdkTypeIDs.OLD_OBJECT_SAMPLE);
206
207 private class MemoryLeakPageUI implements IPageUI {
208
209 private static final String OBJECT_FORMATTING_OPTIONS = "objectFormattingOptions"; //$NON-NLS-1$
210 private ReferenceTreeModel model;
211 private int objectFormattingOptions = 0b0000;
212 private final ToDoubleFunction<ReferenceTreeObject> getSelectedFraction = o -> {
213 if (model == null) {
214 return 1d;
215 }
216 return ((double) o.getItems().size()) / model.getLeakObjects().size();
217 };
231 protected Color getForegroundTyped(ReferenceTreeObject object) {
232 if (object.getLeakRelevance() > 0) {
233 int red = Math.min((int) (object.getLeakRelevance() * 100), 255);
234 return new Color(Display.getCurrent(), new RGB(red, 0, 0));
235 }
236 return new Color(Display.getCurrent(), new RGB(0, 0, 0));
237 }
238 }).build();
239 private final IColumn ADDRESS_COLUMN = new ColumnBuilder(Messages.MemoryLeakPage_ADDRESS_COLUMN_HEADER,
240 "address", //$NON-NLS-1$
241 new TypedLabelProvider<ReferenceTreeObject>(ReferenceTreeObject.class) {
242 @Override
243 protected String getTextTyped(ReferenceTreeObject object) {
244 return object.getAddress().displayUsing(IDisplayable.AUTO);
245 }
246 }).build();
247 private final IColumn COUNT_COLUMN = new ColumnBuilder(Messages.MemoryLeakPage_COUNT_COLUMN_HEADER, "count", //$NON-NLS-1$
248 new TypedLabelProvider<ReferenceTreeObject>(ReferenceTreeObject.class) {
249 @Override
250 protected String getTextTyped(ReferenceTreeObject object) {
251 return object == null ? "" : Integer.toString(object.getItems().size()); //$NON-NLS-1$
252 };
253 }).style(SWT.RIGHT).comparator((o1, o2) -> {
254 if (o1 instanceof ReferenceTreeObject && o2 instanceof ReferenceTreeObject) {
255 return ((ReferenceTreeObject) o1).getObjectsKeptAliveCount()
256 - ((ReferenceTreeObject) o2).getObjectsKeptAliveCount();
257 }
258 return -1;
259 }).columnDrawer(BackgroundFractionDrawer.<ReferenceTreeObject> unchecked(getSelectedFraction)).build();
260 private final IColumn RELEVANCE_COLUMN = new ColumnBuilder(Messages.MemoryLeakPage_RELEVANCE_COLUMN_HEADER,
261 "relevance", //$NON-NLS-1$
262 new TypedLabelProvider<ReferenceTreeObject>(ReferenceTreeObject.class) {
263 @Override
264 protected String getTextTyped(ReferenceTreeObject object) {
265 return Double.toString(object.getLeakRelevance());
266 }
267 }).build();
268 private final IColumn DESCRIPTION_COLUMN = new ColumnBuilder(Messages.MemoryLeakPage_DESCRIPTION_COLUMN_HEADER,
269 "description", //$NON-NLS-1$
270 new TypedLabelProvider<ReferenceTreeObject>(ReferenceTreeObject.class) {
271 @Override
293 private ColumnManager referenceTree;
294
295 public MemoryLeakPageUI(Composite parent, FormToolkit toolkit, IPageContainer editor, IState state) {
296 objectFormattingOptions = StateToolkit.readInt(state, OBJECT_FORMATTING_OPTIONS, 0);
297 form = DataPageToolkit.createForm(parent, toolkit, getName(), getImageDescriptor().createImage());
298 addResultActions(form);
299 mainSash = new SashForm(form.getBody(), SWT.VERTICAL);
300 toolkit.adapt(mainSash);
301
302 buildChart(toolkit, editor, mainSash);
303
304 aggregatedReferenceTree = new TreeViewer(mainSash, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
305 aggregatedReferenceTree.setContentProvider(new ReferenceTreeContentProvider());
306 referenceTree = ColumnManager.build(aggregatedReferenceTree,
307 Arrays.asList(OBJECT_COLUMN, COUNT_COLUMN, DESCRIPTION_COLUMN, ADDRESS_COLUMN, RELEVANCE_COLUMN),
308 TableSettings.forState(state.getChild(REFERENCE_TREE)));
309 configureColumnManager(editor, referenceTree, null, Messages.MemoryLeakPage_OBJECT_SAMPLES_SELECTION,
310 state.getChild(REFERENCE_TREE), null);
311 model = ReferenceTreeModel.buildReferenceTree(getDataSource().getItems().apply(TABLE_ITEMS));
312 model.getLeakCandidates(0.5d); // this doesn't really matter, since we're not saving the return value
313 aggregatedReferenceTree.setInput(model.getRootObjects());
314 chartCanvas.replaceRenderer(createChart());
315
316 PersistableSashForm.loadState(mainSash, state.getChild(MAIN_SASH));
317 }
318
319 private void configureColumnManager(
320 IPageContainer editor, ColumnManager manager, Supplier<IItemCollection> selectionStoreSupplier,
321 String selectionName, IState state, FilterComponent filter) {
322 MCContextMenuManager menuManager = MCContextMenuManager.create(manager.getViewer().getControl());
323 ColumnMenusFactory.addDefaultMenus(manager, menuManager);
324 if (selectionStoreSupplier != null) {
325 SelectionStoreActionToolkit.addSelectionStoreActions(manager.getViewer(), editor.getSelectionStore(),
326 selectionStoreSupplier, selectionName, menuManager);
327 }
328 manager.getViewer().addSelectionChangedListener(e -> {
329 TreeSelection selection = (TreeSelection) e.getSelection();
330 ReferenceTreeObject element = (ReferenceTreeObject) selection.getFirstElement();
331 if (element != null) {
332 editor.showSelection(ItemCollectionToolkit.build(element.getItems().stream()));
333 }
362 }
363
364 private void setDisplayOption(int option) {
365 objectFormattingOptions = objectFormattingOptions ^ option;
366 aggregatedReferenceTree.refresh();
367 }
368
369 private void buildChart(FormToolkit toolkit, IPageContainer editor, Composite parent) {
370 chartContainer = toolkit.createComposite(parent);
371 chartContainer.setLayout(new GridLayout(2, false));
372 chartCanvas = new ChartCanvas(chartContainer);
373 chartCanvas.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
374 DataPageToolkit.createChartTimestampTooltip(chartCanvas);
375 chart = new XYChart(editor.getRecordingRange(), RendererToolkit.empty(), 180);
376 DataPageToolkit.setChart(chartCanvas, chart, JdkAttributes.ALLOCATION_TIME, i -> {
377 if (aggregatedReferenceTree != null && model != null) {
378 IRange<IQuantity> selectionRange = chart.getSelectionRange();
379 if (selectionRange != null) {
380 ((ReferenceTreeContentProvider) aggregatedReferenceTree
381 .getContentProvider()).timeRange = selectionRange;
382 aggregatedReferenceTree.setInput(model.getRootObjects(selectionRange));
383 } else {
384 ((ReferenceTreeContentProvider) aggregatedReferenceTree.getContentProvider()).timeRange = null;
385 aggregatedReferenceTree.setInput(model.getRootObjects());
386 }
387 }
388 });
389 chart.setVisibleRange(visibleRange.getStart(), visibleRange.getEnd());
390 }
391
392 private IXDataRenderer createChart() {
393 List<IXDataRenderer> rows = new ArrayList<>();
394 IItemCollection items = getDataSource().getItems().apply(TABLE_ITEMS);
395 rows.add(DataPageToolkit.buildTimestampHistogram(Messages.HeapPage_ROW_ALLOCATION,
396 JdkAggregators.ALLOCATION_TOTAL.getDescription(), items, Aggregators.count(TABLE_ITEMS),
397 JdkAttributes.ALLOCATION_TIME, DataPageToolkit.ALLOCATION_COLOR));
398 IXDataRenderer root = RendererToolkit.uniformRows(rows);
399 return new ItemRow(root, items);
400 }
401
402 @Override
|
20 *
21 * 3. Neither the name of the copyright holder nor the names of its contributors may be used to
22 * endorse or promote products derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
26 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
31 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 package org.openjdk.jmc.flightrecorder.ui.pages;
34
35 import java.text.MessageFormat;
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.Collection;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.function.Predicate;
42 import java.util.function.Supplier;
43 import java.util.function.ToDoubleFunction;
44
45 import org.eclipse.jface.action.GroupMarker;
46 import org.eclipse.jface.action.IAction;
47 import org.eclipse.jface.action.MenuManager;
48 import org.eclipse.jface.resource.ImageDescriptor;
49 import org.eclipse.jface.viewers.ITreeContentProvider;
50 import org.eclipse.jface.viewers.TreeSelection;
51 import org.eclipse.jface.viewers.TreeViewer;
52 import org.eclipse.jface.viewers.Viewer;
53 import org.eclipse.swt.SWT;
54 import org.eclipse.swt.custom.SashForm;
55 import org.eclipse.swt.graphics.Color;
56 import org.eclipse.swt.graphics.RGB;
57 import org.eclipse.swt.layout.GridData;
58 import org.eclipse.swt.layout.GridLayout;
59 import org.eclipse.swt.widgets.Composite;
60 import org.eclipse.swt.widgets.Display;
122 return FlightRecorderUI.getDefault().getMCImageDescriptor(ImageConstants.PAGE_HEAP);
123 }
124
125 @Override
126 public String[] getTopics(IState state) {
127 return new String[] {JfrRuleTopics.MEMORY_LEAK_TOPIC};
128 }
129
130 @Override
131 public IDisplayablePage createPage(IPageDefinition definition, StreamModel items, IPageContainer editor) {
132 return new MemoryLeakPage(definition, items, editor);
133 }
134
135 }
136
137 private static class ReferenceTreeContentProvider extends AbstractStructuredContentProvider
138 implements ITreeContentProvider {
139
140 IRange<IQuantity> timeRange = null;
141
142 private final Predicate<ReferenceTreeObject> withinTimeRangePredicateFromRootObject = rto -> {
143 if (timeRange != null) {
144 if (rto.getTimestamp().compareTo(timeRange.getStart()) >= 0
145 && rto.getTimestamp().compareTo(timeRange.getEnd()) <= 0) {
146 return true;
147 } else if (rto.getRootObject().getLeafNodes() != null && rto.getRootObject().getLeafNodes().size() > 1) {
148 for (Map.Entry<IQuantity, ReferenceTreeObject> rt : rto.getRootObject().getLeafNodes().entrySet()) {
149 if (rt.getKey().compareTo(timeRange.getStart()) >= 0
150 && rt.getKey().compareTo(timeRange.getEnd()) <= 0) {
151 return true;
152 }
153 }
154 }
155 return false;
156 }
157 return true;
158 };
159
160 private final Predicate<ReferenceTreeObject> withinTimeRangePredicate = rto -> {
161 if (timeRange != null) {
162 return rto.getTimestamp().compareTo(timeRange.getStart()) >= 0
163 && rto.getTimestamp().compareTo(timeRange.getEnd()) <= 0;
164 }
165 return true;
166 };
167
168 @Override
169 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
170 }
171
172 @Override
173 public void dispose() {
174 }
175
176 @Override
177 public boolean hasChildren(Object element) {
178 if (element instanceof ReferenceTreeObject) {
179 ReferenceTreeObject object = (ReferenceTreeObject) element;
180 List<ReferenceTreeObject> children = object.getChildren();
181 if (timeRange != null) {
182 return children.stream().anyMatch(withinTimeRangePredicateFromRootObject);
183 }
184 return !children.isEmpty();
185 }
186 return false;
187 }
188
189 @Override
190 public Object getParent(Object element) {
191 if (element instanceof ReferenceTreeObject) {
192 return ((ReferenceTreeObject) element).getParent();
193 }
194 return null;
195 }
196
197 @SuppressWarnings("unchecked")
198 @Override
199 public Object[] getElements(Object inputElement) {
200 if (inputElement instanceof Collection<?>) {
201 Collection<ReferenceTreeObject> collection = (Collection<ReferenceTreeObject>) inputElement;
202 if (timeRange != null) {
203 return collection.stream().filter(withinTimeRangePredicateFromRootObject).toArray();
204 }
205 return collection.toArray();
206 }
207 return new Object[0];
208 }
209
210 @Override
211 public Object[] getChildren(Object element) {
212 if (element instanceof ReferenceTreeObject) {
213 ReferenceTreeObject object = (ReferenceTreeObject) element;
214 List<ReferenceTreeObject> children = object.getChildren();
215 if (timeRange != null) {
216 // Node has more than 1 children, select only those nodes which are leaky (leaf node) objects
217 if (children.size() > 1) {
218 return children.stream().filter(withinTimeRangePredicate).toArray();
219 } else {
220 return children.stream().filter(withinTimeRangePredicateFromRootObject).toArray();
221 }
222 }
223 return children.toArray();
224 }
225 return new Object[0];
226 }
227 }
228
229 private static final IItemFilter TABLE_ITEMS = ItemFilters.type(JdkTypeIDs.OLD_OBJECT_SAMPLE);
230
231 private class MemoryLeakPageUI implements IPageUI {
232
233 private static final String OBJECT_FORMATTING_OPTIONS = "objectFormattingOptions"; //$NON-NLS-1$
234 private ReferenceTreeModel model;
235 private int objectFormattingOptions = 0b0000;
236 private final ToDoubleFunction<ReferenceTreeObject> getSelectedFraction = o -> {
237 if (model == null) {
238 return 1d;
239 }
240 return ((double) o.getItems().size()) / model.getLeakObjects().size();
241 };
255 protected Color getForegroundTyped(ReferenceTreeObject object) {
256 if (object.getLeakRelevance() > 0) {
257 int red = Math.min((int) (object.getLeakRelevance() * 100), 255);
258 return new Color(Display.getCurrent(), new RGB(red, 0, 0));
259 }
260 return new Color(Display.getCurrent(), new RGB(0, 0, 0));
261 }
262 }).build();
263 private final IColumn ADDRESS_COLUMN = new ColumnBuilder(Messages.MemoryLeakPage_ADDRESS_COLUMN_HEADER,
264 "address", //$NON-NLS-1$
265 new TypedLabelProvider<ReferenceTreeObject>(ReferenceTreeObject.class) {
266 @Override
267 protected String getTextTyped(ReferenceTreeObject object) {
268 return object.getAddress().displayUsing(IDisplayable.AUTO);
269 }
270 }).build();
271 private final IColumn COUNT_COLUMN = new ColumnBuilder(Messages.MemoryLeakPage_COUNT_COLUMN_HEADER, "count", //$NON-NLS-1$
272 new TypedLabelProvider<ReferenceTreeObject>(ReferenceTreeObject.class) {
273 @Override
274 protected String getTextTyped(ReferenceTreeObject object) {
275 IRange<IQuantity> selectionRange = chart.getSelectionRange();
276 if (selectionRange == null) {
277 return object == null ? "" : Integer.toString(object.getObjectsKeptAliveCount()); //$NON-NLS-1$
278 } else {
279 return (object == null || selectionRange == null) ? "" : Integer.toString(model.getLeakCountInRange(selectionRange, object)); //$NON-NLS-1$
280 }
281 };
282 }).style(SWT.RIGHT).comparator((o1, o2) -> {
283 if (o1 instanceof ReferenceTreeObject && o2 instanceof ReferenceTreeObject) {
284 return ((ReferenceTreeObject) o1).getObjectsKeptAliveCount()
285 - ((ReferenceTreeObject) o2).getObjectsKeptAliveCount();
286 }
287 return -1;
288 }).columnDrawer(BackgroundFractionDrawer.<ReferenceTreeObject> unchecked(getSelectedFraction)).build();
289 private final IColumn RELEVANCE_COLUMN = new ColumnBuilder(Messages.MemoryLeakPage_RELEVANCE_COLUMN_HEADER,
290 "relevance", //$NON-NLS-1$
291 new TypedLabelProvider<ReferenceTreeObject>(ReferenceTreeObject.class) {
292 @Override
293 protected String getTextTyped(ReferenceTreeObject object) {
294 return Double.toString(object.getLeakRelevance());
295 }
296 }).build();
297 private final IColumn DESCRIPTION_COLUMN = new ColumnBuilder(Messages.MemoryLeakPage_DESCRIPTION_COLUMN_HEADER,
298 "description", //$NON-NLS-1$
299 new TypedLabelProvider<ReferenceTreeObject>(ReferenceTreeObject.class) {
300 @Override
322 private ColumnManager referenceTree;
323
324 public MemoryLeakPageUI(Composite parent, FormToolkit toolkit, IPageContainer editor, IState state) {
325 objectFormattingOptions = StateToolkit.readInt(state, OBJECT_FORMATTING_OPTIONS, 0);
326 form = DataPageToolkit.createForm(parent, toolkit, getName(), getImageDescriptor().createImage());
327 addResultActions(form);
328 mainSash = new SashForm(form.getBody(), SWT.VERTICAL);
329 toolkit.adapt(mainSash);
330
331 buildChart(toolkit, editor, mainSash);
332
333 aggregatedReferenceTree = new TreeViewer(mainSash, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
334 aggregatedReferenceTree.setContentProvider(new ReferenceTreeContentProvider());
335 referenceTree = ColumnManager.build(aggregatedReferenceTree,
336 Arrays.asList(OBJECT_COLUMN, COUNT_COLUMN, DESCRIPTION_COLUMN, ADDRESS_COLUMN, RELEVANCE_COLUMN),
337 TableSettings.forState(state.getChild(REFERENCE_TREE)));
338 configureColumnManager(editor, referenceTree, null, Messages.MemoryLeakPage_OBJECT_SAMPLES_SELECTION,
339 state.getChild(REFERENCE_TREE), null);
340 model = ReferenceTreeModel.buildReferenceTree(getDataSource().getItems().apply(TABLE_ITEMS));
341 model.getLeakCandidates(0.5d); // this doesn't really matter, since we're not saving the return value
342 aggregatedReferenceTree.setInput(model.getLeakObjects());
343 chartCanvas.replaceRenderer(createChart());
344
345 PersistableSashForm.loadState(mainSash, state.getChild(MAIN_SASH));
346 }
347
348 private void configureColumnManager(
349 IPageContainer editor, ColumnManager manager, Supplier<IItemCollection> selectionStoreSupplier,
350 String selectionName, IState state, FilterComponent filter) {
351 MCContextMenuManager menuManager = MCContextMenuManager.create(manager.getViewer().getControl());
352 ColumnMenusFactory.addDefaultMenus(manager, menuManager);
353 if (selectionStoreSupplier != null) {
354 SelectionStoreActionToolkit.addSelectionStoreActions(manager.getViewer(), editor.getSelectionStore(),
355 selectionStoreSupplier, selectionName, menuManager);
356 }
357 manager.getViewer().addSelectionChangedListener(e -> {
358 TreeSelection selection = (TreeSelection) e.getSelection();
359 ReferenceTreeObject element = (ReferenceTreeObject) selection.getFirstElement();
360 if (element != null) {
361 editor.showSelection(ItemCollectionToolkit.build(element.getItems().stream()));
362 }
391 }
392
393 private void setDisplayOption(int option) {
394 objectFormattingOptions = objectFormattingOptions ^ option;
395 aggregatedReferenceTree.refresh();
396 }
397
398 private void buildChart(FormToolkit toolkit, IPageContainer editor, Composite parent) {
399 chartContainer = toolkit.createComposite(parent);
400 chartContainer.setLayout(new GridLayout(2, false));
401 chartCanvas = new ChartCanvas(chartContainer);
402 chartCanvas.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
403 DataPageToolkit.createChartTimestampTooltip(chartCanvas);
404 chart = new XYChart(editor.getRecordingRange(), RendererToolkit.empty(), 180);
405 DataPageToolkit.setChart(chartCanvas, chart, JdkAttributes.ALLOCATION_TIME, i -> {
406 if (aggregatedReferenceTree != null && model != null) {
407 IRange<IQuantity> selectionRange = chart.getSelectionRange();
408 if (selectionRange != null) {
409 ((ReferenceTreeContentProvider) aggregatedReferenceTree
410 .getContentProvider()).timeRange = selectionRange;
411 aggregatedReferenceTree.setInput(model.getLeakObjects(selectionRange));
412 } else {
413 ((ReferenceTreeContentProvider) aggregatedReferenceTree.getContentProvider()).timeRange = null;
414 aggregatedReferenceTree.setInput(model.getRootObjects());
415 }
416 }
417 });
418 chart.setVisibleRange(visibleRange.getStart(), visibleRange.getEnd());
419 }
420
421 private IXDataRenderer createChart() {
422 List<IXDataRenderer> rows = new ArrayList<>();
423 IItemCollection items = getDataSource().getItems().apply(TABLE_ITEMS);
424 rows.add(DataPageToolkit.buildTimestampHistogram(Messages.HeapPage_ROW_ALLOCATION,
425 JdkAggregators.ALLOCATION_TOTAL.getDescription(), items, Aggregators.count(TABLE_ITEMS),
426 JdkAttributes.ALLOCATION_TIME, DataPageToolkit.ALLOCATION_COLOR));
427 IXDataRenderer root = RendererToolkit.uniformRows(rows);
428 return new ItemRow(root, items);
429 }
430
431 @Override
|