diff -r f65f740e69f9 -r 8e12a575a9b5 sysperfana/memspyext/com.nokia.s60tools.swmtanalyser/src/com/nokia/s60tools/swmtanalyser/ui/graphs/ThreadsGraph.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sysperfana/memspyext/com.nokia.s60tools.swmtanalyser/src/com/nokia/s60tools/swmtanalyser/ui/graphs/ThreadsGraph.java Wed Apr 21 20:01:08 2010 +0300 @@ -0,0 +1,477 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ +package com.nokia.s60tools.swmtanalyser.ui.graphs; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import org.eclipse.draw2d.Graphics; +import org.eclipse.draw2d.Polyline; +import org.eclipse.draw2d.geometry.PointList; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Transform; +import org.eclipse.swt.widgets.Display; + +import com.nokia.s60tools.swmtanalyser.data.CycleData; +import com.nokia.s60tools.swmtanalyser.data.ThreadData; +import com.nokia.s60tools.swmtanalyser.model.SWMTLogReaderUtils; +import com.nokia.s60tools.util.debug.DbgUtility; + +/** + * This class contains all needed logic to paint data related to Threads. + */ +public class ThreadsGraph extends GenericGraph { + + // + // Members + // + private HashMap> threadData = new HashMap>(); + private HashMap samplesData = new HashMap(); + private double visY; + private double multiplier; + private boolean yAxisNeedsToBeChanged = false; + + /* (non-Javadoc) + * @see com.nokia.s60tools.swmtanalyser.ui.graphs.GenericGraph#paint(org.eclipse.draw2d.Graphics) + */ + public void paint(Graphics graphics) { + + DbgUtility.println(DbgUtility.PRIORITY_OPERATION, this.getClass().getSimpleName() + "/paint START"); + + // Getting threads that user has been selected + ArrayList threadsList = this.getUserSelectedItems(); + + if(threadsList == null){ + // No thread data selected for drawing + return; + } + + // Storing original settings before graphs are painted with case-specific settings + int origLineWidth = graphics.getLineWidth(); + Color origColor = graphics.getForegroundColor(); + int origLineStyle = graphics.getLineStyle(); + + // Setting graph drawing specific settings + graphics.setLineWidth(CommonGraphConstants.DEFAULT_GRAPH_LINE_WIDTH); + graphics.setLineStyle(SWT.LINE_SOLID); + + // Getting cycle time stamps + int [] listX = this.calculateTimeIntervals(); + this.lastSampleTime = listX[listX.length-1]; + + // Each thread is drawn by different color stored in external array + int colorIndex=0; + visY = visualSizeY - CommonGraphConstants.XLEGENDSPACE; + + // Looping through all the threads + for(String th: threadsList) + { + ArrayList data = threadData.get(th); + + boolean handleDeleted = false; + + int[] valuesToBePlotted = new int[data.size()]; + int [] points = new int[valuesToBePlotted.length *2]; + + List> ListOfSolidLinePoints = new ArrayList>(); + ArrayList solidLinePoints = new ArrayList(); + + for(int i =0, j=0; i 0){ + solidLinePoints.add(x_point); + solidLinePoints.add(y_point); + DbgUtility.println(DbgUtility.PRIORITY_LOOP, "add 1: x_point: " + x_point + ", y_point: " + y_point); + } + else{ + DbgUtility.println(DbgUtility.PRIORITY_LOOP, "skipped because non-positive Y-axis value"); + } + } + + if(data.get(i).isKernelHandleDeleted() && !handleDeleted){ + handleDeleted = true; + } + + if(handleDeleted && data.get(i).getStatus() == CycleData.New) + { + handleDeleted = false; + + if(y_point > 0){ + // Graphing only positive values + solidLinePoints.add(x_point); + solidLinePoints.add(y_point); + DbgUtility.println(DbgUtility.PRIORITY_LOOP, "add 2:x_point: " + x_point + ", y_point: " + y_point); + } + else{ + DbgUtility.println(DbgUtility.PRIORITY_LOOP, "skipped because zero value"); + } + } + + points[j] = x_point; + points[++j] = y_point; + } + + if(solidLinePoints.size() > 0){ + // Adding point for this thread graph, possible to have more instances for same thread name + ListOfSolidLinePoints.add(solidLinePoints); + } + + visY = visualSizeY - CommonGraphConstants.XLEGENDSPACE; + + // Each thread have a separate color + graphics.setForegroundColor(this.getColors().get(colorIndex)); + + DbgUtility.println(DbgUtility.PRIORITY_OPERATION, "No of solid lists are " + ListOfSolidLinePoints.size()); + + for(int i=0; i < ListOfSolidLinePoints.size(); i++) + { + int [] solidPts = GraphsUtils.CreateIntArrayFromIntegerList(ListOfSolidLinePoints.get(i)); + + if(solidPts != null) + { + if(ListOfSolidLinePoints.size() > 1) + { + int instance_id = i+1; + graphics.drawString("(0" + instance_id + ")", solidPts[0]+2, solidPts[1] - 15); + } + + // Drawing graph based on the stored data points + graphics.drawPolyline(solidPts); + + // Drawing markers to the data points + GraphsUtils.drawMarkers(graphics, solidPts); + } + } + + Polyline line = new Polyline(); + line.setPoints(new PointList(points)); + + DbgUtility.println(DbgUtility.PRIORITY_OPERATION, "Putting the points list in a map for '" + th + "'."); + samplesData.put(th, line); + + colorIndex++; + } + + // Restoring original settings before paint call + graphics.setLineStyle(origLineStyle); + graphics.setForegroundColor(origColor); + graphics.setLineWidth(origLineWidth); + + DbgUtility.println(DbgUtility.PRIORITY_OPERATION, this.getClass().getSimpleName() + "/paint END"); + } + + /* (non-Javadoc) + * @see com.nokia.s60tools.swmtanalyser.ui.graphs.GenericGraph#paintYAxis(org.eclipse.swt.graphics.GC) + */ + public void paintYAxis(GC gc) + { + double visY = visualSizeY - CommonGraphConstants.XLEGENDSPACE; + + switch(this.getEvent()) + { + case NO_OF_FILES: + case HEAP_ALLOC_CELL_COUNT: + case HEAP_FREE_CELL_COUNT: + case NO_OF_PSHANDLES: + multiplier = GraphsUtils.roundToNearestNumber(maxBytes) / visY; + yAxisNeedsToBeChanged = true; + break; + default: + multiplier = GraphsUtils.prettyMaxBytes(maxBytes) / visY; + break; + } + int countOfYAxisLabels = 10; + double yIncrement = visY / countOfYAxisLabels; + int previousBottom = 0; + + for (int k = countOfYAxisLabels; k >= 0; k--) + { + // location for the value indicator is k * 1/10 the height of the display + int y = (int) (visY - (yIncrement * k)); + + int bytes = (int)(yIncrement * multiplier) * k; + + String legend = ""; + + switch(this.getEvent()) + { + case NO_OF_FILES: + case HEAP_ALLOC_CELL_COUNT: + case HEAP_FREE_CELL_COUNT: + case NO_OF_PSHANDLES: + legend += bytes; + break; + default: + //legend += bytes + "B"; + if (maxBytes < 10000) + { + legend += bytes + " B"; //$NON-NLS-1$ + } + else if (maxBytes <= 500 * 1024) + { + legend += (bytes / 1024) + " KB"; //$NON-NLS-1$ + } + else + { + legend += MBformat.format(((float) bytes / (1024 * 1024))) + " MB"; //$NON-NLS-1$ + } + break; + } + + Point extent = gc.stringExtent(legend); + + gc.drawLine(CommonGraphConstants.YLEGENDSPACE - 3, (int)y + 1, CommonGraphConstants.YLEGENDSPACE, (int)y + 1); + + if (y >= previousBottom) + { + gc.drawString(legend, CommonGraphConstants.YLEGENDSPACE - extent.x -2, (int)y); + previousBottom = (int)y + extent.y; + } + } + + if(yAxisNeedsToBeChanged) + drawCountLabel(gc, (int)(visY/3)); + else + drawBytesLabel(gc, (int)(visY/3)); + } + + private void fetchEntireDataForSelectedThreads() + { + ArrayList selectedThreads = this.getUserSelectedItems(); + SWMTLogReaderUtils utils = new SWMTLogReaderUtils(); + + for(String th:selectedThreads) + { + ArrayList thData = utils.getHeapDataFromAllCycles(th, this.getCyclesData()); + threadData.put(th, thData); + } + } + + /* (non-Javadoc) + * @see com.nokia.s60tools.swmtanalyser.ui.graphs.GenericGraph#prepareData() + */ + public void prepareData() + { + fetchEntireDataForSelectedThreads(); + + for(String th:getUserSelectedItems()) + { + ArrayList data = threadData.get(th); + + valuesToBePlotted = new int[data.size()]; + for(int i =0; i maxBytes) + maxBytes = maxValue; + } + + } + + } + + private int getEventValueFromThreadData(ThreadData thData, EventTypes event) + { + int value = 0; + + if(thData.getStatus() == CycleData.Deleted) + return 0; + + switch(event) + { + case NO_OF_FILES: + value = (int)thData.getOpenFiles(); + break; + case MAX_HEAP_SIZE: + value = (int)thData.getMaxHeapSize(); + break; + case HEAP_SIZE: + value = (int)thData.getHeapChunkSize(); + break; + case HEAP_ALLOC_SPACE: + value = (int)thData.getHeapAllocatedSpace(); + break; + case HEAP_FREE_SPACE: + value = (int)thData.getHeapFreeSpace(); + break; + case HEAP_ALLOC_CELL_COUNT: + value = (int)thData.getAllocatedCells(); + break; + case HEAP_FREE_CELL_COUNT: + value = (int)thData.getFreeCells(); + break; + case HEAP_FREE_SLACK: + value = (int)thData.getFreeSlackSize(); + break; + case NO_OF_PSHANDLES: + value = (int)thData.getPsHandles(); + break; + default: + value = 0; + break; + } + + return value; + } + + /* (non-Javadoc) + * @see com.nokia.s60tools.swmtanalyser.ui.graphs.GenericGraph#getToolTipText(int, int) + */ + public String getToolTipText(int x, int y) + { + if(y > (int)visY) + return null; + + String text = ""; + + double xValue = x + timeOffset; + int scaledX = (int)(xValue * getScale()); + + double valY = visY - y; + double scaledY = valY * multiplier; + + String yValue = ""; + + yValue+= (int)(scaledY); + + switch(this.getEvent()) + { + case NO_OF_FILES: + case NO_OF_PSHANDLES: + case HEAP_ALLOC_CELL_COUNT: + case HEAP_FREE_CELL_COUNT: + text += scaledX + " s, " + yValue; + break; + default: + yValue = getFormattedValues(scaledY); + text += scaledX + " s, " + yValue; + break; + } + + for(String th: getUserSelectedItems()) + { + Polyline line = samplesData.get(th); + if(line != null && line.containsPoint(x, y)) + text += "\n" + th; + + } + + return text; + } + + /** + * Get thread data for thread + * @param thread + * @return thread data + */ + public ArrayList getDataForThread(String thread) + { + return this.threadData.get(thread); + } + + /** + * Draws Bytes label on given gc at given position + * @param gc + * @param position + */ + private void drawBytesLabel(GC gc, int position) + { + final Image image = this.getVerticalLabel("Bytes"); + gc.setAdvanced(true); + final org.eclipse.swt.graphics.Rectangle rect2 = image.getBounds(); + Transform transform = new Transform(Display.getDefault()); + + transform.translate(rect2.height / 2f, rect2.width / 2f); + transform.rotate(-90); + transform.translate(-rect2.width / 2f, -rect2.height / 2f); + + gc.setTransform(transform); + gc.drawImage(image, -position, 0); + + transform.dispose(); + gc.dispose(); + + } + + /** + * Draws Count label on given gc at given position + * @param gc + * @param position + */ + private void drawCountLabel(GC gc, int position) + { + final Image image = this.getVerticalLabel("Count"); + gc.setAdvanced(true); + final org.eclipse.swt.graphics.Rectangle rect2 = image.getBounds(); + Transform transform = new Transform(Display.getDefault()); + + transform.translate(rect2.height / 2f, rect2.width / 2f); + transform.rotate(-90); + transform.translate(-rect2.width / 2f, -rect2.height / 2f); + + gc.setTransform(transform); + gc.drawImage(image, -position, 0); + + transform.dispose(); + gc.dispose(); + + } + + private String getFormattedValues(double bytes) + { + String scaledY = ""; + + if (bytes < 10000) + { + scaledY += Bytes_Format.format(bytes) + " B"; //$NON-NLS-1$ + } + else if (bytes <= 500 * 1024) + { + scaledY += Bytes_Format.format(bytes / 1024) + " KB"; //$NON-NLS-1$ + } + else + { + scaledY += MBformat.format(((float) bytes / (1024 * 1024))) + " MB"; //$NON-NLS-1$ + } + + return scaledY; + } +}