sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi/src/com/nokia/carbide/cpp/internal/pi/model/ProfiledGeneric.java
changeset 5 844b047e260d
parent 2 b9ab3b238396
child 12 ae255c9aa552
--- a/sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi/src/com/nokia/carbide/cpp/internal/pi/model/ProfiledGeneric.java	Tue Apr 20 14:41:43 2010 +0300
+++ b/sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi/src/com/nokia/carbide/cpp/internal/pi/model/ProfiledGeneric.java	Wed Apr 21 15:14:16 2010 +0300
@@ -25,48 +25,131 @@
 
 import com.nokia.carbide.cpp.pi.util.ColorPalette;
 
+/**
+ * Generic class for a profiled element, such as a thread, a binary or a function
+ *
+ */
 public abstract class ProfiledGeneric
 {
+	/** number of graphs */
+	protected static final int GRAPH_COUNT = 3;
+	
+	/**
+	 * Unique ordinal for this profiled element, given on creation. The first created profiled element
+	 * of this kind has an index of zero, each following is incremented by one.
+	 */
     protected int index = -1;
+    /** Name of this profiled element */
     private String nameString;
+    /** Colour with which this profiled element is represented in any graph or legend view*/
     protected Color color;
-    protected int totalSampleCount;
+    /** overall sample count of this profiled element in the trace */
+	protected int totalSampleCount;
+	/** timestamp of the first sample for this profiled element */
     protected int firstSample = -1;
+	/** timestamp of the last sample for this profiled element */
     protected int lastSample = -1;
-    private int   recentSample = -1;
-    private int   recentSampleCount = 0;
-    private int   recentPercentage = -1;
-    protected int[] activityList;
-    private int[] sampleList;
-    private int[][] cumulativeList = new int[3][];
-    
+
 	// since each instance may be used by table viewers for multiple graphs,
 	// keep per graph (for a maximum of 3 graphs):
     //	whether the thread/binary/function is currently enabled
     //	sample count in the selected graph area
     //	% load in the selected graph area
 	//  string version of graph percent load
-    protected boolean[] enableValue = {true, true, true};
-	protected int[]   graphSampleCount = { 0, 0, 0 };
-	protected float[] graphPercentLoad = { 0.0f, 0.0f, 0.0f };
-    private String[]  averageLoadValueString = { "", "", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-	
-    private PointList[] pointList  = {new PointList(), new PointList(), new PointList()};
-    protected int[] activityP = null;
+    
+    /**
+  	 * The cumulative list contains for each bucket the 
+  	 * cumulative sample percentage of the same bucket of all ProfiledGenerics
+  	 * so far processed (not including the values of the current ProfiledGeneric).
+  	 * 
+  	 * In other words it's containing the bottom or start value of this
+  	 * profiled element to draw on the graph (the graph drawn just underneath the 
+  	 * graph of this profiled element)
+  	 */
+    private float[][] cumulativeList;
+    /** checkbox enabled state of this profiled element for each of the graphs */
+    protected boolean[] enableValue;
+    /** current sample count of this profiled element for each of the graphs, changes with enabled state, selected time frame, master filtering */
+	protected int[]   graphSampleCount;
+    /** current sample percentage load of this profiled element for each of the graphs, changes with enabled state, selected time frame, master filtering */
+	protected float[] graphPercentLoad;
+    /** current sample average load of this profiled element for each of the graphs, changes with enabled state, selected time frame, master filtering */
+    private String[]  averageLoadValueString; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$	
+    /** PointList for each graphs polyline */
+    private PointList[] pointList;
+    
+    //  bucket values 
+    //
+    /** holds the sample count value for all buckets, calculated as one-off when trace is first processed */
+    private int[] activityN = null;
+    /** holds percentage value for all buckets, calculated as one-off when trace is first processed */
+    protected float[] activityP = null;
+    /** holds start timestamp of all buckets, calculated as one-off when trace is first processed */
     private int[] activityT = null;
+    /** the index of the bucket currently updated */
     protected int activityIndx = 0;
     
-    public ProfiledGeneric()
-    {
-      // default to light gray
-      this.color = ColorPalette.getColor(new RGB(192, 192, 192));
-     }
+    /** total number of CPUs in the system; 1 for non-SMP trace */
+	private int cpuCount;
+
+    //for SMP
+    protected boolean isSMP;
+	protected int[] totalSampleCountSMP;
+    
+    protected float[][] activityPSMP;
+    private int[][] activityNSMP;
     
+	/**
+	 * Constructor
+	 * @param cpuCount number of CPUs present in the trace
+	 * @param graphCount number of graphs to display
+	 */
+	public ProfiledGeneric(int cpuCount, int graphCount) {
+		if (graphCount < 0){
+			throw new IllegalArgumentException("graphCount must be greater than 0.");
+		}
+		// default to light gray
+		this.color = ColorPalette.getColor(new RGB(192, 192, 192));
+		this.cpuCount = cpuCount;
+		
+		// init variables for values per graph
+		cumulativeList = new float[graphCount][];
+		enableValue = new boolean[graphCount];
+		graphSampleCount = new int[graphCount];
+		graphPercentLoad = new float[graphCount];
+		averageLoadValueString = new String[graphCount];
+		pointList = new PointList[graphCount];
+		for (int graph = 0; graph < graphCount; graph++) {
+		    enableValue[graph] = true;
+			averageLoadValueString[graph] = ""; //$NON-NLS-1$
+			pointList[graph] = new PointList();
+		}
+
+		if (cpuCount > 1) { // SMP
+
+			isSMP = true;
+			totalSampleCountSMP = new int[cpuCount];
+
+			activityPSMP = new float[cpuCount][];
+			activityNSMP = new int[cpuCount][];
+		}
+	}
+    
+    /**
+     * Setter for the name of the profiled element
+     * @param nameString
+     */
     public void setNameString(String nameString)
     {
     	this.nameString = nameString;
     }
     
+    /**
+     * Adds a point to the PointList of the given graph
+     * @param graphIndex the graph to use
+     * @param x the X-coordinate of the point
+     * @param y the Y-coordinate of the point
+     */
     public void addPointToPolyline(int graphIndex, int x, int y)
     {
     	pointList[graphIndex].addPoint(x, y);
@@ -87,51 +170,92 @@
     	return this.index;
     }
     
-    public void setActivityMarkCount(int size)
-    {
-    	this.activityP = new int[size];
-    	this.activityT = new int[size];
+    /**
+     * Creates bucket arrays. This also propagates to SMP bucket arrays.  
+     * @param numberOfBuckets The total number of buckets to use.
+     */
+    public void createBuckets(int numberOfBuckets){
+    	this.activityP = new float[numberOfBuckets];
+    	this.activityT = new int[numberOfBuckets];
+    	this.activityN = new int[numberOfBuckets];
+    	if (isSMP){
+			for (int cpu = 0; cpu < cpuCount; cpu++) {
+		    	this.activityPSMP[cpu] = new float[numberOfBuckets];
+		    	this.activityNSMP[cpu] = new int[numberOfBuckets];
+			}						    		
+    	}
+    }
+    
+    /**
+     * this is intended to initialise the newly created bucket arrays
+     * @param duration length of time each bucket represents 
+     */
+    public void initialiseBuckets(int duration){
+    	for (int i = 0; i < activityT.length; i++) {
+			//this is important for calculating the x values later, so use mid-bucket values
+    		activityT[i] = duration*i + duration / 2;
+		}
     }
     
-    // zero the samples of this profiled generic in the time range starting at the time stamp
-    public void zeroActivityMarkValues(int timeStamp)
-    {
-        addActivityMarkValues(timeStamp, 0, 0);
+    /**
+     * Updates the bucket percentage values. This requires that sample counts have
+     * already been calculated for each bucket.
+     * @param bucketTotalArr Total number of samples per bucket
+     * @param bucketTotalArrSMP total number of samples per cpu and bucket. May be null for non-SMP systems.
+     */
+    public void calculateBucketPercentages(int[] bucketTotalArr, int[][] bucketTotalArrSMP){
+    	if (activityN != null){ 
+        	for (int b = 0; b < activityN.length; b++) {//loop through sample counts per bucket
+        		if (bucketTotalArr[b] > 0){
+            		activityP[b] = (float)activityN[b]*100/bucketTotalArr[b];
+        			
+        		}
+        		
+        		activityIndx = activityP.length; //TODO: temporarily needed, remove later
+        		
+    			if (isSMP){
+    				for (int cpu = 0; cpu < bucketTotalArrSMP.length; cpu++) {
+    					if (bucketTotalArrSMP[cpu][b]>0){
+    						activityPSMP[cpu][b] = (float)activityNSMP[cpu][b]*100/bucketTotalArrSMP[cpu][b];
+    					}
+					}
+    			}
+    		}    		
+    	}	    		
     }
-
-    // set the samples of of this profiled generic in the time range starting at the time stamp
-    public void addActivityMarkValues(int timeStamp, int percentage, int sampleCount)
-    {
-      this.activityT[this.activityIndx] = timeStamp;
-      this.activityP[this.activityIndx] = percentage;
-
-      if (this.firstSample == -1 && percentage != 0)
-      {
-    	  this.firstSample = this.recentSample;
-      }
-
-   	  if (this.recentSampleCount > 0)
-   		  this.lastSample = timeStamp;
-
-      this.recentSample      = timeStamp;
-      this.recentSampleCount = sampleCount;
-      this.recentPercentage  = percentage;
-      this.activityIndx++;
-    }
-
-    public void addActivityMark(int timeStamp, int percentage)
-    {
-      this.activityT[this.activityIndx] = timeStamp;
-      this.activityP[this.activityIndx] = percentage;
-      this.activityIndx++;
+    
+    /**
+     * Increases total sample count as well as sample count for the given bucket. Takes care of SMP values
+     * if SMP trace.
+     * @param bucketIndex The index of the bucket to use
+     * @param timestamp the timestamp of the sample
+     * @param cpu the CPU number of the sample
+     */
+    public void increaseSampleCount(int bucketIndex, int timestamp, int cpu){
+    	//note, activityT (bucket times) is constant and has been set during initialisation
+    	//activityP (bucket percentages) will be calculated after all samples have been processed
+    	
+		incTotalSampleCount();
+		if (isSMP){
+			incTotalSampleCountForSMP(cpu);				
+		}
+		
+    	this.activityN[bucketIndex]++; //increase sample count in bucket
+    	if (firstSample == -1){
+    		firstSample = timestamp;
+    	}
+    	lastSample = timestamp;
+    	if (isSMP){
+    		this.activityNSMP[cpu][bucketIndex]++;
+    	}
     }
 
   	public void setupCumulativeList(int graphIndex)
   	{
-  		if (this.activityIndx != 0)
+  		if (this.activityT != null && activityT.length != 0)
   		{	
   			if (cumulativeList[graphIndex] == null)
-  				cumulativeList[graphIndex] = new int[this.activityIndx];
+  				cumulativeList[graphIndex] = new float[this.activityT.length];
   			else
   			{
   				for (int i = 0; i < cumulativeList[graphIndex].length; i++)
@@ -142,47 +266,77 @@
   		}
   	}
 
-  	public int[] getCumulativeList(int graphIndex)
+  	/**
+  	 * The cumulative list contains for each bucket the 
+  	 * cumulative sample percentage of the same bucket of all ProfiledGenerics
+  	 * so far processed (not including the values of the current ProfiledGeneric).
+  	 * 
+  	 * Typically used for drawing a stacked-area chart
+  	 * @param graphIndex the graph ordinal to use
+  	 * @return
+  	 */
+  	public float[] getCumulativeList(int graphIndex)
   	{
   		return this.cumulativeList[graphIndex];
   	}
 
-  	public void setCumulativeValue(int graphIndex, int index, int value)
+  	public void setCumulativeValue(int graphIndex, int index, float value)
   	{
   		this.cumulativeList[graphIndex][index] = value;
   	}
   	
-  	//returns x-coordinates
+  	/**
+  	 * returns x-coordinates
+  	 * @return
+  	 */
   	public int[] getSampleList()
   	{
-  		if (sampleList == null && this.activityIndx != 0)
-  		{
-  			sampleList = new int[this.activityIndx];
- 
-  			for (int i = 0; i < this.activityIndx; i++)
-  			{
-  				this.sampleList[i] = this.activityT[i];
-  			}
-  			this.activityT = null;
+  		if (activityT != null){
+  			//Arrays.copyOf() is only supported from Java 6
+  			//return Arrays.copyOf(this.activityT, this.activityT.length);
+  			int[] ret = new int[activityT.length];
+  			for (int i = 0; i < ret.length; i++) {
+				ret[i] = activityT[i];
+			}
+  			return ret;
   		}
-  		return this.sampleList;
+  		return null;
   	}
   	
-  	// returns y-coordinates
-  	public int[] getActivityList()
+  	/**
+  	 *  returns y-coordinates
+  	 * @return
+  	 */
+  	public float[] getActivityList(){
+  		if (activityP != null){
+  			//Arrays.copyOf() is only supported from Java 6
+  			//return Arrays.copyOf(this.activityP, this.activityP.length);
+  			float[] ret = new float[activityP.length];
+  			for (int i = 0; i < ret.length; i++) {
+				ret[i] = activityP[i];
+			}
+  			return ret;
+  		}
+  		return null;
+   	}
+  	
+  	/**
+  	 *  returns y-coordinates (percentage values of activity)
+  	 * @param cpu 
+  	 * @return
+  	 */
+  	public float[] getActivityListForSMP(int cpu)
   	{
-  		if (activityList == null && this.activityIndx != 0)
-  		{
-  			activityList = new int[this.activityIndx];
-
-  			for (int i = 0; i < this.activityIndx; i++)
-  			{
-  			  activityList[i] = this.activityP[i];
-  			}
-  			this.activityP = null;
+  		if (isSMP && this.activityPSMP[cpu] != null){
+  			//Arrays.copyOf() is only supported from Java 6
+  			//return Arrays.copyOf(activityPSMP[cpu], activityPSMP[cpu].length);
+  			float[] ret = new float[activityPSMP[cpu].length];
+  			for (int i = 0; i < ret.length; i++) {
+				ret[i] = activityPSMP[cpu][i];
+			}
+  			return ret;
   		}
-
-  		return this.activityList;
+  		return null;
   	}
 
     public int getFirstSample()
@@ -193,10 +347,6 @@
     	  return this.firstSample;
     }
 
-    public int getRealFirstSample()
-    {
-   	  return this.firstSample;
-    }
 
     public int getLastSample()
     {
@@ -215,130 +365,11 @@
     {
     	this.lastSample = lastSample;
     }
-
-    private int findNearestSampleIndexFromStart(int sampleNum)
-    {
-    	int i = 0;
-    	while (i < this.sampleList.length && this.sampleList[i] < sampleNum)
-    	{
-    		i++;
-    	}    
-    	return i;
-    }
-
-    private int findNearestSampleIndexFromEnd(int sampleNum)
-    {
-    	int i = sampleList.length - 1;
-    	while (this.sampleList[i] > sampleNum && i > 0)
-    	{
-    		i--;
-    	}
-    	return i;
-    }
-
-    public float getAverageLoad(double startTime, double endTime)
-    {
-        return getAverageLoad((int) startTime,(int) endTime);
-    }
     
-    public float getAverageLoad(int startSample,int endSample)
-    {
-    	if (startSample == -1 || endSample == -1) return -666;
-    	if (endSample < startSample) return -777;
-
-    	if (this.activityList == null || this.sampleList == null) return -888;
-
-    	int firstSampleIndx = 0;
-    	int lastSampleIndx = 0;
-
-    	firstSampleIndx = this.findNearestSampleIndexFromStart(startSample) + 1;
-    	lastSampleIndx  = this.findNearestSampleIndexFromEnd(endSample) + 1;
-   
-    	if (firstSampleIndx < 0)
-    		firstSampleIndx = 0;
-    	if (firstSampleIndx >= activityList.length)
-    		firstSampleIndx = activityList.length - 1;
-    	
-    	if (lastSampleIndx < 0)
-    		lastSampleIndx = 0;
-    	if (lastSampleIndx >= activityList.length)
-    		lastSampleIndx = activityList.length - 1;
-      
-    	if (firstSampleIndx > lastSampleIndx)
-    	{
-    		int temp = firstSampleIndx;
-    		firstSampleIndx = lastSampleIndx;
-    		lastSampleIndx = temp;
-    	}
-    	
-    	int totalTime = sampleList[lastSampleIndx - 1] - sampleList[firstSampleIndx - 1];
-    	int totalLoad = 0;
-    	
-    	for (int i = firstSampleIndx; i < lastSampleIndx; i++)
-    	{
-    		totalLoad += this.activityList[i];
-    	}
-     	
-    	totalLoad *= (sampleList[1] - sampleList[0]);
-
-    	if (totalTime == 0)
-    	{
-    		return 0;
-    	}
-    	else
-    	{
-    		return (float)(((float)totalLoad) / ((float)totalTime));
-    	}
-    }
-    
-    public int getTotalLoad(int startSample,int endSample)
-    {
-    	if (startSample == -1 || endSample == -1) return -666;
-    	if (endSample < startSample) return -777;
-
-    	if (this.activityList == null || this.sampleList == null) return -888;
-
-    	int firstSampleIndx = 0;
-    	int lastSampleIndx = 0;
-
-    	firstSampleIndx = this.findNearestSampleIndexFromStart(startSample) + 1;
-    	lastSampleIndx  = this.findNearestSampleIndexFromEnd(endSample) + 1;
-  
-    	if (firstSampleIndx < 0)
-    		firstSampleIndx = 0;
-    	if (firstSampleIndx >= activityList.length)
-    		firstSampleIndx = activityList.length - 1;
-    	
-    	if (lastSampleIndx < 0)
-    		lastSampleIndx = 0;
-    	if (lastSampleIndx >= activityList.length)
-    		lastSampleIndx = activityList.length - 1;
-      
-    	if (firstSampleIndx > lastSampleIndx)
-    	{
-    		int temp = firstSampleIndx;
-    		firstSampleIndx = lastSampleIndx;
-    		lastSampleIndx = temp;
-    	}
-    	
-    	int totalTime = sampleList[lastSampleIndx - 1] - sampleList[firstSampleIndx - 1];
-    	int totalLoad = 0;
-   	
-    	for (int i = firstSampleIndx; i < lastSampleIndx; i++)
-    	{
-    		totalLoad += this.activityList[i];
-    	}
-     	
-    	if (totalTime == 0)
-    	{
-    		return 0;
-    	}
-    	else
-    	{
-    		return (int) totalLoad;
-    	}
-    }
-    
+    /**
+     * Setter for this ordinal of this profiled element
+     * @param index the ordinal to set
+     */
     public void setIndex(int index)
     {
     	this.index = index;
@@ -354,51 +385,97 @@
     	this.averageLoadValueString[graphIndex] = (new DecimalFormat(Messages.getString("ProfiledGeneric.decimalFormat"))).format(value); //$NON-NLS-1$
     }
 
-    public void setAverageLoadValueString(int graphIndex)
-    {
-    	this.averageLoadValueString[graphIndex] = (new DecimalFormat(Messages.getString("ProfiledGeneric.decimalFormat"))).format(this.graphPercentLoad[graphIndex]); //$NON-NLS-1$
-    }
 
     public String getAverageLoadValueString(int graphIndex)
     {
     	return this.averageLoadValueString[graphIndex];
     }
 
+    /**
+     * Setter for this colour of this profiled element
+     * @param c the colour to set
+     */
     public void setColor(Color c)
     {
     	this.color = c;
     }
 
+    /**
+     * Sets enabled state for this profiled element in the given graph
+     * @param graphIndex the graph index to use
+     * @param enableValue true for enabled, false for disabled
+     */
     public void setEnabled(int graphIndex, boolean enableValue)
     {
     	this.enableValue[graphIndex] = enableValue;
     }
 
+    /**
+     * Checks enabled state for this profiled element in the given graph
+     * @param graphIndex the graph index to use
+     * @return true if enabled, false if disabled
+     */
     public boolean isEnabled(int graphIndex)
     {
     	return enableValue[graphIndex];
     }
 
+    /**
+     * @return the colour of this profiled element
+     */
     public Color getColor()
     {
     	return this.color;
     }
     
+    /**
+     * @return the name of this profiled element
+     */
     public String getNameString()
     {
     	return this.nameString;
     }
     
+    /**
+     * @return the total sample count of this profiled element over the entire trace data
+     */
     public int getTotalSampleCount()
     {
     	return this.totalSampleCount;
     }
     
-    public void incTotalSampleCount()
+    /**
+     * Increased the total sample count of this profiled element by one
+     */
+   public void incTotalSampleCount()
     {
     	this.totalSampleCount++;
     }
+    
+    /**
+     * returns the total sample count over the entire trace data for the given CPU
+     * @param cpu the CPU to use
+     * @return the total sample count for given CPU
+     */
+    public int getTotalSampleCountForSMP(int cpu)
+    {
+    	return this.totalSampleCountSMP[cpu];
+    }
+    
+    /**
+     * Increases the total sample count for the given CPU by one
+     * @param cpu the CPU to use
+     */
+    public void incTotalSampleCountForSMP(int cpu)
+    {
+    	this.totalSampleCountSMP[cpu]++;
+    }
 
+	/**
+	 * Getter for the given graph's sample count
+	 * @param graphIndex
+	 * @return
+	 */
 	public int getSampleCount(int graphIndex)
 	{
 		return this.graphSampleCount[graphIndex];
@@ -414,13 +491,6 @@
 		this.graphSampleCount[graphIndex]++;
 	}
 	
-	public void setSampleCounts(int sampleCount0, int sampleCount1, int sampleCount2)
-	{
-		this.graphSampleCount[0] = sampleCount0;
-		this.graphSampleCount[1] = sampleCount1;
-		this.graphSampleCount[2] = sampleCount2;
-	}
-	
 	public float getPercentLoad(int graphIndex)
 	{
 		return this.graphPercentLoad[graphIndex];
@@ -437,26 +507,6 @@
 		else
 			this.averageLoadValueString[graphIndex] = Messages.getString("ProfiledGeneric.zeroFormat"); //$NON-NLS-1$
 	}
+
 	
-	public void setPercentLoads(float percentLoad0, float percentLoad1, float percentLoad2)
-	{
-		this.graphPercentLoad[0] = percentLoad0;
-		this.graphPercentLoad[1] = percentLoad1;
-		this.graphPercentLoad[2] = percentLoad2;
-
-		// doesn't hurt to set the strings here, too
-		// you may not need to set the strings when you set the float
-		if (percentLoad0 >= 0.005f)
-			this.averageLoadValueString[0] = (new DecimalFormat(Messages.getString("ProfiledGeneric.decimalFormat"))).format(percentLoad0); //$NON-NLS-1$
-		else
-			this.averageLoadValueString[0] = Messages.getString("ProfiledGeneric.zeroFormat"); //$NON-NLS-1$
-		if (percentLoad1 >= 0.005f)
-			this.averageLoadValueString[1] = (new DecimalFormat(Messages.getString("ProfiledGeneric.decimalFormat"))).format(percentLoad1); //$NON-NLS-1$
-		else
-			this.averageLoadValueString[1] = Messages.getString("ProfiledGeneric.zeroFormat"); //$NON-NLS-1$
-		if (percentLoad2 >= 0.005f)
-			this.averageLoadValueString[2] = (new DecimalFormat(Messages.getString("ProfiledGeneric.decimalFormat"))).format(percentLoad2); //$NON-NLS-1$
-		else
-			this.averageLoadValueString[2] = Messages.getString("ProfiledGeneric.zeroFormat"); //$NON-NLS-1$
-	}
 }