|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 package com.nokia.carbide.cpp.pi.memory; |
|
19 |
|
20 import java.awt.Dimension; |
|
21 import java.awt.event.FocusEvent; |
|
22 import java.awt.event.FocusListener; |
|
23 import java.text.DecimalFormat; |
|
24 import java.util.ArrayList; |
|
25 import java.util.Enumeration; |
|
26 import java.util.Hashtable; |
|
27 import java.util.Iterator; |
|
28 import java.util.TreeMap; |
|
29 import java.util.Map.Entry; |
|
30 |
|
31 import org.eclipse.draw2d.ColorConstants; |
|
32 import org.eclipse.draw2d.FigureCanvas; |
|
33 import org.eclipse.draw2d.Graphics; |
|
34 import org.eclipse.draw2d.MouseEvent; |
|
35 import org.eclipse.draw2d.MouseMotionListener; |
|
36 import org.eclipse.draw2d.Panel; |
|
37 import org.eclipse.jface.viewers.CheckboxTableViewer; |
|
38 import org.eclipse.swt.SWT; |
|
39 import org.eclipse.swt.events.SelectionAdapter; |
|
40 import org.eclipse.swt.events.SelectionEvent; |
|
41 import org.eclipse.swt.graphics.Color; |
|
42 import org.eclipse.swt.graphics.GC; |
|
43 import org.eclipse.swt.graphics.Point; |
|
44 import org.eclipse.swt.graphics.RGB; |
|
45 import org.eclipse.swt.graphics.Rectangle; |
|
46 import org.eclipse.swt.layout.GridData; |
|
47 import org.eclipse.swt.layout.GridLayout; |
|
48 import org.eclipse.swt.widgets.Composite; |
|
49 import org.eclipse.swt.widgets.Display; |
|
50 import org.eclipse.swt.widgets.Event; |
|
51 import org.eclipse.swt.widgets.Label; |
|
52 import org.eclipse.swt.widgets.Menu; |
|
53 import org.eclipse.swt.widgets.MenuItem; |
|
54 |
|
55 import com.nokia.carbide.cpp.internal.pi.analyser.NpiInstanceRepository; |
|
56 import com.nokia.carbide.cpp.internal.pi.memory.actions.MemoryStatisticsDialog; |
|
57 import com.nokia.carbide.cpp.internal.pi.model.GenericSampledTrace; |
|
58 import com.nokia.carbide.cpp.internal.pi.plugin.model.IContextMenu; |
|
59 import com.nokia.carbide.cpp.internal.pi.visual.GenericTraceGraph; |
|
60 import com.nokia.carbide.cpp.internal.pi.visual.GraphComposite; |
|
61 import com.nokia.carbide.cpp.internal.pi.visual.PIEvent; |
|
62 import com.nokia.carbide.cpp.internal.pi.visual.PIEventListener; |
|
63 import com.nokia.carbide.cpp.pi.editors.PIPageEditor; |
|
64 import com.nokia.carbide.cpp.pi.util.ColorPalette; |
|
65 |
|
66 public class MemTraceGraph extends GenericTraceGraph implements FocusListener, |
|
67 PIEventListener, MouseMotionListener, IContextMenu { |
|
68 private enum UsageType { |
|
69 CHUNKS, HEAPSTACK, CHUNKS_HEAPSTACK |
|
70 }; |
|
71 |
|
72 private boolean dynamicMemoryVisualisation = false; |
|
73 |
|
74 private MemThreadTable memThreadTable; |
|
75 private CheckboxTableViewer memoryTableViewer; |
|
76 |
|
77 Hashtable<Integer, Integer> threadList; |
|
78 |
|
79 // 3 tabs can share the same trace, but they need different graphs |
|
80 private MemTrace memTrace; |
|
81 |
|
82 private FigureCanvas leftFigureCanvas; |
|
83 |
|
84 // whether any table items are enabled |
|
85 private boolean haveEnabled = false; |
|
86 |
|
87 private boolean readyToDraw = false; |
|
88 private int width = 600; |
|
89 private int height = 400; |
|
90 |
|
91 private final int defaultSamplingTime = 3000; |
|
92 private int samplingTime; |
|
93 private UsageType paintMode; |
|
94 private int[] chunkListY; |
|
95 private int[] stackListY; |
|
96 private int[] chunkStackListY; |
|
97 private int[] polyListX; |
|
98 |
|
99 int[] stackAndHeapPoints; |
|
100 int[] chunkPoints; |
|
101 |
|
102 private TreeMap<Long, Integer> eventChunkListY; |
|
103 private TreeMap<Long, Integer> eventStackListY; |
|
104 private TreeMap<Long, Integer> eventChunkStackListY; |
|
105 |
|
106 private int minStack = Integer.MAX_VALUE; |
|
107 private int maxStack = 0; |
|
108 private int minHeap = Integer.MAX_VALUE; |
|
109 private int maxChunks = 0; |
|
110 private int minStackHeap = Integer.MAX_VALUE; |
|
111 private int maxStackHeap = 0; |
|
112 |
|
113 private DecimalFormat memKBFormat = new DecimalFormat(Messages |
|
114 .getString("MemTraceGraph.KBformat")); //$NON-NLS-1$ |
|
115 private DecimalFormat memMBFloatFormat = new DecimalFormat(Messages |
|
116 .getString("MemTraceGraph.MBformat")); //$NON-NLS-1$ |
|
117 |
|
118 private static int xLegendHeight = 20; |
|
119 |
|
120 private boolean firstTimeDrawThreadList = true; |
|
121 |
|
122 public MemTraceGraph(int graphIndex, MemTrace memTrace, int uid) { |
|
123 super((GenericSampledTrace) memTrace); |
|
124 |
|
125 // |
|
126 |
|
127 if (memTrace != null) { |
|
128 |
|
129 // if no version number is found from trace, we can assume |
|
130 // that sampling based memory model is in use |
|
131 this.memTrace = memTrace; |
|
132 if (memTrace.getVersion() == 0) { |
|
133 memTrace.setVersion(156); |
|
134 } |
|
135 } |
|
136 |
|
137 this.graphIndex = graphIndex; |
|
138 this.memTrace = memTrace; |
|
139 this.paintMode = UsageType.CHUNKS_HEAPSTACK; |
|
140 this.setScale(10); |
|
141 |
|
142 if (memTrace == null) { |
|
143 System.out.print(Messages |
|
144 .getString("MemTraceGraph.traceDataNotFound")); //$NON-NLS-1$ |
|
145 return; |
|
146 } |
|
147 |
|
148 samplingTime = calcSamplingTime(); |
|
149 memTrace.gatherDrawData(); |
|
150 |
|
151 // create the label and a tableviewer |
|
152 Composite holder = new Composite(NpiInstanceRepository.getInstance() |
|
153 .getProfilePage(uid, graphIndex).getBottomComposite(), SWT.NONE); |
|
154 |
|
155 GridLayout gl = new GridLayout(); |
|
156 gl.marginHeight = 0; |
|
157 gl.marginWidth = 0; |
|
158 gl.marginLeft = 0; |
|
159 gl.marginRight = 0; |
|
160 holder.setLayout(gl); |
|
161 |
|
162 Label label = new Label(holder, SWT.CENTER); |
|
163 label |
|
164 .setBackground(holder.getDisplay().getSystemColor( |
|
165 SWT.COLOR_WHITE)); |
|
166 label.setFont(PIPageEditor.helvetica_8); |
|
167 label.setText(Messages.getString("MemTraceGraph.graphTitle")); //$NON-NLS-1$ |
|
168 label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
|
169 |
|
170 this.memThreadTable = new MemThreadTable(this, holder); |
|
171 this.memoryTableViewer = this.memThreadTable.getTableViewer(); |
|
172 |
|
173 this.readyToDraw = true; |
|
174 } |
|
175 |
|
176 public void action(String actionString) { |
|
177 if (actionString.equals("chunk_on")) //$NON-NLS-1$ |
|
178 { |
|
179 paintMode = UsageType.CHUNKS; |
|
180 } else if (actionString.equals("heapstack_on")) //$NON-NLS-1$ |
|
181 { |
|
182 paintMode = UsageType.HEAPSTACK; |
|
183 } else if (actionString.equals("chunk_heapstack_on")) //$NON-NLS-1$ |
|
184 { |
|
185 paintMode = UsageType.CHUNKS_HEAPSTACK; |
|
186 } else if (actionString.equals("rescale_on")) //$NON-NLS-1$ |
|
187 { |
|
188 dynamicMemoryVisualisation = true; |
|
189 makeThreadDrawLists(); |
|
190 } else if (actionString.equals("rescale_off")) //$NON-NLS-1$ |
|
191 { |
|
192 dynamicMemoryVisualisation = false; |
|
193 makeThreadDrawLists(); |
|
194 } else { |
|
195 return; |
|
196 } |
|
197 |
|
198 this.repaint(); |
|
199 if (this.leftFigureCanvas != null) |
|
200 this.leftFigureCanvas.redraw(); |
|
201 } |
|
202 |
|
203 public void piEventReceived(PIEvent be) { |
|
204 switch (be.getType()) { |
|
205 // when the selection area changes, the maximum values shown for each |
|
206 // thread/process |
|
207 // may change; if dynamicMemoryVisualisation is on, we'll also have a |
|
208 // new y-scaling factor |
|
209 case PIEvent.SELECTION_AREA_CHANGED: |
|
210 |
|
211 // before updating the tables, make sure that the memory trace has |
|
212 // computing the |
|
213 // maximum usage by each thread/process within the new time interval |
|
214 double startTime = PIPageEditor.currentPageEditor().getStartTime(); |
|
215 double endTime = PIPageEditor.currentPageEditor().getEndTime(); |
|
216 |
|
217 memTrace.setMaxMemDataByInterval((int) (startTime * 1000), |
|
218 (int) (endTime * 1000)); |
|
219 |
|
220 // send this message to the 2 other graphs |
|
221 PIEvent be2 = new PIEvent(be.getValueObject(), |
|
222 PIEvent.SELECTION_AREA_CHANGED2); |
|
223 |
|
224 for (int i = 0; i < 3; i++) { |
|
225 MemTraceGraph graph = (MemTraceGraph) memTrace.getTraceGraph(i); |
|
226 |
|
227 if (graph != this) { |
|
228 graph.piEventReceived(be2); |
|
229 } |
|
230 } |
|
231 |
|
232 be = be2; |
|
233 |
|
234 // FALL THROUGH |
|
235 case PIEvent.SELECTION_AREA_CHANGED2: |
|
236 double[] values = (double[]) be.getValueObject(); |
|
237 this.setSelectionStart(values[0]); |
|
238 this.setSelectionEnd(values[1]); |
|
239 this.memThreadTable.piEventReceived(be); |
|
240 this.repaint(); |
|
241 break; |
|
242 |
|
243 case PIEvent.CHANGED_MEMORY_TABLE: |
|
244 this.makeThreadDrawLists(); |
|
245 this.repaint(); |
|
246 if (this.leftFigureCanvas != null) |
|
247 this.leftFigureCanvas.redraw(); |
|
248 break; |
|
249 |
|
250 case PIEvent.SCALE_CHANGED: |
|
251 double scale = ((Double) be.getValueObject()).doubleValue(); |
|
252 this.setScale(scale); |
|
253 this.repaint(); |
|
254 break; |
|
255 |
|
256 case PIEvent.SCROLLED: |
|
257 Event event = ((Event) be.getValueObject()); |
|
258 this.parentComponent.setScrolledOrigin(event.x, event.y); |
|
259 this.repaint(); |
|
260 break; |
|
261 |
|
262 default: |
|
263 break; |
|
264 } |
|
265 } |
|
266 |
|
267 public void focusGained(FocusEvent fe) { |
|
268 } |
|
269 |
|
270 public void focusLost(FocusEvent fe) { |
|
271 } |
|
272 |
|
273 public void paint(Panel panel, Graphics graphics) { |
|
274 if (!readyToDraw) |
|
275 return; |
|
276 |
|
277 this.setSize(this.getSize().width, getVisualSize().height); |
|
278 this.makeThreadDrawLists(); |
|
279 this.paintThreads(graphics); |
|
280 this.drawDottedLineBackground(graphics, MemTraceGraph.xLegendHeight); |
|
281 |
|
282 // draw the same selection as the Address/Thread trace |
|
283 this.drawSelectionSection(graphics, MemTraceGraph.xLegendHeight); |
|
284 } |
|
285 |
|
286 private void paintSampledChunks(Graphics graphics) { |
|
287 if (chunkListY == null) |
|
288 return; |
|
289 |
|
290 int[] points = new int[chunkListY.length * 2]; |
|
291 |
|
292 for (int i = 0, j = 0; i < chunkListY.length; i++) { |
|
293 points[j++] = polyListX[i]; |
|
294 points[j++] = chunkListY[i]; |
|
295 } |
|
296 |
|
297 graphics.setBackgroundColor(ColorConstants.orange); |
|
298 graphics.fillPolygon(points); |
|
299 graphics.setBackgroundColor(ColorConstants.gray); |
|
300 } |
|
301 |
|
302 private void paintEventBasedChunks(Graphics graphics) { |
|
303 /* |
|
304 * if (chunkListY == null) return; |
|
305 */ |
|
306 |
|
307 /* |
|
308 * int[] points = new int[chunkListY.length * 2]; |
|
309 * |
|
310 * for (int i = 0, j =0; i < chunkListY.length; i++) { points[j++] = |
|
311 * polyListX[i]; points[j++] = chunkListY[i]; } |
|
312 */ |
|
313 |
|
314 graphics.setBackgroundColor(ColorConstants.orange); |
|
315 graphics.fillPolygon(chunkPoints); |
|
316 graphics.setBackgroundColor(ColorConstants.gray); |
|
317 } |
|
318 |
|
319 private void paintSampledStack(Graphics graphics, UsageType paintMode) { |
|
320 if (stackListY == null) |
|
321 return; |
|
322 |
|
323 // if needed, move every y-value that is 0 down a little so that the |
|
324 // line is more visible |
|
325 boolean increase0 = paintMode != UsageType.HEAPSTACK; |
|
326 |
|
327 int[] points = new int[stackListY.length * 2]; |
|
328 |
|
329 for (int i = 0, j = 0; i < stackListY.length; i++) { |
|
330 points[j++] = polyListX[i]; |
|
331 points[j] = stackListY[i]; |
|
332 |
|
333 if (increase0 && (points[j] == 0)) |
|
334 points[j] = 1; |
|
335 |
|
336 j++; |
|
337 } |
|
338 |
|
339 if (paintMode == UsageType.HEAPSTACK) { |
|
340 graphics.setBackgroundColor(ColorConstants.blue); |
|
341 graphics.fillPolygon(points); |
|
342 graphics.setBackgroundColor(ColorConstants.gray); |
|
343 } else { |
|
344 int lineWidth = graphics.getLineWidth(); |
|
345 Color color = graphics.getForegroundColor(); |
|
346 |
|
347 graphics.setForegroundColor(ColorConstants.blue); |
|
348 graphics.setLineWidth(2); |
|
349 graphics.drawPolyline(points); |
|
350 graphics.setForegroundColor(color); |
|
351 graphics.setLineWidth(lineWidth); |
|
352 } |
|
353 } |
|
354 |
|
355 private void paintEventBasedStack(Graphics graphics, UsageType paintMode) { |
|
356 if (eventStackListY == null) |
|
357 return; |
|
358 |
|
359 // if needed, move every y-value that is 0 down a little so that the |
|
360 // line is more visible |
|
361 boolean increase0 = paintMode != UsageType.HEAPSTACK; |
|
362 |
|
363 /* |
|
364 * int[] points = new int[stackListY.length * 2]; |
|
365 * |
|
366 * for (int i = 0, j =0; i < stackListY.length; i++) { points[j++] = |
|
367 * polyListX[i]; points[j] = stackListY[i]; |
|
368 * |
|
369 * if (increase0 && (points[j] == 0)) points[j] = 1; |
|
370 * |
|
371 * j++; } |
|
372 */ |
|
373 |
|
374 if (paintMode == UsageType.HEAPSTACK) { |
|
375 graphics.setBackgroundColor(ColorConstants.blue); |
|
376 graphics.fillPolygon(stackAndHeapPoints); |
|
377 graphics.setBackgroundColor(ColorConstants.gray); |
|
378 } else { |
|
379 int lineWidth = graphics.getLineWidth(); |
|
380 Color color = graphics.getForegroundColor(); |
|
381 |
|
382 graphics.setForegroundColor(ColorConstants.blue); |
|
383 graphics.setLineWidth(2); |
|
384 graphics.drawPolyline(stackAndHeapPoints); |
|
385 graphics.setForegroundColor(color); |
|
386 graphics.setLineWidth(lineWidth); |
|
387 } |
|
388 } |
|
389 |
|
390 private void paintThreads(Graphics graphics) { |
|
391 if (memTrace.getVersion() >= 202) { |
|
392 paintEventBasedThreads(graphics); |
|
393 } else { |
|
394 paintSampledThreads(graphics); |
|
395 } |
|
396 } |
|
397 |
|
398 private void paintSampledThreads(Graphics graphics) { |
|
399 // if there are no threads to draw |
|
400 if (!haveEnabled) |
|
401 return; |
|
402 |
|
403 int maxBytes = 0; |
|
404 |
|
405 double multiplier; |
|
406 |
|
407 if (paintMode == UsageType.CHUNKS && chunkListY != null) { |
|
408 if (dynamicMemoryVisualisation) |
|
409 maxBytes = maxChunks; |
|
410 else |
|
411 maxBytes = memTrace.getTraceMaxChunks(); |
|
412 |
|
413 // multiplier is bytes / pixel in the graph |
|
414 if (true)// !dynamicMemoryVisualisation) |
|
415 multiplier = prettyMaxBytes(maxBytes) / height; |
|
416 else |
|
417 multiplier = maxBytes / height; |
|
418 // System.out.println("maxBytes " + maxBytes + " multiplier " + |
|
419 // multiplier + " height " + height); |
|
420 |
|
421 for (int j = 1; j < chunkListY.length - 1; j++) { |
|
422 chunkListY[j] = (int) (height - chunkListY[j] / multiplier); |
|
423 |
|
424 if (chunkListY[j] < 0) |
|
425 chunkListY[j] = 0; |
|
426 } |
|
427 |
|
428 this.paintSampledChunks(graphics); |
|
429 } else if (paintMode == UsageType.HEAPSTACK && stackListY != null) { |
|
430 if (dynamicMemoryVisualisation) |
|
431 maxBytes = maxStack; |
|
432 else |
|
433 maxBytes = memTrace.getTraceMaxStackHeap(); |
|
434 |
|
435 // multiplier is bytes / pixel in the final graph |
|
436 if (true)// !dynamicMemoryVisualisation) |
|
437 multiplier = prettyMaxBytes(maxBytes) / height; |
|
438 else |
|
439 multiplier = maxBytes / height; |
|
440 // System.out.println("maxBytes " + maxBytes + " multiplier " + |
|
441 // multiplier + " height " + height); |
|
442 |
|
443 for (int j = 1; j < stackListY.length - 1; j++) { |
|
444 stackListY[j] = (int) (height - stackListY[j] / multiplier); |
|
445 |
|
446 if (stackListY[j] < 0) |
|
447 stackListY[j] = 0; |
|
448 } |
|
449 |
|
450 this.paintSampledStack(graphics, paintMode); |
|
451 } else if (chunkStackListY != null) // heap and stack |
|
452 { |
|
453 if (dynamicMemoryVisualisation) |
|
454 maxBytes = maxChunks > maxStack ? maxChunks : maxStack; |
|
455 else |
|
456 maxBytes = memTrace.getTraceMaxChunks() > memTrace |
|
457 .getTraceMaxStackHeap() ? memTrace.getTraceMaxChunks() |
|
458 : memTrace.getTraceMaxStackHeap(); |
|
459 |
|
460 // multiplier is bytes / pixel in the final graph |
|
461 if (true)// !dynamicMemoryVisualisation) |
|
462 multiplier = prettyMaxBytes(maxBytes) / height; |
|
463 else |
|
464 multiplier = maxBytes / height; |
|
465 // System.out.println("maxBytes " + maxBytes + " multiplier " + |
|
466 // multiplier + " height " + height); |
|
467 |
|
468 int totalStackUsed = 0; |
|
469 |
|
470 for (int j = 1; j < chunkListY.length - 1; j++) { |
|
471 totalStackUsed += stackListY[j]; |
|
472 |
|
473 chunkListY[j] = (int) (height - chunkListY[j] / multiplier); |
|
474 stackListY[j] = (int) (height - stackListY[j] / multiplier); |
|
475 |
|
476 if (stackListY[j] < 0) |
|
477 stackListY[j] = 0; |
|
478 |
|
479 if (chunkListY[j] < 0) |
|
480 chunkListY[j] = 0; |
|
481 } |
|
482 |
|
483 this.paintSampledChunks(graphics); |
|
484 if (totalStackUsed > 0) |
|
485 this.paintSampledStack(graphics, paintMode); |
|
486 } |
|
487 } |
|
488 |
|
489 private void paintEventBasedThreads(Graphics graphics) { |
|
490 // paints treads when using event based memory model |
|
491 |
|
492 // if there are no threads to draw |
|
493 if (!haveEnabled) |
|
494 return; |
|
495 |
|
496 int maxBytes = 0; |
|
497 |
|
498 double yMultiplier; |
|
499 double xMultiplier; |
|
500 xMultiplier = this.getScale(); |
|
501 |
|
502 // get las x coordinate of trace |
|
503 long lastEvent = ((MemSample) memTrace.samples.get(memTrace.samples |
|
504 .size() - 1)).sampleSynchTime; |
|
505 int lastXCoord = (int) (lastEvent / xMultiplier); |
|
506 |
|
507 if (paintMode == UsageType.CHUNKS && eventChunkListY != null) { |
|
508 chunkPoints = new int[eventChunkListY.size() * 4 + 6]; |
|
509 |
|
510 if (dynamicMemoryVisualisation) |
|
511 maxBytes = maxChunks; |
|
512 else |
|
513 maxBytes = memTrace.getTraceMaxChunks(); |
|
514 |
|
515 // multiplier is bytes / pixel in the graph |
|
516 if (true)// !dynamicMemoryVisualisation) |
|
517 yMultiplier = prettyMaxBytes(maxBytes) / height; |
|
518 else |
|
519 yMultiplier = maxBytes / height; |
|
520 // System.out.println("maxBytes " + maxBytes + " multiplier " + |
|
521 // multiplier + " height " + height); |
|
522 |
|
523 createGraphPolygon(this.eventChunkListY, chunkPoints, xMultiplier, |
|
524 yMultiplier, lastXCoord); |
|
525 |
|
526 this.paintEventBasedChunks(graphics); |
|
527 } else if (paintMode == UsageType.HEAPSTACK && eventStackListY != null) { |
|
528 stackAndHeapPoints = new int[eventStackListY.size() * 4 + 6]; |
|
529 |
|
530 if (dynamicMemoryVisualisation) |
|
531 maxBytes = maxStack; |
|
532 else |
|
533 maxBytes = memTrace.getTraceMaxStackHeap(); |
|
534 |
|
535 // multiplier is bytes / pixel in the final graph |
|
536 if (true)// !dynamicMemoryVisualisation) |
|
537 yMultiplier = prettyMaxBytes(maxBytes) / height; |
|
538 else |
|
539 yMultiplier = (double) maxBytes / height; |
|
540 |
|
541 createGraphPolygon(this.eventStackListY, stackAndHeapPoints, |
|
542 xMultiplier, yMultiplier, lastXCoord); |
|
543 this.paintEventBasedStack(graphics, paintMode); |
|
544 } else if (eventChunkStackListY != null) // heap and stack |
|
545 { |
|
546 stackAndHeapPoints = new int[eventStackListY.size() * 4 + 6]; |
|
547 chunkPoints = new int[eventChunkListY.size() * 4 + 6]; |
|
548 |
|
549 if (dynamicMemoryVisualisation) |
|
550 maxBytes = maxChunks > maxStack ? maxChunks : maxStack; |
|
551 else |
|
552 maxBytes = memTrace.getTraceMaxChunks() > memTrace |
|
553 .getTraceMaxStackHeap() ? memTrace.getTraceMaxChunks() |
|
554 : memTrace.getTraceMaxStackHeap(); |
|
555 |
|
556 // multiplier is bytes / pixel in the final graph |
|
557 if (true)// !dynamicMemoryVisualisation) |
|
558 yMultiplier = prettyMaxBytes(maxBytes) / height; |
|
559 else |
|
560 yMultiplier = maxBytes / height; |
|
561 // System.out.println("maxBytes " + maxBytes + " multiplier " + |
|
562 // multiplier + " height " + height); |
|
563 |
|
564 int totalStackUsed = 1; |
|
565 |
|
566 createGraphPolygon(this.eventStackListY, stackAndHeapPoints, |
|
567 xMultiplier, yMultiplier, lastXCoord); |
|
568 createGraphPolygon(this.eventChunkListY, chunkPoints, xMultiplier, |
|
569 yMultiplier, lastXCoord); |
|
570 |
|
571 this.paintEventBasedChunks(graphics); |
|
572 if (totalStackUsed > 0) |
|
573 this.paintEventBasedStack(graphics, paintMode); |
|
574 } |
|
575 } |
|
576 |
|
577 public void createGraphPolygon(TreeMap<Long, Integer> map, int[] points, |
|
578 double xMultiplier, double yMultiplier, int endXCoord) { |
|
579 // Creates graph polygon from TreeMap that contains all x and y values |
|
580 // of one graph. |
|
581 |
|
582 int index = 2; |
|
583 int xCoord = 0; |
|
584 int yCoord = 0; |
|
585 int previousYCoord = 0; |
|
586 |
|
587 // get first event and key from map. |
|
588 Iterator<Long> keys = map.keySet().iterator(); |
|
589 Iterator<Integer> values = map.values().iterator(); |
|
590 |
|
591 |
|
592 int previousXCoord = 0; |
|
593 int countOfSameXCoords = 1; |
|
594 |
|
595 // set first into zero so that polygon is drawn correctly |
|
596 points[0] = 0; |
|
597 points[1] = height; |
|
598 |
|
599 while (keys.hasNext()) { |
|
600 // create polygon's points so that each memory allocation is drawn |
|
601 // as one leap in graph |
|
602 |
|
603 // calculate new x coord's value and round it to integer |
|
604 xCoord = (int) (((double) keys.next() / xMultiplier) + 0.5); |
|
605 |
|
606 // calculate new y-coord's value and round it to integer |
|
607 yCoord = (int) (((double) height - (double) values.next() / yMultiplier) + 0.5); |
|
608 |
|
609 if (xCoord == previousXCoord && index > 3) { |
|
610 // if more than one sample at one point in the screen, count |
|
611 // average value |
|
612 // for y coordinate |
|
613 |
|
614 // count average value |
|
615 double sum = ((double) yCoord + (double) previousYCoord |
|
616 * (double) countOfSameXCoords); |
|
617 countOfSameXCoords++; |
|
618 yCoord = (int) (sum / (double) (countOfSameXCoords)); |
|
619 |
|
620 // add average coordinate to array |
|
621 index = index - 4; |
|
622 index = addCoordsToGraphArray(xCoord, yCoord, index, points); |
|
623 |
|
624 } else { |
|
625 countOfSameXCoords = 1; |
|
626 } |
|
627 |
|
628 index = addCoordsToGraphArray(xCoord, yCoord, index, points); |
|
629 |
|
630 // save coordinates to previousValues |
|
631 previousYCoord = yCoord; |
|
632 previousXCoord = xCoord; |
|
633 } |
|
634 |
|
635 // Set last coordinates to zero so that polygon is drawn correctly |
|
636 points[points.length - 4] = endXCoord; |
|
637 points[points.length - 3] = points[points.length - 5]; |
|
638 |
|
639 points[points.length - 2] = endXCoord; |
|
640 points[points.length - 1] = height; |
|
641 } |
|
642 |
|
643 private int addCoordsToGraphArray(int xCoord, int yCoord, int arrayIndex, |
|
644 int[] array) { |
|
645 |
|
646 // adds coordinates to array so that polygon can be drawn from that |
|
647 // array |
|
648 |
|
649 // instead of straight lines between points, we draw graph more |
|
650 // realistically |
|
651 // so that single memory events are shown as a leap in graph. |
|
652 |
|
653 // first x coordinate |
|
654 array[arrayIndex] = xCoord; |
|
655 arrayIndex++; |
|
656 |
|
657 // first y coordinate, if possible use same y-coord than previous value |
|
658 if ((arrayIndex - 2) < 0) { |
|
659 array[arrayIndex] = 0; |
|
660 } else { |
|
661 array[arrayIndex] = array[arrayIndex - 2]; |
|
662 } |
|
663 arrayIndex++; |
|
664 |
|
665 // second x coordinate |
|
666 array[arrayIndex] = xCoord; |
|
667 arrayIndex++; |
|
668 |
|
669 // second y coordinate |
|
670 array[arrayIndex] = yCoord; |
|
671 arrayIndex++; |
|
672 |
|
673 return arrayIndex; |
|
674 } |
|
675 |
|
676 private void makeThreadDrawLists() { |
|
677 if (memTrace.getVersion() >= 202) { |
|
678 makeEventBasedThreadDrawLists(); |
|
679 } else { |
|
680 makeSamplingBasedThreadDrawLists(); |
|
681 } |
|
682 } |
|
683 |
|
684 private void makeEventBasedThreadDrawLists() { |
|
685 |
|
686 // Get checked table items |
|
687 Object[] checked = this.memoryTableViewer.getCheckedElements(); |
|
688 |
|
689 // if no items is checked do nothing |
|
690 haveEnabled = (checked != null) && (checked.length > 0); |
|
691 if (!haveEnabled) { |
|
692 this.eventChunkListY = null; |
|
693 this.eventStackListY = null; |
|
694 this.eventChunkStackListY = null; |
|
695 return; |
|
696 } |
|
697 |
|
698 // create maps for events for chunks, stacks and chunksandstacks |
|
699 this.eventChunkListY = new TreeMap<Long, Integer>(); |
|
700 this.eventStackListY = new TreeMap<Long, Integer>(); |
|
701 this.eventChunkStackListY = new TreeMap<Long, Integer>(); |
|
702 |
|
703 // go thru checked items |
|
704 for (int j = 0; j < checked.length; j++) { |
|
705 // check that item is instance of memory thread |
|
706 if (!(checked[j] instanceof MemThread)) |
|
707 continue; |
|
708 |
|
709 MemThread memThread = (MemThread) checked[j]; |
|
710 |
|
711 // get all samples of the thread |
|
712 TreeMap<Long, MemSample> memSamples = memTrace |
|
713 .getDrawDataByMemThread(memThread); |
|
714 |
|
715 // ensure that thread has samples |
|
716 if ((memSamples == null) || (memSamples.size() == 0)) { |
|
717 System.out |
|
718 .println(Messages |
|
719 .getString("MemTraceGraph.threadProcessNoSamples1") + memThread.fullName + Messages.getString("MemTraceGraph.threadProcessNoSamples")); //$NON-NLS-1$ //$NON-NLS-2$ |
|
720 continue; |
|
721 } |
|
722 |
|
723 // create empty sample |
|
724 MemSample previousSample = new MemSample(new MemThread(0, "", ""), |
|
725 0, 0, 0); |
|
726 |
|
727 Iterator<MemSample> values = memSamples.values().iterator(); |
|
728 |
|
729 while (values.hasNext()) { |
|
730 MemSample memSample = values.next(); |
|
731 // go thru samples from single threas |
|
732 // save changes after last received sample into TreeMaps |
|
733 addEventToTreeMap(this.eventStackListY, |
|
734 memSample.sampleSynchTime, memSample.stackSize |
|
735 - previousSample.stackSize); |
|
736 addEventToTreeMap(this.eventChunkListY, |
|
737 memSample.sampleSynchTime, memSample.heapSize |
|
738 - previousSample.heapSize); |
|
739 addEventToTreeMap( |
|
740 this.eventChunkStackListY, |
|
741 memSample.sampleSynchTime, |
|
742 memSample.heapSize |
|
743 + memSample.stackSize |
|
744 - (previousSample.stackSize + previousSample.heapSize)); |
|
745 |
|
746 previousSample = memSample; |
|
747 |
|
748 } |
|
749 } |
|
750 |
|
751 // calculate max values and values in each event |
|
752 this.maxStack = calculateValuesInEachEvent(eventStackListY); |
|
753 this.maxStackHeap = calculateValuesInEachEvent(eventChunkStackListY); |
|
754 this.maxChunks = calculateValuesInEachEvent(eventChunkListY); |
|
755 |
|
756 if (this.memTrace.getTraceMaxChunks() == 0) { |
|
757 this.memTrace.setTraceMaxChunks(maxChunks); |
|
758 this.memTrace.setTraceMaxStackHeap(maxStack); |
|
759 this.memTrace.setTraceMaxTotal(maxStackHeap); |
|
760 |
|
761 //repaint left legend if this is first time that tread lists are made |
|
762 if(firstTimeDrawThreadList){ |
|
763 this.parentComponent.paintLeftLegend(); |
|
764 firstTimeDrawThreadList = false; |
|
765 } |
|
766 |
|
767 } |
|
768 |
|
769 } |
|
770 |
|
771 private int calculateValuesInEachEvent(TreeMap<Long, Integer> map) { |
|
772 // this function calculates total sum memory in each event based |
|
773 // on the change map it receives as a parameter |
|
774 |
|
775 // function also returns maximum value in whole map |
|
776 |
|
777 int maxValue = 0; |
|
778 int previousValue = 0; |
|
779 |
|
780 Iterator<Integer> values = map.values().iterator(); |
|
781 Iterator<Long> keys = map.keySet().iterator(); |
|
782 |
|
783 while (values.hasNext()) { |
|
784 |
|
785 int memValue = values.next(); |
|
786 long memKey = keys.next(); |
|
787 |
|
788 // go thru array and count actual state of |
|
789 // memory in each event |
|
790 int value = previousValue + memValue; |
|
791 |
|
792 // is value is greater that max value save |
|
793 // it as max value |
|
794 if (value > maxValue) { |
|
795 maxValue = value; |
|
796 } |
|
797 |
|
798 map.put(memKey, value); |
|
799 previousValue = value; |
|
800 } |
|
801 return maxValue; |
|
802 } |
|
803 |
|
804 private void addEventToTreeMap(TreeMap<Long, Integer> map, long key, |
|
805 int item) { |
|
806 // Adds event into tree map. |
|
807 // If event with that same key(time code) already exists values are |
|
808 // added. |
|
809 |
|
810 int previousValue = 0; |
|
811 if (map.containsKey(key)) { |
|
812 previousValue = map.get(key); |
|
813 } |
|
814 |
|
815 map.put(key, previousValue + item); |
|
816 } |
|
817 |
|
818 private void makeSamplingBasedThreadDrawLists() { |
|
819 |
|
820 // Get checked table items |
|
821 Object[] checked = this.memoryTableViewer.getCheckedElements(); |
|
822 |
|
823 haveEnabled = (checked != null) && (checked.length > 0); |
|
824 |
|
825 // is no items are checked do nothing |
|
826 if (!haveEnabled) { |
|
827 this.chunkListY = null; |
|
828 this.stackListY = null; |
|
829 this.chunkStackListY = null; |
|
830 calculateMinAndMaxValues(); |
|
831 return; |
|
832 } |
|
833 |
|
834 // Get first and last sample from trace |
|
835 int firstSample = memTrace.getFirstSampleNumber(); |
|
836 int lastSample = memTrace.getLastSampleNumber(); |
|
837 |
|
838 // Get number of sampling points |
|
839 int samplesTotal = (int) 1 + (lastSample - firstSample) / samplingTime; |
|
840 |
|
841 // create arrays for y axis values of chunks, stacks chunksandstacks + |
|
842 // polylistx |
|
843 this.chunkListY = new int[samplesTotal * 2 + 1]; |
|
844 this.stackListY = new int[samplesTotal * 2 + 1]; |
|
845 this.chunkStackListY = new int[samplesTotal * 2 + 1]; |
|
846 this.polyListX = new int[samplesTotal * 2 + 1]; |
|
847 |
|
848 // go thru checked items |
|
849 for (int j = 0; j < checked.length; j++) { |
|
850 // check that item is instance of memory thread |
|
851 if (!(checked[j] instanceof MemThread)) |
|
852 continue; |
|
853 |
|
854 MemThread memThread = (MemThread) checked[j]; |
|
855 |
|
856 // get all samples of the thread |
|
857 TreeMap<Long, MemSample> memSamples = memTrace |
|
858 .getDrawDataByMemThread(memThread); |
|
859 |
|
860 // ensure that thread has samples |
|
861 if ((memSamples == null) || (memSamples.size() == 0)) { |
|
862 System.out |
|
863 .println(Messages |
|
864 .getString("MemTraceGraph.threadProcessNoSamples1") + memThread.fullName + Messages.getString("MemTraceGraph.threadProcessNoSamples")); //$NON-NLS-1$ //$NON-NLS-2$ |
|
865 continue; |
|
866 } |
|
867 |
|
868 int sampleCount = memSamples.size(); |
|
869 int[] tempListX = new int[sampleCount * 2 + 1]; |
|
870 |
|
871 int counter = 0; |
|
872 |
|
873 Iterator<MemSample> values = memSamples.values().iterator(); |
|
874 while (values.hasNext()) { |
|
875 MemSample memSample = values.next(); |
|
876 // get index where sample is located at x-axis |
|
877 int index = (int) ((memSample.sampleSynchTime - firstSample) / samplingTime) * 2 + 1; |
|
878 |
|
879 tempListX[counter + 1] = (int) (memSample.sampleSynchTime / getScale()); |
|
880 |
|
881 // add samples value to chunks, stacks chunksandstacks arrays |
|
882 this.stackListY[index] += memSample.stackSize; |
|
883 this.chunkListY[index] += memSample.heapSize; |
|
884 this.chunkStackListY[index] += memSample.heapSize |
|
885 + memSample.stackSize; |
|
886 |
|
887 counter++; |
|
888 tempListX[counter + 1] = (int) ((memSample.sampleSynchTime + samplingTime) / getScale()); |
|
889 |
|
890 index++; |
|
891 if (this.paintMode == UsageType.CHUNKS) { |
|
892 this.chunkListY[index] += memSample.heapSize; |
|
893 counter++; |
|
894 } else if (this.paintMode == UsageType.HEAPSTACK) { |
|
895 this.stackListY[index] += memSample.stackSize; |
|
896 counter++; |
|
897 } else // paint mode chunk and stack |
|
898 { |
|
899 this.stackListY[index] += memSample.stackSize; |
|
900 this.chunkListY[index] += memSample.heapSize; |
|
901 this.chunkStackListY[index] += memSample.heapSize |
|
902 + memSample.stackSize; |
|
903 counter++; |
|
904 } |
|
905 |
|
906 } |
|
907 |
|
908 // tempListX[0] = (int) |
|
909 // (((MemSample)memSamples.firstEntry().getValue()).sampleSynchTime |
|
910 // / getScale()); |
|
911 MemSample firstMemSample = (MemSample)memSamples.get(memSamples.firstKey()); |
|
912 tempListX[0] = (int) ((firstMemSample.sampleSynchTime / getScale())); |
|
913 tempListX[tempListX.length - 1] = tempListX[tempListX.length - 2]; |
|
914 |
|
915 // defaults the originating and ending points into window corners |
|
916 this.stackListY[0] = height; |
|
917 this.stackListY[stackListY.length - 1] = height; |
|
918 this.chunkListY[0] = height; |
|
919 this.chunkListY[chunkListY.length - 1] = height; |
|
920 this.chunkStackListY[0] = height; |
|
921 this.chunkStackListY[chunkStackListY.length - 1] = height; |
|
922 } |
|
923 |
|
924 calculatePolylistX(); |
|
925 calculateMinAndMaxValues(); |
|
926 } |
|
927 |
|
928 private void calculateMinAndMaxValues() { |
|
929 // find heapValue; |
|
930 minHeap = Integer.MAX_VALUE; |
|
931 maxChunks = 0; |
|
932 |
|
933 if (chunkListY != null) { |
|
934 for (int i = 1; i < chunkListY.length - 1; i++) { |
|
935 if (chunkListY[i] < minHeap) |
|
936 minHeap = chunkListY[i]; |
|
937 if (chunkListY[i] > maxChunks) |
|
938 maxChunks = chunkListY[i]; |
|
939 } |
|
940 } |
|
941 |
|
942 // find stackValue; |
|
943 minStack = Integer.MAX_VALUE; |
|
944 maxStack = 0; |
|
945 |
|
946 if (stackListY != null) { |
|
947 for (int i = 1; i < stackListY.length - 1; i++) { |
|
948 if (stackListY[i] < minStack) |
|
949 minStack = stackListY[i]; |
|
950 if (stackListY[i] > maxStack) |
|
951 maxStack = stackListY[i]; |
|
952 } |
|
953 } |
|
954 |
|
955 // find stackValue+HeapValue; |
|
956 minStackHeap = Integer.MAX_VALUE; |
|
957 maxStackHeap = 0; |
|
958 |
|
959 if (stackListY != null && chunkListY != null) { |
|
960 for (int i = 1; i < stackListY.length - 1; i++) { |
|
961 if ((stackListY[i] + chunkListY[i]) < minStackHeap) |
|
962 minStackHeap = stackListY[i] + chunkListY[i]; |
|
963 |
|
964 if ((stackListY[i] + chunkListY[i]) > maxStackHeap) |
|
965 maxStackHeap = stackListY[i] + chunkListY[i]; |
|
966 } |
|
967 } |
|
968 } |
|
969 |
|
970 private void calculatePolylistX() { |
|
971 int currentSample = memTrace.getFirstSampleNumber(); |
|
972 int lastSample = memTrace.getLastSampleNumber(); |
|
973 int sampleCount = (int) 1 + (lastSample - currentSample) / samplingTime; |
|
974 |
|
975 polyListX = new int[sampleCount * 2 + 1]; |
|
976 |
|
977 int i = 0; |
|
978 |
|
979 for (Enumeration e = memTrace.getSamples(); e.hasMoreElements();) { |
|
980 MemSample ms = (MemSample) e.nextElement(); |
|
981 if ((int) ms.sampleSynchTime != currentSample) { |
|
982 i++; |
|
983 currentSample = (int) ms.sampleSynchTime; |
|
984 polyListX[i + 1] = (int) (ms.sampleSynchTime / getScale()); |
|
985 i++; |
|
986 polyListX[i + 1] = polyListX[i]; |
|
987 } |
|
988 } |
|
989 |
|
990 polyListX[0] = (int) (memTrace.getFirstSampleNumber() / getScale()); |
|
991 polyListX[1] = (int) (memTrace.getFirstSampleNumber() / getScale()); |
|
992 polyListX[polyListX.length - 1] = polyListX[polyListX.length - 2]; |
|
993 } |
|
994 |
|
995 public void setSize(int x, int y) { |
|
996 this.width = x; |
|
997 this.height = y - MemTraceGraph.xLegendHeight; |
|
998 |
|
999 if (this.height <= 0) |
|
1000 this.height = 1; |
|
1001 } |
|
1002 |
|
1003 public Dimension getSize() { |
|
1004 return new Dimension(width, height); |
|
1005 } |
|
1006 |
|
1007 private int calcSamplingTime() { |
|
1008 long time = memTrace.getFirstSampleNumber(); |
|
1009 for (Enumeration e = memTrace.getSamples(); e.hasMoreElements();) { |
|
1010 MemSample tmp = (MemSample) e.nextElement(); |
|
1011 if (tmp.sampleSynchTime != time) { |
|
1012 time = tmp.sampleSynchTime - time; |
|
1013 return (int) time; |
|
1014 } |
|
1015 } |
|
1016 return defaultSamplingTime; |
|
1017 } |
|
1018 |
|
1019 public void refreshDataFromTrace() { |
|
1020 } |
|
1021 |
|
1022 public void repaint() { |
|
1023 this.parentComponent.repaintComponent(); |
|
1024 } |
|
1025 |
|
1026 public int getSamplingTime() { |
|
1027 return samplingTime; |
|
1028 } |
|
1029 |
|
1030 /* |
|
1031 * (non-Javadoc) |
|
1032 * |
|
1033 * @seecom.nokia.carbide.cpp.internal.pi.plugin.model.IContextMenu# |
|
1034 * addContextMenuItems(org.eclipse.swt.widgets.Menu, |
|
1035 * org.eclipse.swt.events.MouseEvent) |
|
1036 */ |
|
1037 public void addContextMenuItems(Menu menu, |
|
1038 org.eclipse.swt.events.MouseEvent me) { |
|
1039 new MenuItem(menu, SWT.SEPARATOR); |
|
1040 |
|
1041 MenuItem memoryStatsItem = new MenuItem(menu, SWT.PUSH); |
|
1042 memoryStatsItem.setText(Messages.getString("MemoryPlugin.memoryStats")); //$NON-NLS-1$ |
|
1043 memoryStatsItem.addSelectionListener(new SelectionAdapter() { |
|
1044 public void widgetSelected(SelectionEvent e) { |
|
1045 new MemoryStatisticsDialog(Display.getCurrent()); |
|
1046 } |
|
1047 }); |
|
1048 |
|
1049 new MenuItem(menu, SWT.SEPARATOR); |
|
1050 |
|
1051 boolean showChunk = true; |
|
1052 boolean showHeapStack = true; |
|
1053 |
|
1054 Object obj; |
|
1055 // if there is a showChunk value associated with the current Analyser |
|
1056 // tab, then use it |
|
1057 obj = NpiInstanceRepository.getInstance().activeUidGetPersistState( |
|
1058 "com.nokia.carbide.cpp.pi.memory.showChunk"); //$NON-NLS-1$ |
|
1059 if ((obj != null) && (obj instanceof Boolean)) |
|
1060 // retrieve the current value |
|
1061 showChunk = (Boolean) obj; |
|
1062 else |
|
1063 // set the initial value |
|
1064 NpiInstanceRepository.getInstance().activeUidSetPersistState( |
|
1065 "com.nokia.carbide.cpp.pi.memory.showChunk", showChunk); //$NON-NLS-1$ |
|
1066 |
|
1067 // if there is a showHeapStack value associated with the current |
|
1068 // Analyser tab, then use it |
|
1069 obj = NpiInstanceRepository.getInstance().activeUidGetPersistState( |
|
1070 "com.nokia.carbide.cpp.pi.memory.showHeapStack"); //$NON-NLS-1$ |
|
1071 if ((obj != null) && (obj instanceof Boolean)) |
|
1072 // retrieve the current value |
|
1073 showHeapStack = (Boolean) obj; |
|
1074 else |
|
1075 // set the initial value |
|
1076 NpiInstanceRepository |
|
1077 .getInstance() |
|
1078 .activeUidSetPersistState( |
|
1079 "com.nokia.carbide.cpp.pi.memory.showHeapStack", showHeapStack); //$NON-NLS-1$ |
|
1080 |
|
1081 MenuItem showChunkItem = new MenuItem(menu, SWT.RADIO); |
|
1082 showChunkItem.setText(Messages.getString("MemoryPlugin.showChunks")); //$NON-NLS-1$ |
|
1083 showChunkItem.setSelection(showChunk && !showHeapStack); |
|
1084 showChunkItem.addSelectionListener(new SelectionAdapter() { |
|
1085 public void widgetSelected(SelectionEvent e) { |
|
1086 NpiInstanceRepository.getInstance().activeUidSetPersistState( |
|
1087 "com.nokia.carbide.cpp.pi.memory.showChunk", true); //$NON-NLS-1$ |
|
1088 NpiInstanceRepository.getInstance().activeUidSetPersistState( |
|
1089 "com.nokia.carbide.cpp.pi.memory.showHeapStack", false); //$NON-NLS-1$ |
|
1090 |
|
1091 for (int i = 0; i < 3; i++) { |
|
1092 MemTraceGraph graph = (MemTraceGraph) memTrace |
|
1093 .getTraceGraph(i); |
|
1094 graph.action("chunk_on"); //$NON-NLS-1$ |
|
1095 } |
|
1096 } |
|
1097 }); |
|
1098 |
|
1099 MenuItem showHeapItem = new MenuItem(menu, SWT.RADIO); |
|
1100 showHeapItem.setText(Messages.getString("MemoryPlugin.showHeapStack")); //$NON-NLS-1$ |
|
1101 showHeapItem.setSelection(showHeapStack && !showChunk); |
|
1102 showHeapItem.addSelectionListener(new SelectionAdapter() { |
|
1103 public void widgetSelected(SelectionEvent e) { |
|
1104 NpiInstanceRepository.getInstance().activeUidSetPersistState( |
|
1105 "com.nokia.carbide.cpp.pi.memory.showChunk", false); //$NON-NLS-1$ |
|
1106 NpiInstanceRepository.getInstance().activeUidSetPersistState( |
|
1107 "com.nokia.carbide.cpp.pi.memory.showHeapStack", true); //$NON-NLS-1$ |
|
1108 |
|
1109 for (int i = 0; i < 3; i++) { |
|
1110 MemTraceGraph graph = (MemTraceGraph) memTrace |
|
1111 .getTraceGraph(i); |
|
1112 graph.action("heapstack_on"); //$NON-NLS-1$ |
|
1113 } |
|
1114 } |
|
1115 }); |
|
1116 |
|
1117 MenuItem showBothItem = new MenuItem(menu, SWT.RADIO); |
|
1118 showBothItem.setText(Messages.getString("MemoryPlugin.showAll")); //$NON-NLS-1$ |
|
1119 showBothItem.setSelection(showChunk && showHeapStack); |
|
1120 showBothItem.addSelectionListener(new SelectionAdapter() { |
|
1121 public void widgetSelected(SelectionEvent e) { |
|
1122 NpiInstanceRepository.getInstance().activeUidSetPersistState( |
|
1123 "com.nokia.carbide.cpp.pi.memory.showChunk", true); //$NON-NLS-1$ |
|
1124 NpiInstanceRepository.getInstance().activeUidSetPersistState( |
|
1125 "com.nokia.carbide.cpp.pi.memory.showHeapStack", true); //$NON-NLS-1$ |
|
1126 |
|
1127 for (int i = 0; i < 3; i++) { |
|
1128 MemTraceGraph graph = (MemTraceGraph) memTrace |
|
1129 .getTraceGraph(i); |
|
1130 graph.action("chunk_heapstack_on"); //$NON-NLS-1$ |
|
1131 } |
|
1132 } |
|
1133 }); |
|
1134 |
|
1135 new MenuItem(menu, SWT.SEPARATOR); |
|
1136 |
|
1137 boolean rescale = false; |
|
1138 |
|
1139 // if there is a rescale value associated with the current Analyser tab, |
|
1140 // then use it |
|
1141 obj = NpiInstanceRepository.getInstance().activeUidGetPersistState( |
|
1142 "com.nokia.carbide.cpp.pi.memory.rescale"); //$NON-NLS-1$ |
|
1143 if ((obj != null) && (obj instanceof Boolean)) |
|
1144 // retrieve the current value |
|
1145 rescale = (Boolean) obj; |
|
1146 else |
|
1147 // set the initial value |
|
1148 NpiInstanceRepository.getInstance().activeUidSetPersistState( |
|
1149 "com.nokia.carbide.cpp.pi.memory.rescale", rescale); //$NON-NLS-1$ |
|
1150 |
|
1151 final boolean rescaleFinal = rescale; |
|
1152 |
|
1153 MenuItem rescaleItem = new MenuItem(menu, SWT.CHECK); |
|
1154 rescaleItem.setText(Messages.getString("MemoryPlugin.dynamicRescale")); //$NON-NLS-1$ |
|
1155 rescaleItem.setSelection(rescale); |
|
1156 rescaleItem.addSelectionListener(new SelectionAdapter() { |
|
1157 public void widgetSelected(SelectionEvent e) { |
|
1158 String action; |
|
1159 NpiInstanceRepository |
|
1160 .getInstance() |
|
1161 .activeUidSetPersistState( |
|
1162 "com.nokia.carbide.cpp.pi.memory.rescale", !rescaleFinal); //$NON-NLS-1$ |
|
1163 if (!rescaleFinal) { |
|
1164 action = "rescale_on"; //$NON-NLS-1$ |
|
1165 } else { |
|
1166 action = "rescale_off"; //$NON-NLS-1$ |
|
1167 } |
|
1168 |
|
1169 for (int i = 0; i < 3; i++) { |
|
1170 MemTraceGraph graph = (MemTraceGraph) memTrace |
|
1171 .getTraceGraph(i); |
|
1172 graph.action(action); |
|
1173 } |
|
1174 } |
|
1175 }); |
|
1176 } |
|
1177 |
|
1178 public void paintLeftLegend(FigureCanvas figureCanvas, GC gc) { |
|
1179 // System.out.println("MEM"); if (true)return; |
|
1180 // if there are no threads to draw |
|
1181 GC localGC = gc; |
|
1182 |
|
1183 if (gc == null) |
|
1184 gc = new GC(PIPageEditor.currentPageEditor().getSite().getShell()); |
|
1185 |
|
1186 if (this.leftFigureCanvas == null) |
|
1187 this.leftFigureCanvas = figureCanvas; |
|
1188 |
|
1189 Rectangle rect = ((GraphComposite) figureCanvas.getParent()).figureCanvas |
|
1190 .getClientArea(); |
|
1191 |
|
1192 double visY = rect.height - MemTraceGraph.xLegendHeight; |
|
1193 |
|
1194 gc.setForeground(ColorPalette.getColor(new RGB(100, 100, 100))); |
|
1195 gc.setBackground(ColorPalette.getColor(new RGB(255, 255, 255))); |
|
1196 |
|
1197 int maxBytes = 0; |
|
1198 |
|
1199 if (paintMode == UsageType.CHUNKS) { |
|
1200 if (dynamicMemoryVisualisation) |
|
1201 maxBytes = maxChunks; |
|
1202 else |
|
1203 maxBytes = memTrace.getTraceMaxChunks(); |
|
1204 } else if (paintMode == UsageType.HEAPSTACK) { |
|
1205 if (dynamicMemoryVisualisation) |
|
1206 maxBytes = maxStack; |
|
1207 else |
|
1208 maxBytes = memTrace.getTraceMaxStackHeap(); |
|
1209 } else { |
|
1210 if (dynamicMemoryVisualisation) |
|
1211 maxBytes = maxChunks > maxStack ? maxChunks : maxStack; |
|
1212 else |
|
1213 maxBytes = memTrace.getTraceMaxChunks() > memTrace |
|
1214 .getTraceMaxStackHeap() ? memTrace.getTraceMaxChunks() |
|
1215 : memTrace.getTraceMaxStackHeap(); |
|
1216 } |
|
1217 |
|
1218 double multiplier = 0; |
|
1219 |
|
1220 if (true)// !dynamicMemoryVisualisation) |
|
1221 multiplier = prettyMaxBytes(maxBytes) / visY; |
|
1222 else |
|
1223 multiplier = maxBytes / visY; |
|
1224 |
|
1225 int previousBottom = 0; // bottom of the previous legend drawn |
|
1226 String legend; |
|
1227 double yIncrement = visY / 10; |
|
1228 |
|
1229 // draw 11 value indicators (0..10) to the scale |
|
1230 for (int k = 10; k >= 0; k--) { |
|
1231 // location for the value indicator is k * 1/10 the height of the |
|
1232 // display |
|
1233 int y = (int) (visY - (yIncrement * k)); |
|
1234 |
|
1235 // calculate the exact byte value at the height by multiplying |
|
1236 // the height with the [bytes / pixel] value |
|
1237 int bytes = (int) ((visY * multiplier) / 10.0) * k; |
|
1238 |
|
1239 // construct the text for each scale |
|
1240 legend = ""; //$NON-NLS-1$ |
|
1241 |
|
1242 // if the amount of data is less than 512KB, draw it as bytes |
|
1243 if (maxBytes < 10000) { |
|
1244 legend += bytes + Messages.getString("MemTraceGraph.byByte"); //$NON-NLS-1$ |
|
1245 } |
|
1246 // if the amount is more than 512KB, draw it as KB |
|
1247 else if (maxBytes <= 500 * 1024) { |
|
1248 legend += (bytes / 1024) |
|
1249 + Messages.getString("MemTraceGraph.byKB"); //$NON-NLS-1$ |
|
1250 } else { |
|
1251 legend += memMBFloatFormat |
|
1252 .format(((float) bytes / (1024 * 1024))) |
|
1253 + Messages.getString("MemTraceGraph.byMB"); //$NON-NLS-1$ |
|
1254 } |
|
1255 |
|
1256 Point extent = gc.stringExtent(legend); |
|
1257 |
|
1258 gc.drawLine(GenericTraceGraph.yLegendWidth - 3, (int) y + 1, |
|
1259 GenericTraceGraph.yLegendWidth, (int) y + 1); |
|
1260 |
|
1261 if (y >= previousBottom) { |
|
1262 gc.drawString(legend, GenericTraceGraph.yLegendWidth - extent.x |
|
1263 - 4, (int) y); |
|
1264 previousBottom = (int) y + extent.y; |
|
1265 } |
|
1266 } |
|
1267 |
|
1268 if (localGC == null) { |
|
1269 gc.dispose(); |
|
1270 figureCanvas.redraw(); |
|
1271 } |
|
1272 } |
|
1273 |
|
1274 /* |
|
1275 * (non-Javadoc) |
|
1276 * |
|
1277 * @see |
|
1278 * org.eclipse.draw2d.MouseMotionListener#mouseDragged(org.eclipse.draw2d |
|
1279 * .MouseEvent) |
|
1280 */ |
|
1281 public void mouseDragged(MouseEvent me) { |
|
1282 } |
|
1283 |
|
1284 /* |
|
1285 * (non-Javadoc) |
|
1286 * |
|
1287 * @see |
|
1288 * org.eclipse.draw2d.MouseMotionListener#mouseEntered(org.eclipse.draw2d |
|
1289 * .MouseEvent) |
|
1290 */ |
|
1291 public void mouseEntered(MouseEvent me) { |
|
1292 } |
|
1293 |
|
1294 /* |
|
1295 * (non-Javadoc) |
|
1296 * |
|
1297 * @see |
|
1298 * org.eclipse.draw2d.MouseMotionListener#mouseExited(org.eclipse.draw2d |
|
1299 * .MouseEvent) |
|
1300 */ |
|
1301 public void mouseExited(MouseEvent me) { |
|
1302 } |
|
1303 |
|
1304 /* |
|
1305 * (non-Javadoc) |
|
1306 * |
|
1307 * @see |
|
1308 * org.eclipse.draw2d.MouseMotionListener#mouseHover(org.eclipse.draw2d. |
|
1309 * MouseEvent) |
|
1310 */ |
|
1311 public void mouseHover(MouseEvent me) { |
|
1312 } |
|
1313 |
|
1314 /* |
|
1315 * (non-Javadoc) |
|
1316 * |
|
1317 * @see |
|
1318 * org.eclipse.draw2d.MouseMotionListener#mouseMoved(org.eclipse.draw2d. |
|
1319 * MouseEvent) |
|
1320 */ |
|
1321 public void mouseMoved(MouseEvent me) { |
|
1322 double x = me.x * this.getScale(); |
|
1323 double y = me.y; |
|
1324 |
|
1325 if (y > this.getVisualSizeY() - MemTraceGraph.xLegendHeight) { |
|
1326 this.setToolTipText(null); |
|
1327 return; |
|
1328 } |
|
1329 |
|
1330 // mouse event may return out of range X, that may |
|
1331 // crash when we use it to index data array |
|
1332 x = x >= 0 ? x : 0; |
|
1333 if (me.x >= this.getVisualSize().width |
|
1334 + this.parentComponent.getScrolledOrigin().x) { |
|
1335 x = (this.getVisualSize().width - 1) * this.getScale(); |
|
1336 } |
|
1337 |
|
1338 if (x > PIPageEditor.currentPageEditor().getMaxEndTime() * 1000) { |
|
1339 this.setToolTipText(null); |
|
1340 return; |
|
1341 } |
|
1342 |
|
1343 long chunkSize = 0; |
|
1344 long stackHeapSize = 0; |
|
1345 // long totalSize = 0; |
|
1346 Entry<Long, Integer> entry; |
|
1347 if (memTrace.getVersion() >= 202) { |
|
1348 if (eventStackListY != null) { |
|
1349 /* |
|
1350 * TODO entry = eventStackListY.floorEntry((long)x); if(entry != |
|
1351 * null){ stackHeapSize = entry.getValue(); } |
|
1352 */ |
|
1353 Integer value = (Integer) MemTrace.getFloorEntryFromMap( |
|
1354 (long) x, eventStackListY); |
|
1355 if (value != null) { |
|
1356 stackHeapSize = value; |
|
1357 } |
|
1358 } |
|
1359 if (eventChunkListY != null) { |
|
1360 /* |
|
1361 * TODO entry = eventChunkListY.floorEntry((long)x); if(entry != |
|
1362 * null){ chunkSize = entry.getValue(); } |
|
1363 */ |
|
1364 Integer value = (Integer) MemTrace.getFloorEntryFromMap( |
|
1365 (long) x, eventChunkListY); |
|
1366 if (value != null) { |
|
1367 chunkSize = value; |
|
1368 } |
|
1369 |
|
1370 }/* |
|
1371 * if(stackHeapSize == null){ this.setToolTipText(null); return; } |
|
1372 */ |
|
1373 } else { |
|
1374 ArrayList<MemSample> samples = memTrace |
|
1375 .getMemSampleDataByTime((long) x); |
|
1376 |
|
1377 if (samples != null) { |
|
1378 // tooltip always shows totals for the threads/processes that |
|
1379 // are selected |
|
1380 for (int i = 0; i < samples.size(); i++) { |
|
1381 MemSample sample = samples.get(i); |
|
1382 MemThread memThread = sample.thread; |
|
1383 if (memThread.isEnabled(this.graphIndex)) { |
|
1384 chunkSize += sample.heapSize; |
|
1385 stackHeapSize += sample.stackSize; |
|
1386 // totalSize += sample.heapSize + sample.stackSize; |
|
1387 } |
|
1388 } |
|
1389 } |
|
1390 } |
|
1391 |
|
1392 int time = (int) x; |
|
1393 |
|
1394 if (this.paintMode == UsageType.CHUNKS_HEAPSTACK) { |
|
1395 this.setToolTipText((time / 1000.0) |
|
1396 + Messages.getString("MemTraceGraph.totalTooltip1") //$NON-NLS-1$ |
|
1397 + memKBFormat.format((chunkSize + 512) / 1024) |
|
1398 + Messages.getString("MemTraceGraph.totalTooltip2") //$NON-NLS-1$ |
|
1399 + memKBFormat.format((stackHeapSize + 512) / 1024)); |
|
1400 } else if (this.paintMode == UsageType.CHUNKS) { |
|
1401 this.setToolTipText((time / 1000.0) |
|
1402 + Messages.getString("MemTraceGraph.chunkTooltip1") //$NON-NLS-1$ |
|
1403 + (chunkSize + 512) / 1024 |
|
1404 + Messages.getString("MemTraceGraph.chunkTooltip2")); //$NON-NLS-1$ |
|
1405 } else if (this.paintMode == UsageType.HEAPSTACK) { |
|
1406 this.setToolTipText((time / 1000.0) |
|
1407 + Messages.getString("MemTraceGraph.stackHeapTooltip1") //$NON-NLS-1$ |
|
1408 + (stackHeapSize + 512) / 1024 |
|
1409 + Messages.getString("MemTraceGraph.stackHeapTooltip2")); //$NON-NLS-1$ |
|
1410 } else |
|
1411 return; |
|
1412 |
|
1413 } |
|
1414 |
|
1415 public void setCurrentThreads(Hashtable<Integer, Integer> threadList) { |
|
1416 this.threadList = threadList; |
|
1417 } |
|
1418 |
|
1419 public int getGraphIndex() { |
|
1420 return this.graphIndex; |
|
1421 } |
|
1422 |
|
1423 public MemTrace getMemTrace() { |
|
1424 return this.memTrace; |
|
1425 } |
|
1426 |
|
1427 public MemThreadTable getMemThreadTable() { |
|
1428 return this.memThreadTable; |
|
1429 } |
|
1430 |
|
1431 public boolean haveEnabled() { |
|
1432 return this.haveEnabled; |
|
1433 } |
|
1434 |
|
1435 private int prettyMaxBytes(int bytes) { |
|
1436 if (bytes < 1000) |
|
1437 bytes = 1000; |
|
1438 else if (bytes < 10000) |
|
1439 bytes = 10000; |
|
1440 else if (bytes <= 10 * 1024) |
|
1441 bytes = 10 * 1024; |
|
1442 else if (bytes <= 20 * 1024) |
|
1443 bytes = 20 * 1024; |
|
1444 else if (bytes <= 30 * 1024) |
|
1445 bytes = 30 * 1024; |
|
1446 else if (bytes <= 50 * 1024) |
|
1447 bytes = 50 * 1024; |
|
1448 else if (bytes <= 100 * 1024) |
|
1449 bytes = 100 * 1024; |
|
1450 else if (bytes <= 200 * 1024) |
|
1451 bytes = 200 * 1024; |
|
1452 else if (bytes <= 300 * 1024) |
|
1453 bytes = 300 * 1024; |
|
1454 else if (bytes <= 500 * 1024) |
|
1455 bytes = 500 * 1024; |
|
1456 else if (bytes <= 1000 * 1024) |
|
1457 bytes = 1000 * 1024; |
|
1458 else if (bytes <= 1 * 1024 * 1024) |
|
1459 bytes = 1 * 1024 * 1024; |
|
1460 else if (bytes <= 2 * 1024 * 1024) |
|
1461 bytes = 2 * 1024 * 1024; |
|
1462 else if (bytes <= 3 * 1024 * 1024) |
|
1463 bytes = 3 * 1024 * 1024; |
|
1464 else if (bytes <= 5 * 1024 * 1024) |
|
1465 bytes = 5 * 1024 * 1024; |
|
1466 else if (bytes <= 10 * 1024 * 1024) |
|
1467 bytes = 10 * 1024 * 1024; |
|
1468 else if (bytes <= 20 * 1024 * 1024) |
|
1469 bytes = 20 * 1024 * 1024; |
|
1470 else if (bytes <= 30 * 1024 * 1024) |
|
1471 bytes = 30 * 1024 * 1024; |
|
1472 else if (bytes <= 50 * 1024 * 1024) |
|
1473 bytes = 50 * 1024 * 1024; |
|
1474 else if (bytes <= 100 * 1024 * 1024) |
|
1475 bytes = 100 * 1024 * 1024; |
|
1476 else if (bytes <= 200 * 1024 * 1024) |
|
1477 bytes = 200 * 1024 * 1024; |
|
1478 else if (bytes <= 300 * 1024 * 1024) |
|
1479 bytes = 300 * 1024 * 1024; |
|
1480 else if (bytes <= 500 * 1024 * 1024) |
|
1481 bytes = 500 * 1024 * 1024; |
|
1482 else |
|
1483 bytes = ((bytes + 1024 * 1024 * 1024 - 1) / (1024 * 1024 * 1024)) |
|
1484 * (1024 * 1024 * 1024); |
|
1485 |
|
1486 return bytes; |
|
1487 } |
|
1488 |
|
1489 } |