diff options
author | Siva Velusamy <vsiva@google.com> | 2012-02-21 14:45:54 -0800 |
---|---|---|
committer | Siva Velusamy <vsiva@google.com> | 2012-02-21 14:56:22 -0800 |
commit | 3824d578d3d56f7a4d65572fb942a1e035121cc8 (patch) | |
tree | f60bbf1107f5c933f695562424c9e8c72fa6d550 /eclipse/plugins/com.android.ide.eclipse.gldebugger | |
parent | 34e4ce9cb42f4db512103b47445d4145c09fc806 (diff) | |
download | sdk-3824d578d3d56f7a4d65572fb942a1e035121cc8.zip sdk-3824d578d3d56f7a4d65572fb942a1e035121cc8.tar.gz sdk-3824d578d3d56f7a4d65572fb942a1e035121cc8.tar.bz2 |
gltrace: Show per frame summary statistics.
This CL changes the framebuffer view to be a frame summary view.
The Frame Summary View displays summary information regarding the
currently displayed frame. For each frame, it displays:
- the contents of the framebuffer at the end of the frame.
- summary statistics regarding the GL Calls present in the frame.
Change-Id: I293f5b0de40aac315dee257fbc3eaa3d5ff0919c
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.gldebugger')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.gldebugger/plugin.xml | 4 | ||||
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTracePerspective.java | 4 | ||||
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java | 18 | ||||
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameBufferViewPage.java | 119 | ||||
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameSummaryView.java (renamed from eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameBufferView.java) | 11 | ||||
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameSummaryViewPage.java | 401 |
6 files changed, 419 insertions, 138 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.gldebugger/plugin.xml index d693916..66f7fa6 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/plugin.xml +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/plugin.xml @@ -17,10 +17,10 @@ </view>
<view
category="com.android.ide.eclipse.gltrace"
- class="com.android.ide.eclipse.gltrace.views.FrameBufferView"
+ class="com.android.ide.eclipse.gltrace.views.FrameSummaryView"
icon="icons/opengl.png"
id="com.android.ide.eclipse.gltrace.views.FrameBuffer"
- name="Framebuffer"
+ name="Frame Summary"
restorable="true">
</view>
<view
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTracePerspective.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTracePerspective.java index d8f1a0b..bc41e33 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTracePerspective.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTracePerspective.java @@ -17,7 +17,7 @@ package com.android.ide.eclipse.gltrace; import com.android.ide.eclipse.gltrace.views.DetailsView; -import com.android.ide.eclipse.gltrace.views.FrameBufferView; +import com.android.ide.eclipse.gltrace.views.FrameSummaryView; import com.android.ide.eclipse.gltrace.views.StateView; import org.eclipse.ui.IFolderLayout; @@ -51,6 +51,6 @@ public class GLTracePerspective implements IPerspectiveFactory { IPageLayout.BOTTOM, 0.5f, FB_FOLDER_ID); - column3bottom.addView(FrameBufferView.ID); + column3bottom.addView(FrameSummaryView.ID); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java index 1a1f388..ece4723 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java @@ -25,7 +25,7 @@ import com.android.ide.eclipse.gltrace.model.GLCall; import com.android.ide.eclipse.gltrace.model.GLFrame; import com.android.ide.eclipse.gltrace.model.GLTrace; import com.android.ide.eclipse.gltrace.views.DetailsPage; -import com.android.ide.eclipse.gltrace.views.FrameBufferViewPage; +import com.android.ide.eclipse.gltrace.views.FrameSummaryViewPage; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.dialogs.MessageDialog; @@ -112,7 +112,7 @@ public class GLFunctionTraceViewer extends EditorPart implements ISelectionProvi private boolean mShowContextSwitcher; private int mCurrentlyDisplayedContext = -1; - private FrameBufferViewPage mFrameBufferViewPage; + private FrameSummaryViewPage mFrameSummaryViewPage; public GLFunctionTraceViewer() { mGldrawTextColor = Display.getDefault().getSystemColor(SWT.COLOR_BLUE); @@ -276,9 +276,9 @@ public class GLFunctionTraceViewer extends EditorPart implements ISelectionProvi // update minimap view mDurationMinimap.setCallRangeForCurrentFrame(mCallStartIndex, mCallEndIndex); - // update FB view - if (mFrameBufferViewPage != null) { - mFrameBufferViewPage.setSelectedFrame(selectedFrame - 1); + // update the frame summary view + if (mFrameSummaryViewPage != null) { + mFrameSummaryViewPage.setSelectedFrame(selectedFrame - 1); } } @@ -656,12 +656,12 @@ public class GLFunctionTraceViewer extends EditorPart implements ISelectionProvi return new StateViewPage(mTrace); } - public FrameBufferViewPage getFrameBufferViewPage() { - if (mFrameBufferViewPage == null) { - mFrameBufferViewPage = new FrameBufferViewPage(mTrace); + public FrameSummaryViewPage getFrameSummaryViewPage() { + if (mFrameSummaryViewPage == null) { + mFrameSummaryViewPage = new FrameSummaryViewPage(mTrace); } - return mFrameBufferViewPage; + return mFrameSummaryViewPage; } public DetailsPage getDetailsPage() { diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameBufferViewPage.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameBufferViewPage.java deleted file mode 100644 index 09b43b2..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameBufferViewPage.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.ide.eclipse.gltrace.views; - -import com.android.ide.eclipse.gltrace.editors.GLFunctionTraceViewer; -import com.android.ide.eclipse.gltrace.editors.GLCallGroups.GLCallNode; -import com.android.ide.eclipse.gltrace.model.GLCall; -import com.android.ide.eclipse.gltrace.model.GLTrace; -import com.android.ide.eclipse.gltrace.widgets.ImageCanvas; - -import org.eclipse.jface.action.IToolBarManager; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.TreeSelection; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.ISelectionListener; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.part.IPageSite; -import org.eclipse.ui.part.Page; - -public class FrameBufferViewPage extends Page implements ISelectionListener { - private ImageCanvas mImageCanvas; - - private final GLTrace mTrace; - - public FrameBufferViewPage(GLTrace trace) { - mTrace = trace; - } - - @Override - public void createControl(Composite parent) { - mImageCanvas = new ImageCanvas(parent); - - IToolBarManager toolbarManager = getSite().getActionBars().getToolBarManager(); - toolbarManager.add(new FitToCanvasAction(true, mImageCanvas)); - } - - @Override - public Control getControl() { - return mImageCanvas; - } - - @Override - public void init(IPageSite pageSite) { - super.init(pageSite); - pageSite.getPage().addSelectionListener(this); - } - - @Override - public void dispose() { - getSite().getPage().removeSelectionListener(this); - super.dispose(); - } - - @Override - public void setFocus() { - } - - @Override - public void selectionChanged(IWorkbenchPart part, ISelection selection) { - if (!(part instanceof GLFunctionTraceViewer)) { - return; - } - - if (((GLFunctionTraceViewer) part).getTrace() != mTrace) { - return; - } - - if (!(selection instanceof TreeSelection)) { - return; - } - - GLCall selectedCall = null; - - Object data = ((TreeSelection) selection).getFirstElement(); - if (data instanceof GLCallNode) { - selectedCall = ((GLCallNode) data).getCall(); - } - - if (selectedCall == null) { - return; - } - - setImage(mTrace.getImage(selectedCall)); - } - - private void setImage(final Image image) { - Display.getDefault().asyncExec(new Runnable() { - @Override - public void run() { - mImageCanvas.setImage(image); - } - }); - }; - - public void setSelectedFrame(int frame) { - int lastCallIndex = mTrace.getFrame(frame).getEndIndex() - 1; - if (lastCallIndex >= 0 && lastCallIndex < mTrace.getGLCalls().size()) { - GLCall call = mTrace.getGLCalls().get(lastCallIndex); - setImage(mTrace.getImage(call)); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameBufferView.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameSummaryView.java index 50eafd2..42eb98c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameBufferView.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameSummaryView.java @@ -21,13 +21,12 @@ import com.android.ide.eclipse.gltrace.editors.GLFunctionTraceViewer; import org.eclipse.ui.IWorkbenchPart; /** - * The {@link FrameBufferView} displays the contents of the frame buffer for the - * currently displayed frame. + * The {@link FrameSummaryView} is a page book view with pages of type {@link FrameSummaryViewPage}. */ -public class FrameBufferView extends GLPageBookView { +public class FrameSummaryView extends GLPageBookView { public static final String ID = "com.android.ide.eclipse.gltrace.views.FrameBuffer"; //$NON-NLS-1$ - public FrameBufferView() { + public FrameSummaryView() { super("Open a GL Trace file to view the framebuffer contents."); } @@ -38,7 +37,7 @@ public class FrameBufferView extends GLPageBookView { } GLFunctionTraceViewer viewer = (GLFunctionTraceViewer) part; - FrameBufferViewPage page = viewer.getFrameBufferViewPage(); + FrameSummaryViewPage page = viewer.getFrameSummaryViewPage(); initPage(page); page.createControl(getPageBook()); @@ -47,7 +46,7 @@ public class FrameBufferView extends GLPageBookView { @Override protected void doDestroyPage(IWorkbenchPart part, PageRec pageRecord) { - FrameBufferViewPage page = (FrameBufferViewPage) pageRecord.page; + FrameSummaryViewPage page = (FrameSummaryViewPage) pageRecord.page; page.dispose(); pageRecord.dispose(); } diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameSummaryViewPage.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameSummaryViewPage.java new file mode 100644 index 0000000..fbe131a --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/FrameSummaryViewPage.java @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.gltrace.views; + +import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function; +import com.android.ide.eclipse.gltrace.model.GLCall; +import com.android.ide.eclipse.gltrace.model.GLTrace; +import com.android.ide.eclipse.gltrace.widgets.ImageCanvas; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerCell; +import org.eclipse.jface.viewers.ViewerComparator; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.SashForm; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.ui.part.Page; + +import java.util.EnumMap; +import java.util.List; +import java.util.Map; + +/** + * A {@link FrameSummaryViewPage} displays summary information regarding a frame. This includes + * the contents of the frame buffer at the end of the frame, and statistics regarding the + * OpenGL Calls present in the frame. + */ +public class FrameSummaryViewPage extends Page { + private final GLTrace mTrace; + + private int mCurrentFrame; + + private SashForm mSash; + private ImageCanvas mImageCanvas; + + private Label mWallClockTimeLabel; + private Label mThreadTimeLabel; + + private TableViewer mStatsTableViewer; + private StatsLabelProvider mStatsLabelProvider; + private StatsTableComparator mStatsTableComparator; + + private static final String[] STATS_TABLE_PROPERTIES = { + "Function", + "Count", + "Wall Time (ns)", + "Thread Time (ns)", + }; + private static final float[] STATS_TABLE_COLWIDTH_RATIOS = { + 0.4f, 0.1f, 0.25f, 0.25f, + }; + private static final int[] STATS_TABLE_COL_ALIGNMENT = { + SWT.LEFT, SWT.LEFT, SWT.RIGHT, SWT.RIGHT, + }; + + public FrameSummaryViewPage(GLTrace trace) { + mTrace = trace; + } + + @Override + public void createControl(Composite parent) { + mSash = new SashForm(parent, SWT.VERTICAL); + + // create image canvas where the framebuffer is displayed + mImageCanvas = new ImageCanvas(mSash); + + // create a composite where the frame statistics are displayed + createFrameStatisticsPart(mSash); + + mSash.setWeights(new int[] {70, 30}); + + IToolBarManager toolbarManager = getSite().getActionBars().getToolBarManager(); + toolbarManager.add(new FitToCanvasAction(true, mImageCanvas)); + } + + private void createFrameStatisticsPart(Composite parent) { + Composite c = new Composite(parent, SWT.NONE); + c.setLayout(new GridLayout(2, false)); + GridDataFactory.fillDefaults().grab(true, true).applyTo(c); + + Label l = new Label(c, SWT.NONE); + l.setText("Cumulative call duration of all OpenGL Calls in this frame:"); + l.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_DARK_GRAY)); + GridDataFactory.fillDefaults().span(2, 1).applyTo(l); + + l = new Label(c, SWT.NONE); + l.setText("Wall Clock Time: "); + GridDataFactory.fillDefaults().align(SWT.RIGHT, SWT.CENTER).applyTo(l); + + mWallClockTimeLabel = new Label(c, SWT.NONE); + GridDataFactory.defaultsFor(mWallClockTimeLabel) + .grab(true, false) + .applyTo(mWallClockTimeLabel); + + l = new Label(c, SWT.NONE); + l.setText("Thread Time: "); + GridDataFactory.fillDefaults().align(SWT.RIGHT, SWT.CENTER).applyTo(l); + + mThreadTimeLabel = new Label(c, SWT.NONE); + GridDataFactory.defaultsFor(mThreadTimeLabel) + .grab(true, false) + .applyTo(mThreadTimeLabel); + + l = new Label(c, SWT.HORIZONTAL | SWT.SEPARATOR); + GridDataFactory.fillDefaults().span(2, 1).applyTo(l); + + l = new Label(c, SWT.NONE); + l.setText("Per OpenGL Function Statistics:"); + l.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_DARK_GRAY)); + GridDataFactory.fillDefaults().span(2, 1).applyTo(l); + + final Table table = new Table(c, SWT.BORDER | SWT.FULL_SELECTION); + GridDataFactory.fillDefaults().grab(true, true).span(2, 1).applyTo(table); + + table.setLinesVisible(true); + table.setHeaderVisible(true); + + mStatsTableViewer = new TableViewer(table); + mStatsLabelProvider = new StatsLabelProvider(); + mStatsTableComparator = new StatsTableComparator(1); + + // when a column is selected, sort the table based on that column + SelectionListener columnSelectionListener = new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + TableColumn tc = (TableColumn) e.widget; + String colText = tc.getText(); + for (int i = 0; i < STATS_TABLE_PROPERTIES.length; i++) { + if (STATS_TABLE_PROPERTIES[i].equals(colText)) { + mStatsTableComparator.setSortColumn(i); + table.setSortColumn(tc); + table.setSortDirection(mStatsTableComparator.getDirection()); + mStatsTableViewer.refresh(); + break; + } + } + } + }; + + for (int i = 0; i < STATS_TABLE_PROPERTIES.length; i++) { + TableViewerColumn tvc = new TableViewerColumn(mStatsTableViewer, SWT.NONE); + tvc.getColumn().setText(STATS_TABLE_PROPERTIES[i]); + tvc.setLabelProvider(mStatsLabelProvider); + tvc.getColumn().setAlignment(STATS_TABLE_COL_ALIGNMENT[i]); + tvc.getColumn().addSelectionListener(columnSelectionListener); + } + mStatsTableViewer.setContentProvider(new StatsContentProvider()); + mStatsTableViewer.setInput(null); + mStatsTableViewer.setComparator(mStatsTableComparator); + + // resize columns appropriately when the size of the widget changes + table.addControlListener(new ControlAdapter() { + @Override + public void controlResized(ControlEvent e) { + int w = table.getClientArea().width; + + for (int i = 0; i < STATS_TABLE_COLWIDTH_RATIOS.length; i++) { + table.getColumn(i).setWidth((int) (w * STATS_TABLE_COLWIDTH_RATIOS[i])); + } + } + }); + } + + @Override + public Control getControl() { + return mSash; + } + + @Override + public void setFocus() { + } + + public void setSelectedFrame(int frame) { + mCurrentFrame = frame; + + updateImageCanvas(); + updateFrameStats(); + } + + private void updateFrameStats() { + final List<GLCall> calls = mTrace.getGLCallsForFrame(mCurrentFrame); + + Job job = new Job("Update Frame Statistics") { + @Override + protected IStatus run(IProgressMonitor monitor) { + long wallClockDuration = 0; + long threadDuration = 0; + + final Map<Function, PerCallStats> cumulativeStats = + new EnumMap<Function, PerCallStats>(Function.class); + + for (GLCall c: calls) { + wallClockDuration += c.getWallDuration(); + threadDuration += c.getThreadDuration(); + + PerCallStats stats = cumulativeStats.get(c.getFunction()); + if (stats == null) { + stats = new PerCallStats(); + } + + stats.count++; + stats.threadDuration += c.getThreadDuration(); + stats.wallDuration += c.getWallDuration(); + + cumulativeStats.put(c.getFunction(), stats); + } + + final String wallTime = formatMilliSeconds(wallClockDuration); + final String threadTime = formatMilliSeconds(threadDuration); + + Display.getDefault().syncExec(new Runnable() { + @Override + public void run() { + mWallClockTimeLabel.setText(wallTime); + mThreadTimeLabel.setText(threadTime); + mStatsTableViewer.setInput(cumulativeStats); + } + }); + + return Status.OK_STATUS; + } + }; + job.setUser(true); + job.schedule(); + } + + private String formatMilliSeconds(long nanoSeconds) { + double milliSeconds = (double) nanoSeconds / 1000000; + return String.format("%.2f ms", milliSeconds); //$NON-NLS-1$ + } + + private void updateImageCanvas() { + int lastCallIndex = mTrace.getFrame(mCurrentFrame).getEndIndex() - 1; + if (lastCallIndex >= 0 && lastCallIndex < mTrace.getGLCalls().size()) { + GLCall call = mTrace.getGLCalls().get(lastCallIndex); + final Image image = mTrace.getImage(call); + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + mImageCanvas.setImage(image); + } + }); + } + } + + /** Cumulative stats maintained for each type of OpenGL Function in a particular frame. */ + private static class PerCallStats { + public int count; + public long wallDuration; + public long threadDuration; + } + + private static class StatsContentProvider implements IStructuredContentProvider { + @Override + public void dispose() { + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + @Override + public Object[] getElements(Object inputElement) { + if (inputElement instanceof Map<?, ?>) { + return ((Map<?, ?>) inputElement).entrySet().toArray(); + } + + return null; + } + } + + private static class StatsLabelProvider extends ColumnLabelProvider { + @Override + public void update(ViewerCell cell) { + Object element = cell.getElement(); + if (!(element instanceof Map.Entry<?, ?>)) { + return; + } + + Function f = (Function) ((Map.Entry<?, ?>) element).getKey(); + PerCallStats stats = (PerCallStats) ((Map.Entry<?, ?>) element).getValue(); + + switch (cell.getColumnIndex()) { + case 0: + cell.setText(f.toString()); + break; + case 1: + cell.setText(Integer.toString(stats.count)); + break; + case 2: + cell.setText(formatDuration(stats.wallDuration)); + break; + case 3: + cell.setText(formatDuration(stats.threadDuration)); + break; + default: + // should not happen + cell.setText("??"); //$NON-NLS-1$ + break; + } + } + + private String formatDuration(long time) { + // Max duration is in the 10s of milliseconds = xx,xxx,xxx ns + // So we require a format specifier that is 10 characters wide + return String.format("%,10d", time); //$NON-NLS-1$ + } + } + + private static class StatsTableComparator extends ViewerComparator { + private int mSortColumn; + private boolean mDescending = true; + + private StatsTableComparator(int defaultSortColIndex) { + mSortColumn = defaultSortColIndex; + } + + public void setSortColumn(int index) { + if (index == mSortColumn) { + // if same column as what we are currently sorting on, + // then toggle the direction + mDescending = !mDescending; + } else { + mSortColumn = index; + mDescending = true; + } + } + + public int getDirection() { + return mDescending ? SWT.UP : SWT.DOWN; + } + + @Override + public int compare(Viewer viewer, Object e1, Object e2) { + Map.Entry<?, ?> entry1; + Map.Entry<?, ?> entry2; + + if (mDescending) { + entry1 = (Map.Entry<?, ?>) e1; + entry2 = (Map.Entry<?, ?>) e2; + } else { + entry1 = (Map.Entry<?, ?>) e2; + entry2 = (Map.Entry<?, ?>) e1; + } + + String k1 = entry1.getKey().toString(); + String k2 = entry2.getKey().toString(); + + PerCallStats stats1 = (PerCallStats) entry1.getValue(); + PerCallStats stats2 = (PerCallStats) entry2.getValue(); + + switch (mSortColumn) { + case 0: // function name + return String.CASE_INSENSITIVE_ORDER.compare(k1, k2); + case 1: + return stats1.count - stats2.count; + case 2: + return (int) (stats1.wallDuration - stats2.wallDuration); + case 3: + return (int) (stats1.threadDuration - stats2.threadDuration); + default: + return super.compare(viewer, e1, e2); + } + } + } +} |