~ubuntu-branches/ubuntu/trusty/eclipse-linuxtools/trusty

« back to all changes in this revision

Viewing changes to valgrind/org.eclipse.linuxtools.valgrind.massif/src/org/eclipse/linuxtools/internal/valgrind/massif/MassifViewPart.java

  • Committer: Package Import Robot
  • Author(s): Jakub Adam
  • Date: 2012-06-29 12:07:30 UTC
  • Revision ID: package-import@ubuntu.com-20120629120730-bfri1xys1i71dpn6
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*******************************************************************************
 
2
 * Copyright (c) 2008 Red Hat, Inc.
 
3
 * All rights reserved. This program and the accompanying materials
 
4
 * are made available under the terms of the Eclipse Public License v1.0
 
5
 * which accompanies this distribution, and is available at
 
6
 * http://www.eclipse.org/legal/epl-v10.html
 
7
 *
 
8
 * Contributors:
 
9
 *    Elliott Baron <ebaron@redhat.com> - initial API and implementation
 
10
 *******************************************************************************/
 
11
package org.eclipse.linuxtools.internal.valgrind.massif;
 
12
 
 
13
import java.text.DecimalFormat;
 
14
import java.util.ArrayList;
 
15
import java.util.List;
 
16
 
 
17
import org.eclipse.core.runtime.Path;
 
18
import org.eclipse.jface.action.Action;
 
19
import org.eclipse.jface.action.IAction;
 
20
import org.eclipse.jface.resource.JFaceResources;
 
21
import org.eclipse.jface.viewers.AbstractTreeViewer;
 
22
import org.eclipse.jface.viewers.ArrayContentProvider;
 
23
import org.eclipse.jface.viewers.DoubleClickEvent;
 
24
import org.eclipse.jface.viewers.IDoubleClickListener;
 
25
import org.eclipse.jface.viewers.IFontProvider;
 
26
import org.eclipse.jface.viewers.IStructuredSelection;
 
27
import org.eclipse.jface.viewers.ITableLabelProvider;
 
28
import org.eclipse.jface.viewers.LabelProvider;
 
29
import org.eclipse.jface.viewers.StructuredSelection;
 
30
import org.eclipse.jface.viewers.TableViewer;
 
31
import org.eclipse.jface.viewers.TableViewerColumn;
 
32
import org.eclipse.jface.viewers.Viewer;
 
33
import org.eclipse.jface.viewers.ViewerComparator;
 
34
import org.eclipse.linuxtools.internal.valgrind.massif.MassifSnapshot.SnapshotType;
 
35
import org.eclipse.linuxtools.internal.valgrind.massif.charting.ChartEditorInput;
 
36
import org.eclipse.linuxtools.internal.valgrind.massif.charting.ChartPNG;
 
37
import org.eclipse.linuxtools.internal.valgrind.massif.charting.HeapChart;
 
38
import org.eclipse.linuxtools.valgrind.ui.IValgrindToolView;
 
39
import org.eclipse.swt.SWT;
 
40
import org.eclipse.swt.custom.StackLayout;
 
41
import org.eclipse.swt.events.SelectionAdapter;
 
42
import org.eclipse.swt.events.SelectionEvent;
 
43
import org.eclipse.swt.events.SelectionListener;
 
44
import org.eclipse.swt.graphics.Font;
 
45
import org.eclipse.swt.graphics.Image;
 
46
import org.eclipse.swt.layout.GridData;
 
47
import org.eclipse.swt.widgets.Composite;
 
48
import org.eclipse.swt.widgets.Control;
 
49
import org.eclipse.swt.widgets.Display;
 
50
import org.eclipse.swt.widgets.FileDialog;
 
51
import org.eclipse.swt.widgets.Shell;
 
52
import org.eclipse.swt.widgets.Table;
 
53
import org.eclipse.swt.widgets.TableColumn;
 
54
import org.eclipse.ui.IEditorInput;
 
55
import org.eclipse.ui.IEditorPart;
 
56
import org.eclipse.ui.IWorkbenchPage;
 
57
import org.eclipse.ui.PartInitException;
 
58
import org.eclipse.ui.PlatformUI;
 
59
import org.eclipse.ui.part.ViewPart;
 
60
import org.eclipse.ui.plugin.AbstractUIPlugin;
 
61
 
 
62
public class MassifViewPart extends ViewPart implements IValgrindToolView {
 
63
 
 
64
        protected static final String TITLE_STACKS = Messages
 
65
        .getString("MassifViewPart.Stacks"); //$NON-NLS-1$
 
66
        protected static final String TITLE_EXTRA = Messages
 
67
        .getString("MassifViewPart.Extra_Heap"); //$NON-NLS-1$
 
68
        protected static final String TITLE_USEFUL = Messages
 
69
        .getString("MassifViewPart.Useful_Heap"); //$NON-NLS-1$
 
70
        protected static final String TITLE_TOTAL = Messages
 
71
        .getString("MassifViewPart.Total"); //$NON-NLS-1$
 
72
        protected static final String TITLE_TIME = Messages
 
73
        .getString("MassifViewPart.Time"); //$NON-NLS-1$
 
74
        protected static final String TITLE_NUMBER = Messages
 
75
        .getString("MassifViewPart.Snapshot"); //$NON-NLS-1$
 
76
        protected static final String TREE_ACTION = MassifPlugin.PLUGIN_ID
 
77
        + ".treeAction"; //$NON-NLS-1$
 
78
        public static final String CHART_ACTION = MassifPlugin.PLUGIN_ID
 
79
        + ".chartAction"; //$NON-NLS-1$
 
80
        public static final String PID_ACTION = MassifPlugin.PLUGIN_ID
 
81
        + ".pidAction"; //$NON-NLS-1$
 
82
        public static final String SAVE_CHART_ACTION = MassifPlugin.PLUGIN_ID
 
83
        + ".saveChartAction"; //$NON-NLS-1$
 
84
 
 
85
        protected MassifOutput output;
 
86
        protected Integer pid;
 
87
 
 
88
        protected Composite top;
 
89
        protected StackLayout stackLayout;
 
90
        protected TableViewer viewer;
 
91
        protected MassifTreeViewer treeViewer;
 
92
        protected MassifHeapTreeNode[] nodes;
 
93
        protected String chartName;
 
94
 
 
95
        protected static final int COLUMN_SIZE = 125;
 
96
 
 
97
        protected Action treeAction;
 
98
        protected Action chartAction;
 
99
        protected MassifPidMenuAction pidAction;
 
100
        protected Action saveChartAction;
 
101
 
 
102
        protected List<ChartEditorInput> chartInputs;
 
103
 
 
104
        @Override
 
105
        public void createPartControl(Composite parent) {
 
106
                chartInputs = new ArrayList<ChartEditorInput>();
 
107
 
 
108
                top = new Composite(parent, SWT.NONE);
 
109
                stackLayout = new StackLayout();
 
110
                top.setLayout(stackLayout);
 
111
                top.setLayoutData(new GridData(GridData.FILL_BOTH));
 
112
 
 
113
                viewer = new TableViewer(top, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL
 
114
                                | SWT.FULL_SELECTION);
 
115
 
 
116
                Table table = viewer.getTable();
 
117
                table.setLayoutData(new GridData(GridData.FILL_BOTH));
 
118
 
 
119
 
 
120
                String[] columnTitles = { TITLE_NUMBER, TITLE_TIME, TITLE_TOTAL,
 
121
                                TITLE_USEFUL, TITLE_EXTRA, TITLE_STACKS };
 
122
 
 
123
                for (int i = 0; i < columnTitles.length; i++) {
 
124
                        TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
 
125
                        column.getColumn().setText(columnTitles[i]);
 
126
                        column.getColumn().setWidth(COLUMN_SIZE);
 
127
                        column.getColumn().setResizable(true);
 
128
                        column.getColumn().addSelectionListener(getHeaderListener());
 
129
                }
 
130
                table.setHeaderVisible(true);
 
131
                table.setLinesVisible(true);
 
132
 
 
133
                viewer.setContentProvider(new ArrayContentProvider());
 
134
                viewer.setLabelProvider(new MassifLabelProvider());
 
135
 
 
136
                treeViewer = new MassifTreeViewer(top);
 
137
                treeViewer.getViewer().getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
 
138
 
 
139
                viewer.addDoubleClickListener(new IDoubleClickListener() {
 
140
                        public void doubleClick(DoubleClickEvent event) {
 
141
                                MassifSnapshot snapshot = (MassifSnapshot) ((IStructuredSelection) event
 
142
                                                .getSelection()).getFirstElement();
 
143
                                if (snapshot.getType() != SnapshotType.EMPTY) {
 
144
                                        treeAction.setChecked(true);
 
145
                                        setTopControl(treeViewer.getViewer().getControl());
 
146
                                        treeViewer.getViewer().setSelection(new StructuredSelection(snapshot
 
147
                                                        .getRoot()), true);
 
148
                                        treeViewer.getViewer().expandToLevel(snapshot.getRoot(),
 
149
                                                        AbstractTreeViewer.ALL_LEVELS);
 
150
                                }
 
151
                        }
 
152
                });
 
153
 
 
154
                stackLayout.topControl = viewer.getControl();
 
155
                top.layout();
 
156
        }
 
157
 
 
158
        private String getUnitString(MassifSnapshot[] snapshots) {
 
159
                String result;
 
160
                MassifSnapshot snapshot = snapshots[0];
 
161
                switch (snapshot.getUnit()) {
 
162
                case BYTES:
 
163
                        result = "B"; //$NON-NLS-1$
 
164
                        break;
 
165
                case INSTRUCTIONS:
 
166
                        result = "i"; //$NON-NLS-1$
 
167
                        break;
 
168
                default:
 
169
                        result = "ms"; //$NON-NLS-1$
 
170
                break;
 
171
                }
 
172
                return result;
 
173
        }
 
174
 
 
175
        private SelectionListener getHeaderListener() {
 
176
                return new SelectionAdapter() {
 
177
                        @Override
 
178
                        public void widgetSelected(SelectionEvent e) {
 
179
                                TableColumn column = (TableColumn) e.widget;
 
180
                                Table table = viewer.getTable();
 
181
                                if (column.equals(table.getSortColumn())) {
 
182
                                        int direction = table.getSortDirection() == SWT.UP ? SWT.DOWN
 
183
                                                        : SWT.UP;
 
184
                                        table.setSortDirection(direction);
 
185
                                } else {
 
186
                                        table.setSortDirection(SWT.UP);
 
187
                                }
 
188
                                table.setSortColumn(column);
 
189
                                viewer.setComparator(new ViewerComparator() {
 
190
                                        @Override
 
191
                                        public int compare(Viewer viewer, Object o1, Object o2) {
 
192
                                                Table table = ((TableViewer) viewer).getTable();
 
193
                                                int direction = table.getSortDirection();
 
194
                                                MassifSnapshot s1 = (MassifSnapshot) o1;
 
195
                                                MassifSnapshot s2 = (MassifSnapshot) o2;
 
196
                                                long result;
 
197
                                                TableColumn column = table.getSortColumn();
 
198
                                                if (column.getText().equals(TITLE_NUMBER)) {
 
199
                                                        result = s1.getNumber() - s2.getNumber();
 
200
                                                } else if (column.getText().startsWith(TITLE_TIME)) {
 
201
                                                        result = s1.getTime() - s2.getTime();
 
202
                                                } else if (column.getText().equals(TITLE_TOTAL)) {
 
203
                                                        result = s1.getTotal() - s2.getTotal();
 
204
                                                } else if (column.getText().equals(TITLE_USEFUL)) {
 
205
                                                        result = s1.getHeapBytes() - s2.getHeapBytes();
 
206
                                                } else if (column.getText().equals(TITLE_EXTRA)) {
 
207
                                                        result = s1.getHeapExtra() - s2.getHeapExtra();
 
208
                                                } else {
 
209
                                                        result = s1.getStacks() - s2.getStacks();
 
210
                                                }
 
211
 
 
212
                                                // ascending / descending
 
213
                                                result = direction == SWT.UP ? result : -result;
 
214
 
 
215
                                                // overflow check
 
216
                                                if (result > Integer.MAX_VALUE) {
 
217
                                                        result = Integer.MAX_VALUE;
 
218
                                                } else if (result < Integer.MIN_VALUE) {
 
219
                                                        result = Integer.MIN_VALUE;
 
220
                                                }
 
221
                                                return (int) result;
 
222
                                        }
 
223
                                });
 
224
                        }
 
225
                };
 
226
        }
 
227
 
 
228
        public IAction[] getToolbarActions() {
 
229
                pidAction = new MassifPidMenuAction(this);
 
230
                pidAction.setId(PID_ACTION);
 
231
 
 
232
                chartAction = new Action(
 
233
                                Messages.getString("MassifViewPart.Display_Heap_Allocation"), IAction.AS_PUSH_BUTTON) { //$NON-NLS-1$
 
234
                        @Override
 
235
                        public void run() {
 
236
                                ChartEditorInput input = getChartInput(pid);
 
237
                                if (input != null) {                                    
 
238
                                        displayChart(input);
 
239
                                }
 
240
                        }
 
241
                };
 
242
                chartAction.setId(CHART_ACTION);
 
243
                chartAction.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(
 
244
                                MassifPlugin.PLUGIN_ID, "icons/linecharticon.gif")); //$NON-NLS-1$
 
245
                chartAction.setToolTipText(Messages
 
246
                                .getString("MassifViewPart.Display_Heap_Allocation")); //$NON-NLS-1$
 
247
 
 
248
                saveChartAction = new Action(Messages.getString("MassifViewPart.Save_Chart"), IAction.AS_PUSH_BUTTON) { //$NON-NLS-1$
 
249
                        @Override
 
250
                        public void run() {
 
251
                                ChartEditorInput currentInput = getChartInput(pid);
 
252
                                String path = getChartSavePath(currentInput.getName() + ".png"); //$NON-NLS-1$
 
253
                                if (path != null) {
 
254
                                        ChartPNG renderer = new ChartPNG(currentInput.getChart());
 
255
                                        renderer.renderPNG(Path.fromOSString(path));
 
256
                                }
 
257
                        }
 
258
                };
 
259
                saveChartAction.setId(SAVE_CHART_ACTION);
 
260
                saveChartAction.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(
 
261
                                MassifPlugin.PLUGIN_ID, "icons/chart-save.png")); //$NON-NLS-1$
 
262
                saveChartAction.setToolTipText(Messages.getString("MassifViewPart.Save_Chart")); //$NON-NLS-1$
 
263
                
 
264
                treeAction = new Action(
 
265
                                Messages.getString("MassifViewPart.Show_Heap_Tree"), IAction.AS_CHECK_BOX) { //$NON-NLS-1$
 
266
                        @Override
 
267
                        public void run() {
 
268
                                if (isChecked()) {
 
269
                                        stackLayout.topControl = treeViewer.getViewer().getControl();
 
270
                                        top.layout();
 
271
                                } else {
 
272
                                        stackLayout.topControl = viewer.getControl();
 
273
                                        top.layout();
 
274
                                }
 
275
                        }
 
276
                };
 
277
                treeAction.setId(TREE_ACTION);
 
278
                treeAction.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(
 
279
                                MassifPlugin.PLUGIN_ID, "icons/call_hierarchy.gif")); //$NON-NLS-1$
 
280
                treeAction.setToolTipText(Messages
 
281
                                .getString("MassifViewPart.Show_Heap_Tree")); //$NON-NLS-1$
 
282
 
 
283
                return new IAction[] { pidAction, chartAction, saveChartAction, treeAction };
 
284
        }
 
285
        
 
286
        protected String getChartSavePath(String defaultName) {
 
287
                Shell parent = new Shell(Display.getDefault());
 
288
                FileDialog dialog = new FileDialog(parent, SWT.SAVE);
 
289
                dialog.setText(Messages.getString("MassifViewPart.Save_chart_dialog_title")); //$NON-NLS-1$
 
290
                dialog.setOverwrite(true);
 
291
                dialog.setFilterExtensions(new String[] { ".png" }); //$NON-NLS-1$
 
292
                dialog.setFileName(defaultName);
 
293
 
 
294
                return dialog.open();
 
295
        }
 
296
 
 
297
        protected void createChart(MassifSnapshot[] snapshots) {
 
298
                String title = chartName + " [PID: " + pid + "]";  //$NON-NLS-1$//$NON-NLS-2$
 
299
                HeapChart chart = new HeapChart(snapshots, title);
 
300
 
 
301
                String name = getInputName(title);
 
302
                ChartEditorInput input = new ChartEditorInput(chart, this, name, pid);
 
303
                chartInputs.add(input);
 
304
 
 
305
                // open the editor
 
306
                displayChart(input);
 
307
        }
 
308
 
 
309
        protected void displayChart(final ChartEditorInput chartInput) {
 
310
                Display.getDefault().syncExec(new Runnable() {
 
311
                        public void run() {
 
312
                                try {
 
313
                                        IWorkbenchPage page = PlatformUI.getWorkbench()
 
314
                                        .getActiveWorkbenchWindow().getActivePage();
 
315
                                        page.openEditor(chartInput, MassifPlugin.EDITOR_ID);
 
316
                                } catch (PartInitException e) {
 
317
                                        e.printStackTrace();
 
318
                                }
 
319
                        }
 
320
                });
 
321
        }
 
322
 
 
323
        protected String getInputName(String description) {
 
324
                String launchName = description.substring(0, description
 
325
                                .indexOf("[massif")); //$NON-NLS-1$
 
326
                return launchName.trim();
 
327
        }
 
328
 
 
329
        @Override
 
330
        public void setFocus() {
 
331
                viewer.getTable().setFocus();
 
332
        }
 
333
 
 
334
        public void refreshView() {
 
335
                if (output != null && pid != null) {
 
336
                        MassifSnapshot[] snapshots = output.getSnapshots(pid);
 
337
                        pidAction.setPids(output.getPids());
 
338
                        if (snapshots != null) {
 
339
                                viewer.setInput(snapshots);
 
340
 
 
341
                                String timeWithUnit = TITLE_TIME + " (" + getUnitString(snapshots) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
 
342
                                for (TableColumn column : viewer.getTable().getColumns()) {
 
343
                                        if (column.getText().startsWith(TITLE_TIME)) {
 
344
                                                column.setText(timeWithUnit);
 
345
                                        }
 
346
                                        viewer.getTable().layout(true);
 
347
                                }
 
348
                                MassifSnapshot[] detailed = getDetailed(snapshots);
 
349
                                nodes = new MassifHeapTreeNode[detailed.length];
 
350
                                for (int i = 0; i < detailed.length; i++) {
 
351
                                        nodes[i] = detailed[i].getRoot();
 
352
                                }
 
353
                                treeViewer.getViewer().setInput(nodes);
 
354
 
 
355
                                // create and display chart
 
356
                                if (snapshots.length > 0) {
 
357
                                        ChartEditorInput input = getChartInput(pid);
 
358
                                        if (input == null) {
 
359
                                                createChart(snapshots);
 
360
                                        }
 
361
                                        else {
 
362
                                                displayChart(input);
 
363
                                        }
 
364
                                }
 
365
                        }
 
366
                }
 
367
        }
 
368
 
 
369
        @Override
 
370
        public void dispose() {
 
371
                // Close all chart editors to keep Valgrind output consistent throughout workbench
 
372
                IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
 
373
                if (page != null) {
 
374
                        for (IEditorInput input : chartInputs) {
 
375
                                IEditorPart part = page.findEditor(input);
 
376
                                if (part != null) {
 
377
                                        page.closeEditor(part, false);
 
378
                                }
 
379
                        }
 
380
                }
 
381
                super.dispose();
 
382
        }
 
383
 
 
384
        public void setTopControl(Control control) {
 
385
                stackLayout.topControl = control;
 
386
                top.layout(true);
 
387
        }
 
388
 
 
389
        public void setOutput(MassifOutput output) {
 
390
                this.output = output;
 
391
        }
 
392
 
 
393
        public MassifOutput getOutput() {
 
394
                return output;
 
395
        }
 
396
 
 
397
        public void setPid(Integer pid) {
 
398
                this.pid = pid;
 
399
        }
 
400
 
 
401
        public Integer getPid() {
 
402
                return pid;
 
403
        }
 
404
 
 
405
        public MassifSnapshot[] getSnapshots() {
 
406
                return output != null && pid != null ? output.getSnapshots(pid) : null;
 
407
        }
 
408
 
 
409
        public TableViewer getTableViewer() {
 
410
                return viewer;
 
411
        }
 
412
 
 
413
        public MassifTreeViewer getTreeViewer() {
 
414
                return treeViewer;
 
415
        }
 
416
 
 
417
        protected class MassifLabelProvider extends LabelProvider implements
 
418
        ITableLabelProvider, IFontProvider {
 
419
 
 
420
                public Image getColumnImage(Object element, int columnIndex) {
 
421
                        Image image = null;
 
422
                        if (columnIndex == 0) {
 
423
                                MassifSnapshot snapshot = (MassifSnapshot) element;
 
424
                                switch (snapshot.getType()) {
 
425
                                case EMPTY:
 
426
                                        break;
 
427
                                case PEAK:
 
428
                                case DETAILED:
 
429
                                        image = AbstractUIPlugin
 
430
                                        .imageDescriptorFromPlugin(MassifPlugin.PLUGIN_ID,
 
431
                                                        "icons/call_hierarchy.gif").createImage(); //$NON-NLS-1$
 
432
                                }
 
433
                        }
 
434
                        return image;
 
435
                }
 
436
 
 
437
                public String getColumnText(Object element, int columnIndex) {
 
438
                        MassifSnapshot snapshot = (MassifSnapshot) element;
 
439
                        DecimalFormat df = new DecimalFormat("#,##0"); //$NON-NLS-1$
 
440
                        switch (columnIndex) {
 
441
                        case 0:
 
442
                                return df.format(snapshot.getNumber());
 
443
                        case 1:
 
444
                                return df.format(snapshot.getTime());
 
445
                        case 2:
 
446
                                return df.format(snapshot.getTotal());
 
447
                        case 3:
 
448
                                return df.format(snapshot.getHeapBytes());
 
449
                        case 4:
 
450
                                return df.format(snapshot.getHeapExtra());
 
451
                        default:
 
452
                                return df.format(snapshot.getStacks());
 
453
                        }
 
454
                }
 
455
 
 
456
                public Font getFont(Object element) {
 
457
                        Font font = null;
 
458
                        MassifSnapshot snapshot = (MassifSnapshot) element;
 
459
                        switch (snapshot.getType()) {
 
460
                        case EMPTY:
 
461
                        case DETAILED:
 
462
                                break;
 
463
                        case PEAK:
 
464
                                font = JFaceResources.getFontRegistry().getBold(
 
465
                                                JFaceResources.DIALOG_FONT);
 
466
                        }
 
467
                        return font;
 
468
                }
 
469
        }
 
470
        
 
471
        public void setChartName(String chartName) {
 
472
                this.chartName = chartName;
 
473
        }
 
474
 
 
475
        private MassifSnapshot[] getDetailed(MassifSnapshot[] snapshots) {
 
476
                ArrayList<MassifSnapshot> list = new ArrayList<MassifSnapshot>();
 
477
                for (MassifSnapshot snapshot : snapshots) {
 
478
                        if (snapshot.getType() != SnapshotType.EMPTY) {
 
479
                                list.add(snapshot);
 
480
                        }
 
481
                }
 
482
                return list.toArray(new MassifSnapshot[list.size()]);
 
483
        }
 
484
 
 
485
        private ChartEditorInput getChartInput(Integer pid) {
 
486
                ChartEditorInput result = null;
 
487
                for (int i = 0; i < chartInputs.size(); i++) {
 
488
                        ChartEditorInput input = chartInputs.get(i);
 
489
                        if (input.getPid().equals(pid)) {
 
490
                                result = input;
 
491
                        }
 
492
                }
 
493
                return result;
 
494
        }
 
495
}