15 * and the following disclaimer.
16 *
17 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
18 * conditions and the following disclaimer in the documentation and/or other materials provided with
19 * the distribution.
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.util.ArrayList;
36 import java.util.LinkedHashMap;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.stream.Collectors;
40 import java.util.stream.Stream;
41
42 import org.eclipse.jface.action.IAction;
43 import org.eclipse.jface.resource.ImageDescriptor;
44 import org.eclipse.swt.SWT;
45 import org.eclipse.swt.custom.CTabFolder;
46 import org.eclipse.swt.custom.SashForm;
47 import org.eclipse.swt.layout.GridData;
48 import org.eclipse.swt.layout.GridLayout;
49 import org.eclipse.swt.widgets.Composite;
50 import org.eclipse.swt.widgets.Control;
51 import org.eclipse.ui.forms.widgets.Form;
52 import org.eclipse.ui.forms.widgets.FormToolkit;
53
54 import org.openjdk.jmc.common.IState;
55 import org.openjdk.jmc.common.IWritableState;
56 import org.openjdk.jmc.common.item.Aggregators;
57 import org.openjdk.jmc.common.item.IAttribute;
58 import org.openjdk.jmc.common.item.IItemCollection;
59 import org.openjdk.jmc.common.item.IItemFilter;
60 import org.openjdk.jmc.common.item.ItemFilters;
61 import org.openjdk.jmc.common.item.RangeMatchPolicy;
62 import org.openjdk.jmc.common.unit.IQuantity;
63 import org.openjdk.jmc.common.unit.IRange;
64 import org.openjdk.jmc.common.unit.UnitLookup;
65 import org.openjdk.jmc.flightrecorder.JfrAttributes;
66 import org.openjdk.jmc.flightrecorder.jdk.JdkAttributes;
67 import org.openjdk.jmc.flightrecorder.jdk.JdkFilters;
68 import org.openjdk.jmc.flightrecorder.jdk.JdkQueries;
69 import org.openjdk.jmc.flightrecorder.jdk.JdkTypeIDs;
70 import org.openjdk.jmc.flightrecorder.rules.util.JfrRuleTopics;
71 import org.openjdk.jmc.flightrecorder.ui.FlightRecorderUI;
72 import org.openjdk.jmc.flightrecorder.ui.IDataPageFactory;
73 import org.openjdk.jmc.flightrecorder.ui.IDisplayablePage;
74 import org.openjdk.jmc.flightrecorder.ui.IPageContainer;
75 import org.openjdk.jmc.flightrecorder.ui.IPageDefinition;
76 import org.openjdk.jmc.flightrecorder.ui.IPageUI;
114 public ImageDescriptor getImageDescriptor(IState state) {
115 return FlightRecorderUI.getDefault().getMCImageDescriptor(ImageConstants.PAGE_CLASSLOADING);
116 }
117
118 @Override
119 public String[] getTopics(IState state) {
120 return new String[] {JfrRuleTopics.CLASS_LOADING_TOPIC};
121 }
122
123 @Override
124 public IDisplayablePage createPage(IPageDefinition dpd, StreamModel items, IPageContainer editor) {
125 return new ClassLoadingPage(dpd, items, editor);
126 }
127 }
128
129 private static final IItemFilter TABLE_FILTER = ItemFilters.or(JdkQueries.CLASS_LOAD.getFilter(),
130 JdkQueries.CLASS_UNLOAD.getFilter());
131 private static final ItemHistogramBuilder CLASSLOADER_HISTOGRAM = new ItemHistogramBuilder();
132 private static final ItemListBuilder CLASS_LOADING_LIST = new ItemListBuilder();
133 private static final ItemListBuilder CLASS_UNLOADING_LIST = new ItemListBuilder();
134 private static final Map<String, Boolean> LEGEND_ITEMS = new LinkedHashMap<>();
135 private static final String LOADED_COUNT = "loadedCount"; //$NON-NLS-1$
136 private static final String UNLOADED_COUNT = "unloadedCount"; //$NON-NLS-1$
137 private static final String CLASS_LOAD = "classLoad"; //$NON-NLS-1$
138 private static final String CLASS_UNLOAD = "classUnload"; //$NON-NLS-1$
139
140 static {
141 CLASSLOADER_HISTOGRAM.addColumn(LOADED_COUNT,
142 Aggregators.count(Messages.ClassLoadingPage_AGGR_CLASSES_LOADED_BY_CLASSLOADER,
143 Messages.ClassLoadingPage_AGGR_CLASSES_LOADED_BY_CLASSLOADER_DESC,
144 ItemFilters.type(JdkTypeIDs.CLASS_LOAD)));
145 CLASSLOADER_HISTOGRAM.addColumn(UNLOADED_COUNT,
146 Aggregators.count(Messages.ClassLoadingPage_AGGR_CLASSES_UNLOADED_BY_CLASSLOADER,
147 Messages.ClassLoadingPage_AGGR_CLASSES_UNLOADED_BY_CLASSLOADER_DESC,
148 ItemFilters.type(JdkTypeIDs.CLASS_UNLOAD)));
149
150 CLASS_LOADING_LIST.addColumn(JdkAttributes.CLASS_LOADED);
151 CLASS_LOADING_LIST.addColumn(JdkAttributes.CLASS_DEFINING_CLASSLOADER);
152 CLASS_LOADING_LIST.addColumn(JdkAttributes.CLASS_INITIATING_CLASSLOADER);
153 CLASS_LOADING_LIST.addColumn(JfrAttributes.START_TIME);
154 CLASS_LOADING_LIST.addColumn(JfrAttributes.DURATION);
155 CLASS_LOADING_LIST.addColumn(JfrAttributes.END_TIME);
156 CLASS_LOADING_LIST.addColumn(JfrAttributes.EVENT_THREAD);
157 CLASS_UNLOADING_LIST.addColumn(JfrAttributes.EVENT_TIMESTAMP);
158 CLASS_UNLOADING_LIST.addColumn(JfrAttributes.EVENT_THREAD);
159 CLASS_UNLOADING_LIST.addColumn(JdkAttributes.CLASS_UNLOADED);
160 CLASS_UNLOADING_LIST.addColumn(JdkAttributes.CLASS_DEFINING_CLASSLOADER);
161
162 // FIXME: Need to make a label provider for this
163 // FIXME: Want to have this in the same order
164
165 LEGEND_ITEMS.put(JdkAttributes.CLASSLOADER_LOADED_COUNT.getIdentifier(), Boolean.TRUE);
166 LEGEND_ITEMS.put(JdkAttributes.CLASSLOADER_UNLOADED_COUNT.getIdentifier(), Boolean.FALSE);
167 LEGEND_ITEMS.put(CLASS_LOAD, Boolean.TRUE);
168 LEGEND_ITEMS.put(CLASS_UNLOAD, Boolean.FALSE);
169 }
170
171 private class ClassLoadingUi implements IPageUI {
172
173 private final ChartCanvas classLoadingChart;
174 private final ItemList classLoadingTable;
175 private final ItemList classUnloadingTable;
176 private FilterComponent classLoadingFilter;
177 private FilterComponent classUnloadingFilter;
178 private final SashForm sash;
179 private final IPageContainer pageContainer;
180 private IItemCollection selectionItems;
181 private ItemHistogram classloaderHistogram;
182 private FilterComponent classloaderHistogramFilter;
183 private final IAction classLoadAction = DataPageToolkit.createTypeCheckAction(CLASS_LOAD, JdkTypeIDs.CLASS_LOAD,
184 Messages.ClassLoadingPage_CLASS_LOADING_ACTION, Messages.ClassLoadingPage_CLASS_LOADING_ACTION_DESC,
185 b -> updateChart());
186 private final IAction classUnloadAction = DataPageToolkit.createTypeCheckAction(CLASS_UNLOAD,
187 JdkTypeIDs.CLASS_UNLOAD, Messages.ClassLoadingPage_CLASS_UNLOADING_ACTION,
188 Messages.ClassLoadingPage_CLASS_UNLOADING_ACTION_DESC, b -> updateChart());
189 private final Stream<IAction> statsActions = Stream
190 .of(JdkAttributes.CLASSLOADER_LOADED_COUNT, JdkAttributes.CLASSLOADER_UNLOADED_COUNT)
191 .map(a -> DataPageToolkit.createAttributeCheckAction(a, b -> updateChart()));
192 private final List<IAction> allChartSeriesActions = Stream
193 .concat(Stream.of(classLoadAction, classUnloadAction), statsActions).collect(Collectors.toList());
194 private CTabFolder tabFolder;
195 private XYChart chart;
196 private IRange<IQuantity> timeRange;
197 private FlavorSelector flavorSelector;
198
199 ClassLoadingUi(Composite parent, FormToolkit toolkit, IPageContainer pageContainer, IState state) {
200 this.pageContainer = pageContainer;
201
202 Form form = DataPageToolkit.createForm(parent, toolkit, getName(), getIcon());
203
204 sash = new SashForm(form.getBody(), SWT.VERTICAL);
205
206 Composite chartComp = new Composite(sash, SWT.NONE);
207 chartComp.setLayout(new GridLayout());
208 Control legend = ActionUiToolkit.buildCheckboxControl(chartComp, allChartSeriesActions.stream(), false);
209 legend.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
210 ActionToolkit.loadCheckState(state.getChild(CHART), allChartSeriesActions.stream());
211
212 chart = new XYChart(pageContainer.getRecordingRange(), RendererToolkit.empty(), 180);
213 chart.setVisibleRange(timelineRange.getStart(), timelineRange.getEnd());
214 chart.addVisibleRangeListener(r -> timelineRange = r);
215 classLoadingChart = new ChartCanvas(chartComp);
216 classLoadingChart.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
217 DataPageToolkit.createChartTimestampTooltip(classLoadingChart);
218 DataPageToolkit.setChart(classLoadingChart, chart, pageContainer::showSelection, this::onChartSelection);
219 SelectionStoreActionToolkit.addSelectionStoreRangeActions(pageContainer.getSelectionStore(), chart,
220 JfrAttributes.LIFETIME, Messages.ClassLoadingPage_CLASS_LOADING_TIMELINE_SELECTION,
221 classLoadingChart.getContextMenu());
222
223 classloaderHistogram = CLASSLOADER_HISTOGRAM.buildWithoutBorder(sash,
224 JdkAttributes.CLASS_DEFINING_CLASSLOADER, TableSettings.forState(state.getChild(HISTOGRAM)));
225 classloaderHistogramFilter = FilterComponent.createFilterComponent(classloaderHistogram, null,
226 getDataSource().getItems().apply(JdkFilters.CLASS_LOAD_OR_UNLOAD),
227 pageContainer.getSelectionStore()::getSelections, this::onHistogramFilterChange);
228 classloaderHistogram.getManager().getViewer().addSelectionChangedListener(
229 e -> pageContainer.showSelection(classloaderHistogram.getSelection().getItems()));
230 MCContextMenuManager classLoaderHistogramMm = MCContextMenuManager
231 .create(classloaderHistogram.getManager().getViewer().getControl());
232 ColumnMenusFactory.addDefaultMenus(classloaderHistogram.getManager(), classLoaderHistogramMm);
233 SelectionStoreActionToolkit.addSelectionStoreActions(pageContainer.getSelectionStore(),
234 classloaderHistogram, Messages.ClassLoadingPage_CLASS_LOADING_HISTOGRAM_SELECTION,
235 classLoaderHistogramMm);
236 classLoaderHistogramMm.add(classloaderHistogramFilter.getShowFilterAction());
237 classLoaderHistogramMm.add(classloaderHistogramFilter.getShowSearchAction());
238 classloaderHistogramFilter.loadState(state.getChild(HISTOGRAM_FILTER));
239
240 ItemHistogramWithInput.chain(classloaderHistogram, this::updateTables);
241
242 tabFolder = new CTabFolder(sash, SWT.NONE);
243
244 classLoadingTable = CLASS_LOADING_LIST.buildWithoutBorder(tabFolder,
245 TableSettings.forState(state.getChild(CLASS_LOADING_TABLE)));
246 classLoadingTable.getManager().getViewer().addSelectionChangedListener(e -> pageContainer
247 .showSelection(ItemCollectionToolkit.build(classLoadingTable.getSelection().get())));
248 classLoadingFilter = FilterComponent.createFilterComponent(classLoadingTable, null,
249 getDataSource().getItems().apply(JdkFilters.CLASS_LOAD),
250 pageContainer.getSelectionStore()::getSelections, this::onClassLoadFilterChange);
251 MCContextMenuManager classLoadingTableMm = MCContextMenuManager
252 .create(classLoadingTable.getManager().getViewer().getControl());
253 ColumnMenusFactory.addDefaultMenus(classLoadingTable.getManager(), classLoadingTableMm);
254 SelectionStoreActionToolkit.addSelectionStoreActions(pageContainer.getSelectionStore(), classLoadingTable,
255 Messages.ClassLoadingPage_CLASS_LOADING_LIST_SELECTION, classLoadingTableMm);
256 classLoadingTableMm.add(classLoadingFilter.getShowFilterAction());
257 classLoadingTableMm.add(classLoadingFilter.getShowSearchAction());
258 classLoadingFilter.loadState(state.getChild(CLASS_LOADING_FILTER));
259 DataPageToolkit.addTabItem(tabFolder, classLoadingFilter.getComponent(),
260 Messages.ClassLoadingPage_CLASS_LOADING_TAB_TITLE);
261
262 classUnloadingTable = CLASS_UNLOADING_LIST.buildWithoutBorder(tabFolder,
263 TableSettings.forState(state.getChild(CLASS_UNLOADING_TABLE)));
264 classUnloadingTable.getManager().getViewer().addSelectionChangedListener(e -> pageContainer
265 .showSelection(ItemCollectionToolkit.build(classUnloadingTable.getSelection().get())));
266 classUnloadingFilter = FilterComponent.createFilterComponent(classUnloadingTable, null,
267 getDataSource().getItems().apply(JdkFilters.CLASS_UNLOAD),
268 pageContainer.getSelectionStore()::getSelections, this::onClassUnloadFilterChange);
269 MCContextMenuManager classUnloadingTableMm = MCContextMenuManager
270 .create(classUnloadingTable.getManager().getViewer().getControl());
271 ColumnMenusFactory.addDefaultMenus(classUnloadingTable.getManager(), classUnloadingTableMm);
272 SelectionStoreActionToolkit.addSelectionStoreActions(pageContainer.getSelectionStore(), classUnloadingTable,
273 Messages.ClassLoadingPage_CLASS_UNLOADING_LIST_SELECTION, classUnloadingTableMm);
274 classUnloadingTableMm.add(classUnloadingFilter.getShowFilterAction());
275 classUnloadingTableMm.add(classUnloadingFilter.getShowSearchAction());
276 classUnloadingFilter.loadState(state.getChild(CLASS_UNLOADING_FILTER));
277 DataPageToolkit.addTabItem(tabFolder, classUnloadingFilter.getComponent(),
278 Messages.ClassLoadingPage_CLASS_UNLOADING_TAB_TITLE);
279
280 tabFolder.setSelection(tabFolderIndex);
281
282 PersistableSashForm.loadState(sash, state.getChild(SASH));
283 flavorSelector = FlavorSelector.itemsWithTimerange(form, TABLE_FILTER, getDataSource().getItems(),
284 pageContainer, this::onInputSelected, this::onShow, flavorSelectorState);
285 addResultActions(form);
286
287 onHistogramFilterChange(histogramFilter);
288 onClassLoadFilterChange(classLoadTableFilter);
289 onClassUnloadFilterChange(classUnloadTableFilter);
290
291 classloaderHistogram.getManager().setSelectionState(histogramSelection);
292 classLoadingTable.getManager().setSelectionState(classLoadingTableSelection);
293 classUnloadingTable.getManager().setSelectionState(classUnloadingTableSelection);
294 }
295
296 private void onHistogramFilterChange(IItemFilter filter) {
297 classloaderHistogramFilter.filterChangeHelper(filter, classloaderHistogram,
298 getDataSource().getItems().apply(JdkFilters.CLASS_LOAD_OR_UNLOAD));
299 if (classLoadingFilter != null) {
300 classLoadingFilter.notifyListener();
301 }
302 if (classUnloadingFilter != null) {
303 classUnloadingFilter.notifyListener();
304 }
305 histogramFilter = filter;
306 }
307
308 private void onClassLoadFilterChange(IItemFilter filter) {
309 classLoadingFilter.filterChangeHelper(filter, classLoadingTable,
310 getDataSource().getItems().apply(JdkFilters.CLASS_LOAD));
311 classLoadTableFilter = filter;
312 }
313
314 private void onClassUnloadFilterChange(IItemFilter filter) {
315 classUnloadingFilter.filterChangeHelper(filter, classUnloadingTable,
316 getDataSource().getItems().apply(JdkFilters.CLASS_UNLOAD));
317 classUnloadTableFilter = filter;
318 }
319
320 @Override
321 public void saveTo(IWritableState state) {
322 PersistableSashForm.saveState(sash, state.createChild(SASH));
323 classloaderHistogram.getManager().getSettings().saveState(state.createChild(HISTOGRAM));
324 classLoadingTable.getManager().getSettings().saveState(state.createChild(CLASS_LOADING_TABLE));
325 classUnloadingTable.getManager().getSettings().saveState(state.createChild(CLASS_UNLOADING_TABLE));
326 classloaderHistogramFilter.saveState(state.createChild(HISTOGRAM_FILTER));
327 classLoadingFilter.saveState(state.createChild(CLASS_LOADING_FILTER));
328 classUnloadingFilter.saveState(state.createChild(CLASS_UNLOADING_FILTER));
329 ActionToolkit.saveCheckState(state.createChild(CHART), allChartSeriesActions.stream());
330
331 saveToLocal();
332 }
333
334 private void saveToLocal() {
335 histogramSelection = classloaderHistogram.getManager().getSelectionState();
336 classLoadingTableSelection = classLoadingTable.getManager().getSelectionState();
337 classUnloadingTableSelection = classUnloadingTable.getManager().getSelectionState();
338 tabFolderIndex = tabFolder.getSelectionIndex();
339 flavorSelectorState = flavorSelector.getFlavorSelectorState();
340 }
341
342 private void onShow(Boolean show) {
343 IRange<IQuantity> range = show ? timeRange : pageContainer.getRecordingRange();
344 chart.setVisibleRange(range.getStart(), range.getEnd());
345 updateChart();
346 }
347
348 private void onInputSelected(IItemCollection items, IRange<IQuantity> timeRange) {
349 selectionItems = items;
350 this.timeRange = timeRange;
351 updateHistogram(getItems());
352 updateTables(getItems());
353 updateChart();
354 }
355
356 private IItemCollection getItems() {
357 return selectionItems != null ? selectionItems : getDataSource().getItems();
378 Messages.ClassLoadingPage_AGGR_CLASSES_UNLOADED_DESC, getItems().apply(JdkFilters.CLASS_UNLOAD),
379 Aggregators.count(Messages.ClassLoadingPage_AGGR_CLASSES_UNLOADED,
380 Messages.ClassLoadingPage_AGGR_CLASSES_UNLOADED_DESC, JdkFilters.CLASS_UNLOAD),
381 TypeLabelProvider.getColor(JdkTypeIDs.CLASS_UNLOAD)));
382 }
383 classLoadingChart.replaceRenderer(RendererToolkit.uniformRows(rows));
384 }
385
386 private boolean isAttributeEnabled(IAttribute<IQuantity> attr) {
387 return allChartSeriesActions.stream().filter(a -> attr.getIdentifier().equals(a.getId())).findAny().get()
388 .isChecked();
389 }
390
391 private void updateHistogram(IItemCollection items) {
392 if (classloaderHistogram != null) {
393 classloaderHistogram.show(items.apply(JdkFilters.CLASS_LOAD_OR_UNLOAD));
394 }
395 }
396
397 private void updateTables(IItemCollection selectedItems) {
398 if (classLoadingTable != null && classUnloadingTable != null) {
399 classLoadingTable.show(selectedItems.apply(JdkQueries.CLASS_LOAD.getFilter()));
400 classUnloadingTable.show(selectedItems.apply(JdkQueries.CLASS_UNLOAD.getFilter()));
401 }
402 }
403
404 private void onChartSelection(IRange<IQuantity> range) {
405 // FIXME: Make this depend on the legend as well? And maybe on which chart row has been selected?
406 IItemCollection itemsInRange = range != null ? getItems().apply(ItemFilters
407 .matchRange(RangeMatchPolicy.CENTER_CONTAINED_IN_RIGHT_OPEN, JfrAttributes.LIFETIME, range))
408 : getItems();
409 updateTables(itemsInRange);
410 updateHistogram(itemsInRange);
411 }
412
413 }
414
415 private static final String SASH = "sash"; //$NON-NLS-1$
416 private static final String HISTOGRAM = "histogram"; //$NON-NLS-1$
417 private static final String HISTOGRAM_FILTER = "histogramFilter"; //$NON-NLS-1$
418 private static final String CLASS_LOADING_TABLE = "classLoadingTable"; //$NON-NLS-1$
419 private static final String CLASS_UNLOADING_TABLE = "classUnloadingTable"; //$NON-NLS-1$
420 private static final String CLASS_LOADING_FILTER = "classLoadingFilter"; //$NON-NLS-1$
421 private static final String CLASS_UNLOADING_FILTER = "classUnloadingFilter"; //$NON-NLS-1$
422 private static final String CHART = "chart"; //$NON-NLS-1$
423
424 @Override
425 public IPageUI display(Composite parent, FormToolkit toolkit, IPageContainer pageContainer, IState state) {
426 return new ClassLoadingUi(parent, toolkit, pageContainer, state);
427 }
428
429 private SelectionState histogramSelection;
430 private SelectionState classLoadingTableSelection;
431 private SelectionState classUnloadingTableSelection;
432 private IItemFilter histogramFilter;
433 private IItemFilter classLoadTableFilter;
434 private IItemFilter classUnloadTableFilter;
435 private int tabFolderIndex = 0;
436 private IRange<IQuantity> timelineRange;
437 private FlavorSelectorState flavorSelectorState;
438
439 public ClassLoadingPage(IPageDefinition dpd, StreamModel items, IPageContainer editor) {
440 super(dpd, items, editor);
441 timelineRange = editor.getRecordingRange();
442 }
443
444 @Override
445 public IItemFilter getDefaultSelectionFilter() {
446 return ItemFilters.or(TABLE_FILTER, JdkFilters.CLASS_LOAD_STATISTICS);
447 }
448
449 }
|
15 * and the following disclaimer.
16 *
17 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
18 * conditions and the following disclaimer in the documentation and/or other materials provided with
19 * the distribution.
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
36 import static org.openjdk.jmc.common.item.ItemQueryBuilder.fromWhere;
37
38 import java.util.ArrayList;
39 import java.util.HashSet;
40 import java.util.Iterator;
41 import java.util.LinkedHashMap;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Set;
45 import java.util.stream.Collectors;
46 import java.util.stream.Stream;
47
48 import org.eclipse.jface.action.IAction;
49 import org.eclipse.jface.resource.ImageDescriptor;
50 import org.eclipse.swt.SWT;
51 import org.eclipse.swt.custom.CTabFolder;
52 import org.eclipse.swt.custom.SashForm;
53 import org.eclipse.swt.layout.GridData;
54 import org.eclipse.swt.layout.GridLayout;
55 import org.eclipse.swt.widgets.Composite;
56 import org.eclipse.swt.widgets.Control;
57 import org.eclipse.ui.forms.widgets.Form;
58 import org.eclipse.ui.forms.widgets.FormToolkit;
59 import org.openjdk.jmc.common.IMCClassLoader;
60 import org.openjdk.jmc.common.IState;
61 import org.openjdk.jmc.common.IWritableState;
62 import org.openjdk.jmc.common.item.Aggregators;
63 import org.openjdk.jmc.common.item.IAggregator;
64 import org.openjdk.jmc.common.item.IAttribute;
65 import org.openjdk.jmc.common.item.IItemCollection;
66 import org.openjdk.jmc.common.item.IItemFilter;
67 import org.openjdk.jmc.common.item.ItemFilters;
68 import org.openjdk.jmc.common.item.RangeMatchPolicy;
69 import org.openjdk.jmc.common.unit.IQuantity;
70 import org.openjdk.jmc.common.unit.IRange;
71 import org.openjdk.jmc.common.unit.UnitLookup;
72 import org.openjdk.jmc.flightrecorder.JfrAttributes;
73 import org.openjdk.jmc.flightrecorder.jdk.JdkAttributes;
74 import org.openjdk.jmc.flightrecorder.jdk.JdkFilters;
75 import org.openjdk.jmc.flightrecorder.jdk.JdkQueries;
76 import org.openjdk.jmc.flightrecorder.jdk.JdkTypeIDs;
77 import org.openjdk.jmc.flightrecorder.rules.util.JfrRuleTopics;
78 import org.openjdk.jmc.flightrecorder.ui.FlightRecorderUI;
79 import org.openjdk.jmc.flightrecorder.ui.IDataPageFactory;
80 import org.openjdk.jmc.flightrecorder.ui.IDisplayablePage;
81 import org.openjdk.jmc.flightrecorder.ui.IPageContainer;
82 import org.openjdk.jmc.flightrecorder.ui.IPageDefinition;
83 import org.openjdk.jmc.flightrecorder.ui.IPageUI;
121 public ImageDescriptor getImageDescriptor(IState state) {
122 return FlightRecorderUI.getDefault().getMCImageDescriptor(ImageConstants.PAGE_CLASSLOADING);
123 }
124
125 @Override
126 public String[] getTopics(IState state) {
127 return new String[] {JfrRuleTopics.CLASS_LOADING_TOPIC};
128 }
129
130 @Override
131 public IDisplayablePage createPage(IPageDefinition dpd, StreamModel items, IPageContainer editor) {
132 return new ClassLoadingPage(dpd, items, editor);
133 }
134 }
135
136 private static final IItemFilter TABLE_FILTER = ItemFilters.or(JdkQueries.CLASS_LOAD.getFilter(),
137 JdkQueries.CLASS_UNLOAD.getFilter());
138 private static final ItemHistogramBuilder CLASSLOADER_HISTOGRAM = new ItemHistogramBuilder();
139 private static final ItemListBuilder CLASS_LOADING_LIST = new ItemListBuilder();
140 private static final ItemListBuilder CLASS_UNLOADING_LIST = new ItemListBuilder();
141 private static final ItemListBuilder CLASS_DEFINE_LIST = new ItemListBuilder();
142 private static final ItemListBuilder CLASS_LOADER_STATISTICS_LIST = new ItemListBuilder();
143 private static final Map<String, Boolean> LEGEND_ITEMS = new LinkedHashMap<>();
144 private static final String LOADED_COUNT = "loadedCount"; //$NON-NLS-1$
145 private static final String UNLOADED_COUNT = "unloadedCount"; //$NON-NLS-1$
146 private static final String CLASS_LOAD = "classLoad"; //$NON-NLS-1$
147 private static final String CLASS_UNLOAD = "classUnload"; //$NON-NLS-1$
148
149 static {
150 CLASSLOADER_HISTOGRAM.addColumn(LOADED_COUNT,
151 Aggregators.count(Messages.ClassLoadingPage_AGGR_CLASSES_LOADED_BY_CLASSLOADER,
152 Messages.ClassLoadingPage_AGGR_CLASSES_LOADED_BY_CLASSLOADER_DESC,
153 ItemFilters.type(JdkTypeIDs.CLASS_LOAD)));
154 CLASSLOADER_HISTOGRAM.addColumn(UNLOADED_COUNT,
155 Aggregators.count(Messages.ClassLoadingPage_AGGR_CLASSES_UNLOADED_BY_CLASSLOADER,
156 Messages.ClassLoadingPage_AGGR_CLASSES_UNLOADED_BY_CLASSLOADER_DESC,
157 ItemFilters.type(JdkTypeIDs.CLASS_UNLOAD)));
158
159 CLASS_LOADING_LIST.addColumn(JdkAttributes.CLASS_LOADED);
160 CLASS_LOADING_LIST.addColumn(JdkAttributes.CLASS_DEFINING_CLASSLOADER);
161 CLASS_LOADING_LIST.addColumn(JdkAttributes.CLASS_INITIATING_CLASSLOADER);
162 CLASS_LOADING_LIST.addColumn(JfrAttributes.START_TIME);
163 CLASS_LOADING_LIST.addColumn(JfrAttributes.DURATION);
164 CLASS_LOADING_LIST.addColumn(JfrAttributes.END_TIME);
165 CLASS_LOADING_LIST.addColumn(JfrAttributes.EVENT_THREAD);
166
167 CLASS_UNLOADING_LIST.addColumn(JfrAttributes.EVENT_TIMESTAMP);
168 CLASS_UNLOADING_LIST.addColumn(JfrAttributes.EVENT_THREAD);
169 CLASS_UNLOADING_LIST.addColumn(JdkAttributes.CLASS_UNLOADED);
170 CLASS_UNLOADING_LIST.addColumn(JdkAttributes.CLASS_DEFINING_CLASSLOADER);
171
172 CLASS_DEFINE_LIST.addColumn(JfrAttributes.START_TIME);
173 CLASS_DEFINE_LIST.addColumn(JdkAttributes.CLASS_DEFINING_CLASSLOADER);
174 CLASS_DEFINE_LIST.addColumn(JdkAttributes.CLASS_DEFINED);
175 CLASS_DEFINE_LIST.addColumn(JfrAttributes.EVENT_THREAD);
176
177 CLASS_LOADER_STATISTICS_LIST.addColumn(JdkAttributes.ANONYMOUS_BLOCK_SIZE);
178 CLASS_LOADER_STATISTICS_LIST.addColumn(JdkAttributes.ANONYMOUS_CHUNK_SIZE);
179 CLASS_LOADER_STATISTICS_LIST.addColumn(JdkAttributes.ANONYMOUS_CLASS_COUNT);
180 CLASS_LOADER_STATISTICS_LIST.addColumn(JdkAttributes.BLOCK_SIZE);
181 CLASS_LOADER_STATISTICS_LIST.addColumn(JdkAttributes.CHUNK_SIZE);
182 CLASS_LOADER_STATISTICS_LIST.addColumn(JdkAttributes.CLASS_COUNT);
183 CLASS_LOADER_STATISTICS_LIST.addColumn(JdkAttributes.CLASS_LOADER_DATA);
184 CLASS_LOADER_STATISTICS_LIST.addColumn(JdkAttributes.PARENT_CLASSLOADER);
185 CLASS_LOADER_STATISTICS_LIST.addColumn(JdkAttributes.CLASSLOADER);
186 CLASS_LOADER_STATISTICS_LIST.addColumn(JfrAttributes.START_TIME);
187 // FIXME: Need to make a label provider for this
188 // FIXME: Want to have this in the same order
189
190 LEGEND_ITEMS.put(JdkAttributes.CLASSLOADER_LOADED_COUNT.getIdentifier(), Boolean.TRUE);
191 LEGEND_ITEMS.put(JdkAttributes.CLASSLOADER_UNLOADED_COUNT.getIdentifier(), Boolean.FALSE);
192 LEGEND_ITEMS.put(CLASS_LOAD, Boolean.TRUE);
193 LEGEND_ITEMS.put(CLASS_UNLOAD, Boolean.FALSE);
194 }
195
196 private class ClassLoadingUi implements IPageUI {
197
198 private final ChartCanvas classLoadingChart;
199 private final ItemList classLoadingTable;
200 private final ItemList classUnloadingTable;
201 private final ItemList classDefineTable;
202 private final ItemList classLoaderStatisticsTable;
203 private FilterComponent classLoadingFilter;
204 private FilterComponent classUnloadingFilter;
205 private FilterComponent classDefineFilter;
206 private FilterComponent classLoaderStatisticsFilter;
207 private final SashForm sash;
208 private final IPageContainer pageContainer;
209 private IItemCollection selectionItems;
210 private ItemHistogram classloaderHistogram;
211 private FilterComponent classloaderHistogramFilter;
212 private final IAction classLoadAction = DataPageToolkit.createTypeCheckAction(CLASS_LOAD, JdkTypeIDs.CLASS_LOAD,
213 Messages.ClassLoadingPage_CLASS_LOADING_ACTION, Messages.ClassLoadingPage_CLASS_LOADING_ACTION_DESC,
214 b -> updateChart());
215 private final IAction classUnloadAction = DataPageToolkit.createTypeCheckAction(CLASS_UNLOAD,
216 JdkTypeIDs.CLASS_UNLOAD, Messages.ClassLoadingPage_CLASS_UNLOADING_ACTION,
217 Messages.ClassLoadingPage_CLASS_UNLOADING_ACTION_DESC, b -> updateChart());
218 private final Stream<IAction> statsActions = Stream
219 .of(JdkAttributes.CLASSLOADER_LOADED_COUNT, JdkAttributes.CLASSLOADER_UNLOADED_COUNT)
220 .map(a -> DataPageToolkit.createAttributeCheckAction(a, b -> updateChart()));
221 private final List<IAction> allChartSeriesActions = Stream
222 .concat(Stream.of(classLoadAction, classUnloadAction), statsActions).collect(Collectors.toList());
223 private CTabFolder tabFolder;
224 private CTabFolder classloaderFolder;
225 private XYChart chart;
226 private IRange<IQuantity> timeRange;
227 private FlavorSelector flavorSelector;
228
229 ClassLoadingUi(Composite parent, FormToolkit toolkit, IPageContainer pageContainer, IState state) {
230 this.pageContainer = pageContainer;
231
232 Form form = DataPageToolkit.createForm(parent, toolkit, getName(), getIcon());
233
234 sash = new SashForm(form.getBody(), SWT.VERTICAL);
235
236 Composite chartComp = new Composite(sash, SWT.NONE);
237 chartComp.setLayout(new GridLayout());
238 Control legend = ActionUiToolkit.buildCheckboxControl(chartComp, allChartSeriesActions.stream(), false);
239 legend.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
240 ActionToolkit.loadCheckState(state.getChild(CHART), allChartSeriesActions.stream());
241
242 chart = new XYChart(pageContainer.getRecordingRange(), RendererToolkit.empty(), 180);
243 chart.setVisibleRange(timelineRange.getStart(), timelineRange.getEnd());
244 chart.addVisibleRangeListener(r -> timelineRange = r);
245 classLoadingChart = new ChartCanvas(chartComp);
246 classLoadingChart.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
247 DataPageToolkit.createChartTimestampTooltip(classLoadingChart);
248 DataPageToolkit.setChart(classLoadingChart, chart, pageContainer::showSelection, this::onChartSelection);
249 SelectionStoreActionToolkit.addSelectionStoreRangeActions(pageContainer.getSelectionStore(), chart,
250 JfrAttributes.LIFETIME, Messages.ClassLoadingPage_CLASS_LOADING_TIMELINE_SELECTION,
251 classLoadingChart.getContextMenu());
252
253 classloaderFolder = new CTabFolder(sash, SWT.NONE);
254
255 classloaderHistogram = CLASSLOADER_HISTOGRAM.buildWithoutBorder(classloaderFolder,
256 JdkAttributes.CLASS_DEFINING_CLASSLOADER, TableSettings.forState(state.getChild(HISTOGRAM)));
257 classloaderHistogramFilter = FilterComponent.createFilterComponent(classloaderHistogram, null,
258 getDataSource().getItems().apply(JdkFilters.CLASS_LOAD_OR_UNLOAD),
259 pageContainer.getSelectionStore()::getSelections, this::onHistogramFilterChange);
260 classloaderHistogram.getManager().getViewer().addSelectionChangedListener(
261 e -> pageContainer.showSelection(classloaderHistogram.getSelection().getItems()));
262 MCContextMenuManager classLoaderHistogramMm = MCContextMenuManager
263 .create(classloaderHistogram.getManager().getViewer().getControl());
264 ColumnMenusFactory.addDefaultMenus(classloaderHistogram.getManager(), classLoaderHistogramMm);
265 SelectionStoreActionToolkit.addSelectionStoreActions(pageContainer.getSelectionStore(),
266 classloaderHistogram, Messages.ClassLoadingPage_CLASS_LOADING_HISTOGRAM_SELECTION,
267 classLoaderHistogramMm);
268 classLoaderHistogramMm.add(classloaderHistogramFilter.getShowFilterAction());
269 classLoaderHistogramMm.add(classloaderHistogramFilter.getShowSearchAction());
270 classloaderHistogramFilter.loadState(state.getChild(HISTOGRAM_FILTER));
271 DataPageToolkit.addTabItem(classloaderFolder, classloaderHistogramFilter.getComponent(),
272 Messages.ClassLoadingPage_CLASS_LOADER_TAB);
273
274 ItemHistogramWithInput.chain(classloaderHistogram, this::updateTables);
275
276 classLoaderStatisticsTable = CLASS_LOADER_STATISTICS_LIST.buildWithoutBorder(classloaderFolder,
277 TableSettings.forState(state.getChild(CLASS_LOADER_STATISTICS_TABLE)));
278 classLoaderStatisticsTable.getManager().getViewer().addSelectionChangedListener(e -> {
279 // The standard aggregators will skip the null classloader, so we need to do this manually.
280 IItemCollection selection = ItemCollectionToolkit.build(classLoaderStatisticsTable.getSelection().get());
281 Stream<IMCClassLoader> stream = ItemCollectionToolkit.values(selection, JdkAttributes.CLASSLOADER).get().distinct();
282 Set<IMCClassLoader> selected = stream.collect(Collectors.toSet());
283 IItemFilter selectionFilter = ItemFilters.and(ItemFilters.or(JdkFilters.CLASS_LOAD_OR_UNLOAD,
284 JdkFilters.CLASS_DEFINE), ItemFilters.memberOf(JdkAttributes.CLASS_DEFINING_CLASSLOADER, selected));
285 IItemCollection filteredItems = getDataSource().getItems().apply(selectionFilter);
286 pageContainer.showSelection(filteredItems);
287 updateTables(filteredItems);
288 });
289 classLoaderStatisticsFilter = FilterComponent.createFilterComponent(classLoaderStatisticsTable, null,
290 getDataSource().getItems().apply(JdkFilters.CLASS_LOADER_STATISTICS),
291 pageContainer.getSelectionStore()::getSelections, this::onClassLoaderStatisticsFilterChange);
292 MCContextMenuManager classLoaderStatisticsTableMm = MCContextMenuManager
293 .create(classLoaderStatisticsTable.getManager().getViewer().getControl());
294 ColumnMenusFactory.addDefaultMenus(classLoaderStatisticsTable.getManager(), classLoaderStatisticsTableMm);
295 SelectionStoreActionToolkit.addSelectionStoreActions(pageContainer.getSelectionStore(), classLoaderStatisticsTable,
296 Messages.ClassLoadingPage_CLASS_LOADER_STATISTICS_LIST_SELECTION, classLoaderStatisticsTableMm);
297 classLoaderStatisticsTableMm.add(classLoaderStatisticsFilter.getShowFilterAction());
298 classLoaderStatisticsTableMm.add(classLoaderStatisticsFilter.getShowSearchAction());
299 classLoaderStatisticsFilter.loadState(state.getChild(CLASS_LOADER_STATISTICS_FILTER));
300 DataPageToolkit.addTabItem(classloaderFolder, classLoaderStatisticsFilter.getComponent(),
301 Messages.ClassLoadingPage_CLASS_LOADER_STATISTICS_TAB_TITLE);
302
303 tabFolder = new CTabFolder(sash, SWT.NONE);
304
305 classLoadingTable = CLASS_LOADING_LIST.buildWithoutBorder(tabFolder,
306 TableSettings.forState(state.getChild(CLASS_LOADING_TABLE)));
307 classLoadingTable.getManager().getViewer().addSelectionChangedListener(e -> pageContainer
308 .showSelection(ItemCollectionToolkit.build(classLoadingTable.getSelection().get())));
309 classLoadingFilter = FilterComponent.createFilterComponent(classLoadingTable, null,
310 getDataSource().getItems().apply(JdkFilters.CLASS_LOAD),
311 pageContainer.getSelectionStore()::getSelections, this::onClassLoadFilterChange);
312 MCContextMenuManager classLoadingTableMm = MCContextMenuManager
313 .create(classLoadingTable.getManager().getViewer().getControl());
314 ColumnMenusFactory.addDefaultMenus(classLoadingTable.getManager(), classLoadingTableMm);
315 SelectionStoreActionToolkit.addSelectionStoreActions(pageContainer.getSelectionStore(), classLoadingTable,
316 Messages.ClassLoadingPage_CLASS_LOADING_LIST_SELECTION, classLoadingTableMm);
317 classLoadingTableMm.add(classLoadingFilter.getShowFilterAction());
318 classLoadingTableMm.add(classLoadingFilter.getShowSearchAction());
319 classLoadingFilter.loadState(state.getChild(CLASS_LOADING_FILTER));
320 DataPageToolkit.addTabItem(tabFolder, classLoadingFilter.getComponent(),
321 Messages.ClassLoadingPage_CLASS_LOADING_TAB_TITLE);
322
323 classDefineTable = CLASS_DEFINE_LIST.buildWithoutBorder(tabFolder,
324 TableSettings.forState(state.getChild(CLASS_DEFINE_TABLE)));
325 classDefineTable.getManager().getViewer().addSelectionChangedListener(e -> pageContainer
326 .showSelection(ItemCollectionToolkit.build(classDefineTable.getSelection().get())));
327 classDefineFilter = FilterComponent.createFilterComponent(classDefineTable, null,
328 getDataSource().getItems().apply(JdkFilters.CLASS_DEFINE),
329 pageContainer.getSelectionStore()::getSelections, this::onClassDefineFilterChange);
330 MCContextMenuManager classDefineTableMm = MCContextMenuManager
331 .create(classDefineTable.getManager().getViewer().getControl());
332 ColumnMenusFactory.addDefaultMenus(classDefineTable.getManager(), classDefineTableMm);
333 SelectionStoreActionToolkit.addSelectionStoreActions(pageContainer.getSelectionStore(), classDefineTable,
334 Messages.ClassLoadingPage_CLASS_DEFINE_LIST_SELECTION, classDefineTableMm);
335 classDefineTableMm.add(classDefineFilter.getShowFilterAction());
336 classDefineTableMm.add(classDefineFilter.getShowSearchAction());
337 classDefineFilter.loadState(state.getChild(CLASS_DEFINE_FILTER));
338 DataPageToolkit.addTabItem(tabFolder, classDefineFilter.getComponent(),
339 Messages.ClassLoadingPage_CLASS_DEFINE_TAB_TITLE);
340
341 classUnloadingTable = CLASS_UNLOADING_LIST.buildWithoutBorder(tabFolder,
342 TableSettings.forState(state.getChild(CLASS_UNLOADING_TABLE)));
343 classUnloadingTable.getManager().getViewer().addSelectionChangedListener(e -> pageContainer
344 .showSelection(ItemCollectionToolkit.build(classUnloadingTable.getSelection().get())));
345 classUnloadingFilter = FilterComponent.createFilterComponent(classUnloadingTable, null,
346 getDataSource().getItems().apply(JdkFilters.CLASS_UNLOAD),
347 pageContainer.getSelectionStore()::getSelections, this::onClassUnloadFilterChange);
348 MCContextMenuManager classUnloadingTableMm = MCContextMenuManager
349 .create(classUnloadingTable.getManager().getViewer().getControl());
350 ColumnMenusFactory.addDefaultMenus(classUnloadingTable.getManager(), classUnloadingTableMm);
351 SelectionStoreActionToolkit.addSelectionStoreActions(pageContainer.getSelectionStore(), classUnloadingTable,
352 Messages.ClassLoadingPage_CLASS_UNLOADING_LIST_SELECTION, classUnloadingTableMm);
353 classUnloadingTableMm.add(classUnloadingFilter.getShowFilterAction());
354 classUnloadingTableMm.add(classUnloadingFilter.getShowSearchAction());
355 classUnloadingFilter.loadState(state.getChild(CLASS_UNLOADING_FILTER));
356 DataPageToolkit.addTabItem(tabFolder, classUnloadingFilter.getComponent(),
357 Messages.ClassLoadingPage_CLASS_UNLOADING_TAB_TITLE);
358
359 tabFolder.setSelection(tabFolderIndex);
360 classloaderFolder.setSelection(tabFolderIndex);
361
362 PersistableSashForm.loadState(sash, state.getChild(SASH));
363 flavorSelector = FlavorSelector.itemsWithTimerange(form, TABLE_FILTER, getDataSource().getItems(),
364 pageContainer, this::onInputSelected, this::onShow, flavorSelectorState);
365 addResultActions(form);
366
367 onHistogramFilterChange(histogramFilter);
368 onClassLoadFilterChange(classLoadTableFilter);
369 onClassUnloadFilterChange(classUnloadTableFilter);
370 onClassDefineFilterChange(classDefineTableFilter);
371 onClassLoaderStatisticsFilterChange(classLoaderStatisticsTableFilter);
372
373 classloaderHistogram.getManager().setSelectionState(histogramSelection);
374 classLoadingTable.getManager().setSelectionState(classLoadingTableSelection);
375 classUnloadingTable.getManager().setSelectionState(classUnloadingTableSelection);
376 classDefineTable.getManager().setSelectionState(classDefineTableSelection);
377 classLoaderStatisticsTable.getManager().setSelectionState(classLoaderStatisticsTableSelection);
378 }
379
380 private void onHistogramFilterChange(IItemFilter filter) {
381 classloaderHistogramFilter.filterChangeHelper(filter, classloaderHistogram,
382 getDataSource().getItems().apply(ItemFilters.or(JdkFilters.CLASS_LOAD_OR_UNLOAD, JdkFilters.CLASS_DEFINE)));
383 if (classLoadingFilter != null) {
384 classLoadingFilter.notifyListener();
385 }
386 if (classUnloadingFilter != null) {
387 classUnloadingFilter.notifyListener();
388 }
389 if (classDefineFilter != null) {
390 classDefineFilter.notifyListener();
391 }
392 if (classLoaderStatisticsFilter != null) {
393 classLoaderStatisticsFilter.notifyListener();
394 }
395 histogramFilter = filter;
396 }
397
398 private void onClassLoadFilterChange(IItemFilter filter) {
399 classLoadingFilter.filterChangeHelper(filter, classLoadingTable,
400 getDataSource().getItems().apply(JdkFilters.CLASS_LOAD));
401 classLoadTableFilter = filter;
402 }
403
404 private void onClassUnloadFilterChange(IItemFilter filter) {
405 classUnloadingFilter.filterChangeHelper(filter, classUnloadingTable,
406 getDataSource().getItems().apply(JdkFilters.CLASS_UNLOAD));
407 classUnloadTableFilter = filter;
408 }
409
410 private void onClassDefineFilterChange(IItemFilter filter) {
411 classDefineFilter.filterChangeHelper(filter, classDefineTable,
412 getDataSource().getItems().apply(JdkFilters.CLASS_DEFINE));
413 classDefineTableFilter = filter;
414 }
415
416 private void onClassLoaderStatisticsFilterChange(IItemFilter filter) {
417 classLoaderStatisticsFilter.filterChangeHelper(filter, classLoaderStatisticsTable,
418 getDataSource().getItems().apply(JdkFilters.CLASS_LOADER_STATISTICS));
419 classLoaderStatisticsTableFilter = filter;
420 }
421
422 @Override
423 public void saveTo(IWritableState state) {
424 PersistableSashForm.saveState(sash, state.createChild(SASH));
425 classloaderHistogram.getManager().getSettings().saveState(state.createChild(HISTOGRAM));
426 classLoadingTable.getManager().getSettings().saveState(state.createChild(CLASS_LOADING_TABLE));
427 classUnloadingTable.getManager().getSettings().saveState(state.createChild(CLASS_UNLOADING_TABLE));
428 classDefineTable.getManager().getSettings().saveState(state.createChild(CLASS_DEFINE_TABLE));
429 classLoaderStatisticsTable.getManager().getSettings().saveState(state.createChild(CLASS_LOADER_STATISTICS_TABLE));
430 classloaderHistogramFilter.saveState(state.createChild(HISTOGRAM_FILTER));
431 classLoadingFilter.saveState(state.createChild(CLASS_LOADING_FILTER));
432 classUnloadingFilter.saveState(state.createChild(CLASS_UNLOADING_FILTER));
433 classDefineFilter.saveState(state.createChild(CLASS_DEFINE_FILTER));
434 classLoaderStatisticsFilter.saveState(state.createChild(CLASS_LOADER_STATISTICS_FILTER));
435 ActionToolkit.saveCheckState(state.createChild(CHART), allChartSeriesActions.stream());
436
437 saveToLocal();
438 }
439
440 private void saveToLocal() {
441 histogramSelection = classloaderHistogram.getManager().getSelectionState();
442 classLoadingTableSelection = classLoadingTable.getManager().getSelectionState();
443 classUnloadingTableSelection = classUnloadingTable.getManager().getSelectionState();
444 classDefineTableSelection = classDefineTable.getManager().getSelectionState();
445 classLoaderStatisticsTableSelection = classLoaderStatisticsTable.getManager().getSelectionState();
446 tabFolderIndex = tabFolder.getSelectionIndex();
447 flavorSelectorState = flavorSelector.getFlavorSelectorState();
448 }
449
450 private void onShow(Boolean show) {
451 IRange<IQuantity> range = show ? timeRange : pageContainer.getRecordingRange();
452 chart.setVisibleRange(range.getStart(), range.getEnd());
453 updateChart();
454 }
455
456 private void onInputSelected(IItemCollection items, IRange<IQuantity> timeRange) {
457 selectionItems = items;
458 this.timeRange = timeRange;
459 updateHistogram(getItems());
460 updateTables(getItems());
461 updateChart();
462 }
463
464 private IItemCollection getItems() {
465 return selectionItems != null ? selectionItems : getDataSource().getItems();
486 Messages.ClassLoadingPage_AGGR_CLASSES_UNLOADED_DESC, getItems().apply(JdkFilters.CLASS_UNLOAD),
487 Aggregators.count(Messages.ClassLoadingPage_AGGR_CLASSES_UNLOADED,
488 Messages.ClassLoadingPage_AGGR_CLASSES_UNLOADED_DESC, JdkFilters.CLASS_UNLOAD),
489 TypeLabelProvider.getColor(JdkTypeIDs.CLASS_UNLOAD)));
490 }
491 classLoadingChart.replaceRenderer(RendererToolkit.uniformRows(rows));
492 }
493
494 private boolean isAttributeEnabled(IAttribute<IQuantity> attr) {
495 return allChartSeriesActions.stream().filter(a -> attr.getIdentifier().equals(a.getId())).findAny().get()
496 .isChecked();
497 }
498
499 private void updateHistogram(IItemCollection items) {
500 if (classloaderHistogram != null) {
501 classloaderHistogram.show(items.apply(JdkFilters.CLASS_LOAD_OR_UNLOAD));
502 }
503 }
504
505 private void updateTables(IItemCollection selectedItems) {
506 if (classLoadingTable != null && classUnloadingTable != null && classDefineTable != null
507 && classLoaderStatisticsTable != null) {
508 classLoadingTable.show(selectedItems.apply(JdkQueries.CLASS_LOAD.getFilter()));
509 classUnloadingTable.show(selectedItems.apply(JdkQueries.CLASS_UNLOAD.getFilter()));
510 classDefineTable.show(selectedItems.apply(JdkQueries.CLASS_DEFINE.getFilter()));
511 }
512 }
513
514 private void onChartSelection(IRange<IQuantity> range) {
515 // FIXME: Make this depend on the legend as well? And maybe on which chart row has been selected?
516 IItemCollection itemsInRange = range != null ? getItems().apply(ItemFilters
517 .matchRange(RangeMatchPolicy.CENTER_CONTAINED_IN_RIGHT_OPEN, JfrAttributes.LIFETIME, range))
518 : getItems();
519 updateTables(itemsInRange);
520 updateHistogram(itemsInRange);
521 }
522
523 }
524
525 private static final String SASH = "sash"; //$NON-NLS-1$
526 private static final String HISTOGRAM = "histogram"; //$NON-NLS-1$
527 private static final String HISTOGRAM_FILTER = "histogramFilter"; //$NON-NLS-1$
528 private static final String CLASS_LOADING_TABLE = "classLoadingTable"; //$NON-NLS-1$
529 private static final String CLASS_UNLOADING_TABLE = "classUnloadingTable"; //$NON-NLS-1$
530 private static final String CLASS_DEFINE_TABLE = "classDefineTable"; //$NON-NLS-1$
531 private static final String CLASS_LOADER_STATISTICS_TABLE = "classLoaderStatisticsTable"; //$NON-NLS-1$
532 private static final String CLASS_LOADING_FILTER = "classLoadingFilter"; //$NON-NLS-1$
533 private static final String CLASS_UNLOADING_FILTER = "classUnloadingFilter"; //$NON-NLS-1$
534 private static final String CLASS_DEFINE_FILTER = "classDefineFilter"; //$NON-NLS-1$
535 private static final String CLASS_LOADER_STATISTICS_FILTER = "classLoaderStatisticsFilter"; //$NON-NLS-1$
536 private static final String CHART = "chart"; //$NON-NLS-1$
537
538 @Override
539 public IPageUI display(Composite parent, FormToolkit toolkit, IPageContainer pageContainer, IState state) {
540 return new ClassLoadingUi(parent, toolkit, pageContainer, state);
541 }
542
543 private SelectionState histogramSelection;
544 private SelectionState classLoadingTableSelection;
545 private SelectionState classUnloadingTableSelection;
546 private SelectionState classDefineTableSelection;
547 private SelectionState classLoaderStatisticsTableSelection;
548 private IItemFilter histogramFilter;
549 private IItemFilter classLoadTableFilter;
550 private IItemFilter classUnloadTableFilter;
551 private IItemFilter classDefineTableFilter;
552 private IItemFilter classLoaderStatisticsTableFilter;
553 private int tabFolderIndex = 0;
554 private IRange<IQuantity> timelineRange;
555 private FlavorSelectorState flavorSelectorState;
556
557 public ClassLoadingPage(IPageDefinition dpd, StreamModel items, IPageContainer editor) {
558 super(dpd, items, editor);
559 timelineRange = editor.getRecordingRange();
560 }
561
562 @Override
563 public IItemFilter getDefaultSelectionFilter() {
564 return ItemFilters.or(TABLE_FILTER, JdkFilters.CLASS_LOAD_STATISTICS);
565 }
566
567 }
|