1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * The contents of this file are subject to the terms of either the Universal Permissive License 7 * v 1.0 as shown at http://oss.oracle.com/licenses/upl 8 * 9 * or the following license: 10 * 11 * Redistribution and use in source and binary forms, with or without modification, are permitted 12 * provided that the following conditions are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions 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.awt.Color; 36 import java.util.ArrayList; 37 import java.util.Arrays; 38 import java.util.List; 39 40 import org.eclipse.jface.resource.ImageDescriptor; 41 import org.eclipse.osgi.util.NLS; 42 import org.eclipse.swt.SWT; 43 import org.eclipse.swt.custom.CTabFolder; 44 import org.eclipse.swt.custom.CTabItem; 45 import org.eclipse.swt.custom.SashForm; 46 import org.eclipse.swt.events.SelectionAdapter; 47 import org.eclipse.swt.events.SelectionEvent; 48 import org.eclipse.swt.widgets.Composite; 49 import org.eclipse.ui.forms.widgets.Form; 50 import org.eclipse.ui.forms.widgets.FormToolkit; 51 import org.openjdk.jmc.common.IState; 52 import org.openjdk.jmc.common.IWritableState; 53 import org.openjdk.jmc.common.item.IItem; 54 import org.openjdk.jmc.common.item.IItemCollection; 55 import org.openjdk.jmc.common.item.IItemFilter; 56 import org.openjdk.jmc.common.item.ItemFilters; 57 import org.openjdk.jmc.common.unit.IQuantity; 58 import org.openjdk.jmc.common.unit.IRange; 59 import org.openjdk.jmc.common.unit.UnitLookup; 60 import org.openjdk.jmc.common.util.ColorToolkit; 61 import org.openjdk.jmc.flightrecorder.JfrAttributes; 62 import org.openjdk.jmc.flightrecorder.jdk.JdkAggregators; 63 import org.openjdk.jmc.flightrecorder.jdk.JdkAttributes; 64 import org.openjdk.jmc.flightrecorder.jdk.JdkFilters; 65 import org.openjdk.jmc.flightrecorder.jdk.JdkTypeIDs; 66 import org.openjdk.jmc.flightrecorder.rules.util.JfrRuleTopics; 67 import org.openjdk.jmc.flightrecorder.ui.FlightRecorderUI; 68 import org.openjdk.jmc.flightrecorder.ui.IDataPageFactory; 69 import org.openjdk.jmc.flightrecorder.ui.IDisplayablePage; 70 import org.openjdk.jmc.flightrecorder.ui.IPageContainer; 71 import org.openjdk.jmc.flightrecorder.ui.IPageDefinition; 72 import org.openjdk.jmc.flightrecorder.ui.IPageUI; 73 import org.openjdk.jmc.flightrecorder.ui.ItemCollectionToolkit; 74 import org.openjdk.jmc.flightrecorder.ui.StreamModel; 75 import org.openjdk.jmc.flightrecorder.ui.common.AbstractDataPage; 76 import org.openjdk.jmc.flightrecorder.ui.common.DataPageToolkit; 77 import org.openjdk.jmc.flightrecorder.ui.common.DurationPercentileTable; 78 import org.openjdk.jmc.flightrecorder.ui.common.DurationPercentileTable.DurationPercentileTableBuilder; 79 import org.openjdk.jmc.flightrecorder.ui.common.FilterComponent; 80 import org.openjdk.jmc.flightrecorder.ui.common.FlavorSelector; 81 import org.openjdk.jmc.flightrecorder.ui.common.FlavorSelector.FlavorSelectorState; 82 import org.openjdk.jmc.flightrecorder.ui.common.ImageConstants; 83 import org.openjdk.jmc.flightrecorder.ui.common.ItemHistogram; 84 import org.openjdk.jmc.flightrecorder.ui.common.ItemHistogram.HistogramSelection; 85 import org.openjdk.jmc.flightrecorder.ui.common.ItemHistogram.ItemHistogramBuilder; 86 import org.openjdk.jmc.flightrecorder.ui.common.ItemList; 87 import org.openjdk.jmc.flightrecorder.ui.common.ItemList.ItemListBuilder; 88 import org.openjdk.jmc.flightrecorder.ui.common.TypeLabelProvider; 89 import org.openjdk.jmc.flightrecorder.ui.messages.internal.Messages; 90 import org.openjdk.jmc.flightrecorder.ui.selection.SelectionStoreActionToolkit; 91 import org.openjdk.jmc.ui.charts.IXDataRenderer; 92 import org.openjdk.jmc.ui.charts.RendererToolkit; 93 import org.openjdk.jmc.ui.charts.XYChart; 94 import org.openjdk.jmc.ui.column.ColumnManager.SelectionState; 95 import org.openjdk.jmc.ui.column.ColumnMenusFactory; 96 import org.openjdk.jmc.ui.column.TableSettings; 97 import org.openjdk.jmc.ui.column.TableSettings.ColumnSettings; 98 import org.openjdk.jmc.ui.handlers.MCContextMenuManager; 99 import org.openjdk.jmc.ui.layout.SimpleLayout; 100 import org.openjdk.jmc.ui.layout.SimpleLayoutData; 101 import org.openjdk.jmc.ui.misc.ChartCanvas; 102 import org.openjdk.jmc.ui.misc.PersistableSashForm; 103 104 public class FileIOPage extends AbstractDataPage { 105 public static class FileIOPageFactory implements IDataPageFactory { 106 107 @Override 108 public String getName(IState state) { 109 return Messages.FileIOPage_PAGE_NAME; 110 } 111 112 @Override 113 public ImageDescriptor getImageDescriptor(IState state) { 114 return FlightRecorderUI.getDefault().getMCImageDescriptor(ImageConstants.PAGE_IO); 115 } 116 117 @Override 118 public String[] getTopics(IState state) { 119 return new String[] {JfrRuleTopics.FILE_IO_TOPIC}; 120 } 121 122 @Override 123 public IDisplayablePage createPage(IPageDefinition dpd, StreamModel items, IPageContainer editor) { 124 return new FileIOPage(dpd, items, editor); 125 } 126 127 } 128 129 private static final Color WRITE_COLOR = TypeLabelProvider.getColor(JdkTypeIDs.FILE_WRITE); 130 private static final Color READ_COLOR = TypeLabelProvider.getColor(JdkTypeIDs.FILE_READ); 131 private static final Color WRITE_ALPHA_COLOR = ColorToolkit.withAlpha(WRITE_COLOR, 80); 132 private static final Color READ_ALPHA_COLOR = ColorToolkit.withAlpha(READ_COLOR, 80); 133 private static final IItemFilter TABLE_ITEMS = ItemFilters.type(JdkTypeIDs.FILE_READ, JdkTypeIDs.FILE_WRITE); 134 private static final String TOTAL_TIME = "totalTime"; //$NON-NLS-1$ 135 private static final String MAX_TIME = "maxTime"; //$NON-NLS-1$ 136 private static final String AVG_TIME = "avgTime"; //$NON-NLS-1$ 137 private static final String STDDEV_TIME = "stddevTime"; //$NON-NLS-1$ 138 private static final String READ_COUNT = "readCount"; //$NON-NLS-1$ 139 private static final String WRITE_COUNT = "writeCount"; //$NON-NLS-1$ 140 private static final String READ_SIZE = "readSize"; //$NON-NLS-1$ 141 private static final String WRITE_SIZE = "writeSize"; //$NON-NLS-1$ 142 private static final String READ_EOF = "endOfFile"; //$NON-NLS-1$ 143 private static final String PERCENTILE_READ_TIME = "percentileReadTime"; //$NON-NLS-1$ 144 private static final String PERCENTILE_READ_COUNT = "percentileReadCount"; //$NON-NLS-1$ 145 private static final String PERCENTILE_WRITE_TIME = "percentileWriteTime"; //$NON-NLS-1$ 146 private static final String PERCENTILE_WRITE_COUNT = "percentileWriteCount"; //$NON-NLS-1$ 147 148 private static final ItemHistogramBuilder HISTOGRAM = new ItemHistogramBuilder(); 149 private static final ItemListBuilder LIST = new ItemListBuilder(); 150 private static final DurationPercentileTableBuilder PERCENTILES = new DurationPercentileTableBuilder(); 151 152 static { 153 HISTOGRAM.addCountColumn(); 154 HISTOGRAM.addColumn(TOTAL_TIME, JdkAggregators.TOTAL_IO_TIME); 155 HISTOGRAM.addColumn(MAX_TIME, JdkAggregators.MAX_IO_TIME); 156 HISTOGRAM.addColumn(AVG_TIME, JdkAggregators.AVG_IO_TIME); 157 HISTOGRAM.addColumn(STDDEV_TIME, JdkAggregators.STDDEV_IO_TIME); 158 HISTOGRAM.addColumn(READ_COUNT, JdkAggregators.FILE_READ_COUNT); 159 HISTOGRAM.addColumn(WRITE_COUNT, JdkAggregators.FILE_WRITE_COUNT); 160 HISTOGRAM.addColumn(READ_SIZE, JdkAggregators.FILE_READ_SIZE); 161 HISTOGRAM.addColumn(WRITE_SIZE, JdkAggregators.FILE_WRITE_SIZE); 162 LIST.addColumn(JdkAttributes.IO_PATH); 163 LIST.addColumn(JfrAttributes.START_TIME); 164 LIST.addColumn(JfrAttributes.END_TIME); 165 LIST.addColumn(JfrAttributes.DURATION); 166 LIST.addColumn(JdkAttributes.IO_FILE_BYTES_READ); 167 LIST.addColumn(JdkAttributes.IO_FILE_BYTES_WRITTEN); 168 LIST.addColumn(JfrAttributes.EVENT_THREAD); 169 LIST.addColumn(JdkAttributes.IO_FILE_READ_EOF); 170 171 PERCENTILES.addSeries(PERCENTILE_READ_TIME, Messages.FileIOPage_ROW_FILE_READ, 172 PERCENTILE_READ_COUNT, JdkAggregators.FILE_READ_COUNT.getName(), JdkTypeIDs.FILE_READ); 173 PERCENTILES.addSeries(PERCENTILE_WRITE_TIME, Messages.FileIOPage_ROW_FILE_WRITE, 174 PERCENTILE_WRITE_COUNT, JdkAggregators.FILE_WRITE_COUNT.getName(), JdkTypeIDs.FILE_WRITE); 175 } 176 177 private class IOPageUi implements IPageUI { 178 private static final String FILE_IO_TABLE = "fileIoTable"; //$NON-NLS-1$ 179 private static final String FILE_IO_LIST = "fileIoList"; //$NON-NLS-1$ 180 private static final String SASH_ELEMENT = "sash"; //$NON-NLS-1$ 181 private static final String LIST_ELEMENT = "eventList"; //$NON-NLS-1$ 182 private static final String TABLE_ELEMENT = "table"; //$NON-NLS-1$ 183 private static final String PERCENTILE_TABLE_ELEMENT = "percentileTable"; //$NON-NLS-1$ 184 185 private final ChartCanvas timelineCanvas; 186 private final ChartCanvas durationCanvas; 187 private final ChartCanvas sizeCanvas; 188 private XYChart timelineChart; 189 private IRange<IQuantity> timeRange; 190 private IItemCollection selectionItems; 191 private final ItemList itemList; 192 private final ItemHistogram table; 193 private final SashForm sash; 194 private final IPageContainer pageContainer; 195 private FilterComponent tableFilter; 196 private FilterComponent itemListFilter; 197 private FlavorSelector flavorSelector; 198 private DurationPercentileTable percentileTable; 199 private Composite durationParent; 200 201 IOPageUi(Composite parent, FormToolkit toolkit, IPageContainer pageContainer, IState state) { 202 this.pageContainer = pageContainer; 203 Form form = DataPageToolkit.createForm(parent, toolkit, getName(), getIcon()); 204 sash = new SashForm(form.getBody(), SWT.VERTICAL); 205 toolkit.adapt(sash); 206 207 addResultActions(form); 208 209 table = HISTOGRAM.buildWithoutBorder(sash, JdkAttributes.IO_PATH, 210 getTableSettings(state.getChild(TABLE_ELEMENT))); 211 MCContextMenuManager mm = MCContextMenuManager.create(table.getManager().getViewer().getControl()); 212 ColumnMenusFactory.addDefaultMenus(table.getManager(), mm); 213 SelectionStoreActionToolkit.addSelectionStoreActions(pageContainer.getSelectionStore(), table, 214 Messages.FileIOPage_HISTOGRAM_SELECTION, mm); 215 table.getManager().getViewer().addSelectionChangedListener(e -> updateDetails()); 216 table.getManager().getViewer() 217 .addSelectionChangedListener(e -> pageContainer.showSelection(table.getSelection().getItems())); 218 tableFilter = FilterComponent.createFilterComponent(table, FileIOPage.this.tableFilter, 219 getDataSource().getItems().apply(TABLE_ITEMS), pageContainer.getSelectionStore()::getSelections, 220 this::onTableFilterChange); 221 mm.add(tableFilter.getShowFilterAction()); 222 mm.add(tableFilter.getShowSearchAction()); 223 224 CTabFolder tabFolder = new CTabFolder(sash, SWT.NONE); 225 toolkit.adapt(tabFolder); 226 CTabItem t1 = new CTabItem(tabFolder, SWT.NONE); 227 t1.setToolTipText(Messages.IO_PAGE_TIMELINE_DESCRIPTION); 228 timelineCanvas = new ChartCanvas(tabFolder); 229 t1.setText(Messages.PAGES_TIMELINE); 230 t1.setControl(timelineCanvas); 231 DataPageToolkit.createChartTimestampTooltip(timelineCanvas); 232 233 CTabItem t2 = new CTabItem(tabFolder, SWT.NONE); 234 durationParent = toolkit.createComposite(tabFolder); 235 durationParent.setLayout(new SimpleLayout()); 236 t2.setToolTipText(Messages.IO_PAGE_DURATIONS_DESCRIPTION); 237 durationCanvas = new ChartCanvas(durationParent); 238 durationCanvas.setLayoutData(new SimpleLayoutData(3.5f)); 239 DataPageToolkit.createChartTooltip(durationCanvas); 240 241 percentileTable = PERCENTILES.build(durationParent, 242 TableSettings.forState(state.getChild(PERCENTILE_TABLE_ELEMENT))); 243 percentileTable.getManager().getViewer().getControl().setLayoutData(new SimpleLayoutData(6.5f)); 244 MCContextMenuManager percentileTableMm = MCContextMenuManager 245 .create(percentileTable.getManager().getViewer().getControl()); 246 ColumnMenusFactory.addDefaultMenus(percentileTable.getManager(), percentileTableMm); 247 SelectionStoreActionToolkit.addSelectionStoreActions(percentileTable.getManager().getViewer(), 248 pageContainer.getSelectionStore(), percentileTable::getSelectedItems, 249 Messages.FileIOPage_PERCENTILE_SELECTION, percentileTableMm); 250 t2.setText(Messages.PAGES_DURATIONS); 251 t2.setControl(durationParent); 252 253 CTabItem t3 = new CTabItem(tabFolder, SWT.NONE); 254 t3.setToolTipText(Messages.IO_PAGE_SIZE_DESCRIPTION); 255 sizeCanvas = new ChartCanvas(tabFolder); 256 t3.setText(Messages.PAGES_SIZE); 257 t3.setControl(sizeCanvas); 258 DataPageToolkit.createChartTooltip(sizeCanvas); 259 260 CTabItem t4 = new CTabItem(tabFolder, SWT.NONE); 261 t4.setToolTipText(Messages.IO_PAGE_EVENT_LOG_DESCRIPTION); 262 itemList = LIST.buildWithoutBorder(tabFolder, getTableSettings(state.getChild(LIST_ELEMENT))); 263 MCContextMenuManager itemListMm = MCContextMenuManager 264 .create(itemList.getManager().getViewer().getControl()); 265 ColumnMenusFactory.addDefaultMenus(itemList.getManager(), itemListMm); 266 SelectionStoreActionToolkit.addSelectionStoreActions(pageContainer.getSelectionStore(), itemList, 267 Messages.FileIOPage_LOG_SELECTION, itemListMm); 268 itemList.getManager().getViewer().addSelectionChangedListener( 269 e -> pageContainer.showSelection(ItemCollectionToolkit.build(itemList.getSelection().get()))); 270 t4.setText(Messages.PAGES_EVENT_LOG); 271 itemListFilter = FilterComponent.createFilterComponent(itemList, FileIOPage.this.itemListFilter, 272 getDataSource().getItems().apply(TABLE_ITEMS), pageContainer.getSelectionStore()::getSelections, 273 this::onListFilterChange); 274 itemListMm.add(itemListFilter.getShowFilterAction()); 275 itemListMm.add(itemListFilter.getShowSearchAction()); 276 t4.setControl(itemListFilter.getComponent()); 277 278 tableFilter.loadState(state.getChild(FILE_IO_TABLE)); 279 itemListFilter.loadState(state.getChild(FILE_IO_LIST)); 280 281 tabFolder.setSelection(tabFolderIndex); 282 tabFolder.addSelectionListener(new SelectionAdapter() { 283 @Override 284 public void widgetSelected(SelectionEvent e) { 285 tabFolderIndex = ((CTabFolder) e.getSource()).getSelectionIndex(); 286 } 287 }); 288 289 timelineChart = createTimelineChart(pageContainer); 290 hookUpTimeLineChart(); 291 PersistableSashForm.loadState(sash, state.getChild(SASH_ELEMENT)); 292 293 flavorSelector = FlavorSelector.itemsWithTimerange(form, TABLE_ITEMS, getDataSource().getItems(), 294 pageContainer, this::onInputSelected, this::onShowFlavor, flavorSelectorState); 295 296 table.getManager().setSelectionState(tableSelection); 297 percentileTable.getManager().setSelectionState(percentileSelection); 298 itemList.getManager().setSelectionState(itemListSelection); 299 } 300 301 private XYChart createTimelineChart(IPageContainer pageContainer) { 302 XYChart timelineChart = new XYChart(pageContainer.getRecordingRange(), RendererToolkit.empty(), 180); 303 timelineChart.setVisibleRange(timelineRange.getStart(), timelineRange.getEnd()); 304 timelineChart.addVisibleRangeListener(range -> timelineRange = range); 305 return timelineChart; 306 } 307 308 private void onTableFilterChange(IItemFilter filter) { 309 tableFilter.filterChangeHelper(filter, table, getDataSource().getItems().apply(TABLE_ITEMS)); 310 itemListFilter.notifyListener(); 311 FileIOPage.this.tableFilter = filter; 312 } 313 314 private void onListFilterChange(IItemFilter filter) { 315 itemListFilter.filterChangeHelper(filter, itemList, getDataSource().getItems().apply(TABLE_ITEMS)); 316 FileIOPage.this.itemListFilter = filter; 317 } 318 319 @Override 320 public void saveTo(IWritableState writableState) { 321 PersistableSashForm.saveState(sash, writableState.createChild(SASH_ELEMENT)); 322 table.getManager().getSettings().saveState(writableState.createChild(TABLE_ELEMENT)); 323 tableFilter.saveState(writableState.createChild(FILE_IO_TABLE)); 324 itemList.getManager().getSettings().saveState(writableState.createChild(LIST_ELEMENT)); 325 itemListFilter.saveState(writableState.createChild(FILE_IO_LIST)); 326 percentileTable.getManager().getSettings().saveState(writableState.createChild(PERCENTILE_TABLE_ELEMENT)); 327 328 saveToLocal(); 329 } 330 331 private void saveToLocal() { 332 tableSelection = table.getManager().getSelectionState(); 333 itemListSelection = itemList.getManager().getSelectionState(); 334 flavorSelectorState = flavorSelector.getFlavorSelectorState(); 335 percentileSelection = percentileTable.getManager().getSelectionState(); 336 } 337 338 private void onShowFlavor(Boolean show) { 339 IRange<IQuantity> range = show ? timeRange : pageContainer.getRecordingRange(); 340 timelineChart.setVisibleRange(range.getStart(), range.getEnd()); 341 hookUpTimeLineChart(); 342 } 343 344 private void hookUpTimeLineChart() { 345 DataPageToolkit.setChart(timelineCanvas, timelineChart, pageContainer::showSelection); 346 SelectionStoreActionToolkit.addSelectionStoreRangeActions(pageContainer.getSelectionStore(), timelineChart, 347 JfrAttributes.LIFETIME, Messages.FileIOPage_TIMELINE_SELECTION, timelineCanvas.getContextMenu()); 348 } 349 350 private void onInputSelected(IItemCollection items, IRange<IQuantity> timeRange) { 351 this.selectionItems = items; 352 this.timeRange = timeRange; 353 updateDetails(); 354 } 355 356 private void updateDetails() { 357 IItemCollection items = selectionItems != null ? selectionItems.apply(TABLE_ITEMS) 358 : getDataSource().getItems().apply(TABLE_ITEMS); 359 table.show(items); 360 HistogramSelection histogramSelection = table.getSelection(); 361 IItemCollection selectedItems = histogramSelection.getRowCount() == 0 ? items 362 : histogramSelection.getItems(); 363 364 String pathCount = pathCount(histogramSelection.getRowCount()); 365 List<IXDataRenderer> timelineRows = new ArrayList<>(); 366 List<IXDataRenderer> durationRows = new ArrayList<>(); 367 List<IXDataRenderer> sizeRows = new ArrayList<>(); 368 IItemCollection readItems = selectedItems.apply(JdkFilters.FILE_READ); 369 if (readItems.hasItems()) { 370 timelineRows.add(DataPageToolkit.buildSizeRow(Messages.FileIOPage_ROW_FILE_READ + pathCount, 371 JdkAggregators.FILE_READ_SIZE.getDescription(), readItems, JdkAggregators.FILE_READ_SIZE, 372 READ_COLOR, FileIOPage::getColor)); 373 durationRows.add(DataPageToolkit.buildDurationHistogram(Messages.FileIOPage_ROW_FILE_READ + pathCount, 374 JdkAggregators.FILE_READ_COUNT.getDescription(), readItems, JdkAggregators.FILE_READ_COUNT, 375 READ_COLOR)); 376 sizeRows.add(DataPageToolkit.buildSizeHistogram(Messages.FileIOPage_ROW_FILE_READ + pathCount, 377 JdkAggregators.FILE_READ_COUNT.getDescription(), readItems, JdkAggregators.FILE_READ_COUNT, 378 READ_COLOR, JdkAttributes.IO_FILE_BYTES_READ)); 379 } 380 IItemCollection writeItems = selectedItems.apply(JdkFilters.FILE_WRITE); 381 if (writeItems.hasItems()) { 382 timelineRows.add(DataPageToolkit.buildSizeRow(Messages.FileIOPage_ROW_FILE_WRITE + pathCount, 383 JdkAggregators.FILE_WRITE_SIZE.getDescription(), writeItems, JdkAggregators.FILE_WRITE_SIZE, 384 WRITE_COLOR, FileIOPage::getColor)); 385 durationRows.add(DataPageToolkit.buildDurationHistogram(Messages.FileIOPage_ROW_FILE_WRITE + pathCount, 386 JdkAggregators.FILE_WRITE_COUNT.getDescription(), writeItems, JdkAggregators.FILE_WRITE_COUNT, 387 WRITE_COLOR)); 388 sizeRows.add(DataPageToolkit.buildSizeHistogram(Messages.FileIOPage_ROW_FILE_WRITE + pathCount, 389 JdkAggregators.FILE_WRITE_COUNT.getDescription(), writeItems, JdkAggregators.FILE_WRITE_COUNT, 390 WRITE_COLOR, JdkAttributes.IO_FILE_BYTES_WRITTEN)); 391 } 392 // ItemRow[] pathRows = selection.getSelectedRows(FileIOPage::buildPathLane).toArray(ItemRow[]::new); 393 394 timelineCanvas.replaceRenderer(RendererToolkit.uniformRows(timelineRows)); 395 396 IXDataRenderer durationRoot = RendererToolkit.uniformRows(durationRows); 397 // FIXME: X-auto-range should be done properly 398 IQuantity max = selectedItems.getAggregate(JdkAggregators.LONGEST_EVENT); 399 // FIXME: Workaround to make max value included 400 max = max == null ? UnitLookup.MILLISECOND.quantity(20) : max.add(UnitLookup.MILLISECOND.quantity(20)); 401 XYChart durationChart = new XYChart(UnitLookup.MILLISECOND.quantity(0), max, durationRoot, 180); 402 DataPageToolkit.setChart(durationCanvas, durationChart, JfrAttributes.DURATION, 403 selection -> pageContainer.showSelection(selection)); 404 durationChart.setVisibleRange(durationRange.getStart(), durationRange.getEnd()); 405 durationChart.addVisibleRangeListener(range -> durationRange = range); 406 durationCanvas.setChart(durationChart); 407 SelectionStoreActionToolkit.addSelectionStoreActions(pageContainer.getSelectionStore(), durationChart, 408 JfrAttributes.DURATION, Messages.FileIOPage_DURATION_SELECTION, durationCanvas.getContextMenu()); 409 itemList.show(selectedItems); 410 percentileTable.update(selectedItems); 411 412 IXDataRenderer sizeRoot = RendererToolkit.uniformRows(sizeRows); 413 IQuantity sizeMax = selectedItems.getAggregate(JdkAggregators.FILE_READ_LARGEST); 414 // FIXME: Workaround to make max value included 415 sizeMax = sizeMax == null ? UnitLookup.BYTE.quantity(64): sizeMax.add(UnitLookup.BYTE.quantity(64)); 416 XYChart sizeChart = new XYChart(UnitLookup.BYTE.quantity(0), sizeMax, sizeRoot, 180); 417 DataPageToolkit.setChart(sizeCanvas, sizeChart, JdkAttributes.IO_SIZE, 418 selection -> pageContainer.showSelection(selection)); 419 sizeChart.setVisibleRange(sizeRange.getStart(), sizeRange.getEnd()); 420 sizeChart.addVisibleRangeListener(range -> sizeRange = range); 421 sizeCanvas.setChart(sizeChart); 422 SelectionStoreActionToolkit.addSelectionStoreActions(pageContainer.getSelectionStore(), sizeChart, 423 JdkAttributes.IO_SIZE, Messages.FileIOPage_SIZE_SELECTION, sizeCanvas.getContextMenu()); 424 } 425 } 426 427 private static TableSettings getTableSettings(IState state) { 428 if (state == null) { 429 return new TableSettings(TOTAL_TIME, Arrays.asList( 430 new ColumnSettings(ItemHistogram.KEY_COL_ID, false, 500, null), 431 new ColumnSettings(TOTAL_TIME, true, 120, false), new ColumnSettings(MAX_TIME, false, 120, false), 432 new ColumnSettings(AVG_TIME, false, 120, false), new ColumnSettings(STDDEV_TIME, false, 120, false), 433 new ColumnSettings(READ_COUNT, false, 120, false), 434 new ColumnSettings(WRITE_COUNT, false, 120, false), 435 new ColumnSettings(READ_SIZE, false, 120, false), new ColumnSettings(WRITE_SIZE, false, 120, false), 436 new ColumnSettings(READ_EOF, false, 80, false))); 437 } else { 438 return new TableSettings(state); 439 } 440 } 441 442 @Override 443 public IPageUI display(Composite parent, FormToolkit toolkit, IPageContainer pageContainer, IState state) { 444 return new IOPageUi(parent, toolkit, pageContainer, state); 445 } 446 447 private SelectionState tableSelection; 448 private SelectionState itemListSelection; 449 private SelectionState percentileSelection; 450 private IItemFilter tableFilter = null; 451 private IItemFilter itemListFilter = null; 452 private int tabFolderIndex = 0; 453 private IRange<IQuantity> timelineRange; 454 private IRange<IQuantity> durationRange; 455 private IRange<IQuantity> sizeRange; 456 public FlavorSelectorState flavorSelectorState; 457 458 public FileIOPage(IPageDefinition dpd, StreamModel items, IPageContainer editor) { 459 super(dpd, items, editor); 460 timelineRange = editor.getRecordingRange(); 461 durationRange = editor.getRecordingRange(); 462 sizeRange = DataPageToolkit.buildSizeRange(items.getItems(), false); 463 } 464 465 // private static ItemRow buildPathLane(Object path, Supplier<Stream<ItemStream>> pathItems) { 466 // String pathName = String.valueOf(path); 467 // pathName = pathName.length() > 26 ? pathName.substring(0, 23) + "..." : pathName; //$NON-NLS-1$ 468 // return new ItemRow(pathName, buildSpanRenderer(pathItems), pathItems); 469 // } 470 471 private static Color getColor(IItem item) { 472 return JdkTypeIDs.FILE_READ.equals(item.getType().getIdentifier()) ? READ_ALPHA_COLOR : WRITE_ALPHA_COLOR; 473 } 474 475 @Override 476 public IItemFilter getDefaultSelectionFilter() { 477 return TABLE_ITEMS; 478 } 479 480 private static String pathCount(int count) { 481 switch (count) { 482 case 0: 483 return ""; //$NON-NLS-1$ 484 case 1: 485 return " (" + Messages.FileIOPage_SELECTED_PATH + ")"; //$NON-NLS-1$ //$NON-NLS-2$ 486 default: 487 return " (" + NLS.bind(Messages.FileIOPage_SELECTED_PATHS, count) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ 488 } 489 } 490 }