sysperfana/analyzetoolext/com.nokia.s60tools.analyzetool/src/com/nokia/s60tools/analyzetool/engine/statistic/BaseInfo.java
changeset 6 f65f740e69f9
parent 1 1050670c6980
child 15 0367d2db2c06
--- a/sysperfana/analyzetoolext/com.nokia.s60tools.analyzetool/src/com/nokia/s60tools/analyzetool/engine/statistic/BaseInfo.java	Wed Apr 21 15:14:16 2010 +0300
+++ b/sysperfana/analyzetoolext/com.nokia.s60tools.analyzetool/src/com/nokia/s60tools/analyzetool/engine/statistic/BaseInfo.java	Wed Apr 21 19:42:48 2010 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (c) 2008-2010 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"
@@ -19,8 +19,9 @@
 
 import java.util.AbstractList;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Hashtable;
-import java.util.Iterator;
+import java.util.List;
 
 /**
  * Base class for {@link AllocInfo} and {@link FreeInfo}
@@ -29,62 +30,64 @@
  *
  */
 public class BaseInfo {
-
+	
+	private List<AllocCallstack> callstacks = null;
+	
 	/**
 	 * Cache for callstack items. Used when allocation fragment is parsed wrong
 	 * order.
 	 */
-	private final Hashtable<Integer, AbstractList<AllocCallstack>> callstackCache;
+	private Hashtable<Integer, AbstractList<AllocCallstack>> callstackCache = null;
 
 	/** Memory address of this memory allocation. */
-	private Long memoryAddress;
+	private long memoryAddress;
 
 	/** Memory allocation process id. */
 	private int processID;
 
 	/** Allocation time */
-	private Long time;
+	private long time;
 	
 	/** Total memory size at this time */
-	private int totalMemory = 0;
-	private int size = 0;
+	private int totalMemory;
+	private int size;
+	
+	/** file position to defer callstack reading */
+	private long filePos;
 
 	/**
 	 * Constructor
+	 * @param memoryAddress The address for this memory operation
 	 */
-	public BaseInfo() {
-		callstackCache = new Hashtable<Integer, AbstractList<AllocCallstack>>();
+	public BaseInfo(String memoryAddress) {
+		this.memoryAddress = Long.parseLong(memoryAddress, 16);
 	}
 
 	/**
-	 * Sets memory allocation callstack
+	 * Sets memory allocation callstack. Use this method
+	 * only for the first set of callstacks. 
 	 *
 	 * @param callstack
 	 *            Memory allocation callstack
 	 */
 	public void addCallstack(AbstractList<AllocCallstack> callstack) {
-		callstackCache.put(0, callstack);
+		if (callstack.size() > 0){
+			callstacks = new ArrayList<AllocCallstack>(callstack);						
+		}
 	}
 
 	/**
-	 * Returns memory allocation callstack.
-	 *
+	 * Returns memory allocation callstack. This method should only be called
+	 * after all data has finished loading.
+	 * 
 	 * @return Callstack of memory allocation
 	 */
-	public AbstractList<AllocCallstack> getCallstack() {
-		AbstractList<AllocCallstack> wholeCallstack = new ArrayList<AllocCallstack>();
-		int callstacksize = callstackCache.size();
-		for (int i = 0; i < callstacksize; i++) {
-			AbstractList<AllocCallstack> tempCallstack = callstackCache
-					.get(i);
-			if (tempCallstack == null || tempCallstack.isEmpty())
-				continue;
-			Iterator<AllocCallstack> iterCall = tempCallstack.iterator();
-			while (iterCall.hasNext()) {
-				wholeCallstack.add(iterCall.next());
-			}
-		}
-		return wholeCallstack;
+	public List<AllocCallstack> getCallstack() {
+		
+		//we assume all data has been loaded at this point
+		finaliseCallstack();
+		
+		return callstacks == null ? Collections.<AllocCallstack>emptyList() : Collections.unmodifiableList(callstacks);
 	}
 
 	/**
@@ -92,7 +95,7 @@
 	 *
 	 * @return Memory address
 	 */
-	public Long getMemoryAddress() {
+	public long getMemoryAddress() {
 		return memoryAddress;
 	}
 
@@ -110,20 +113,8 @@
 	 *
 	 * @return Allocation time
 	 */
-	public Long getTime() {
-		return time == null ? 0 : time;
-	}
-
-
-	/**
-	 * Sets memory address
-	 *
-	 * @param newMemoryAddress
-	 *            Memory address
-	 */
-	public void setMemoryAddress(String newMemoryAddress) {
-		Long lValue = Long.parseLong(newMemoryAddress, 16);
-		this.memoryAddress = lValue;
+	public long getTime() {
+		return time;
 	}
 
 	/**
@@ -144,11 +135,15 @@
 	 *            Allocation time
 	 */
 	public void setTime(String newTime) {
-		Long lValue = Long.parseLong(newTime, 16);
+		long lValue = Long.parseLong(newTime, 16);
 		this.time = lValue;
 	}
 	
-	public void setTime(Long newTime)
+	/**
+	 * Sets the timestamp of event occurrence
+	 * @param newTime
+	 */
+	public void setTime(long newTime)
 	{
 		this.time = newTime;
 	}
@@ -164,12 +159,47 @@
 	 */
 	public void updateFragment(AbstractList<AllocCallstack> callstack,
 			String packetNumber) {
-		callstackCache.put(Integer.parseInt(packetNumber, 16), callstack);
+		int pck = Integer.parseInt(packetNumber, 16);
+		if (pck == 1){
+			//special case; this can be added to the end of the list straight away
+			callstacks.addAll(callstack);
+		} else {
+			//packages may come out of order; this is managed in the callstackCache
+			if (callstackCache == null){
+				callstackCache = new Hashtable<Integer, AbstractList<AllocCallstack>>();			
+			}
+			callstackCache.put(pck, callstack);			
+		}
+	}
+	
+	/**
+	 * Optimises internal callstack data structures.
+	 * Should only be called after all data for this memory operation
+	 * has been loaded (i.e. all fragments)
+	 */
+	public void finaliseCallstack(){
+		if (callstacks == null && callstackCache != null){
+			throw new IllegalStateException(); //first set of callstacks should always be in callstacks
+		}
+		
+		if (callstackCache != null){
+			int size = callstackCache.size();
+			int i = 2;
+			while(size != 0){
+				AbstractList<AllocCallstack> nextCallStacks = callstackCache.get(i);
+				if (nextCallStacks != null){
+					size --;
+					callstacks.addAll(nextCallStacks);
+				} //TODO else: missing callstack: shall we report it or log it?
+				i++;
+			}
+			callstackCache = null;
+		}
 	}
 	
 	/**
 	 * set total memory used at this time.
-	 * @param size 
+	 * @param newSize 
 	 */
 	public void setTotalMem(int newSize) {
 		totalMemory = newSize;
@@ -183,11 +213,73 @@
 		return totalMemory;
 	}
 	
+	/**
+	 * Sets the number of bytes allocated or freed in this memory operation
+	 * @param aSize size in bytes
+	 */
 	public void setSizeInt(int aSize) {
 		size = aSize;
 	}
 	
+	/**
+	 * Gets the number of bytes allocated or freed in this memory operation
+	 * @return size in bytes
+	 */
 	public int getSizeInt() {
 		return size;
 	}
+
+	/**
+	 * Getter for file position pointing to first record in 
+	 * .dat file where callstack for this BaseInfo starts.
+	 * @return the file position for the start of callstack information,
+	 * or -1 if no callstack available for this BaseInfo
+	 */
+	public long getFilePos() {
+		return filePos;
+	}
+
+	/**
+	 * Setter for file position pointing to callstack information
+	 * @param filePos the file position pointing to start of record with callstack information;
+	 * or -1 if no callstack available for this BaseInfo
+	 */
+	public void setFilePos(long filePos) {
+		this.filePos = filePos;
+	}
+
+	@Override
+	public String toString() {
+		if (filePos > -1 && (callstacks == null || callstacks.size() == 0)){
+			return String.format(
+					"BaseInfo [memoryAddress=0x%08X, processID=%s, time=%s, size=%s, totalMemory=%s, callstacks on demand]",
+					memoryAddress, processID, time, size, totalMemory);  
+							
+		} else {
+			return String.format(
+					"BaseInfo [memoryAddress=0x%08X, processID=%s, time=%s, size=%s, totalMemory=%s, callstacks=%s]",
+					memoryAddress, processID, time, size, totalMemory,  
+					callstacksToString());
+			
+		}
+	}
+
+	private String callstacksToString() {
+		if (callstacks == null){
+			return "null";
+		}
+		
+		StringBuilder sb = new StringBuilder();
+		boolean addComma = false;
+		for (AllocCallstack callstack : callstacks) {
+			if (addComma){
+				sb.append(", ");
+			}
+			addComma = true;
+			sb.append(String.format("addr=0x%08X dll=%s", callstack.getMemoryAddress(), callstack.getDllLoad() == null ? "null" : callstack.getDllLoad().getName()));
+		}
+		return sb.toString();
+	}
+	
+	
 }