< prev index next >

application/org.openjdk.jmc.flightrecorder.ui/src/main/java/org/openjdk/jmc/flightrecorder/ui/pages/MemoryLeakPage.java

Print this page




  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


< prev index next >