sysperfana/analyzetoolext/com.nokia.s60tools.analyzetool/src/com/nokia/s60tools/analyzetool/engine/CallstackDataParser.java
changeset 15 0367d2db2c06
parent 6 f65f740e69f9
--- a/sysperfana/analyzetoolext/com.nokia.s60tools.analyzetool/src/com/nokia/s60tools/analyzetool/engine/CallstackDataParser.java	Tue Aug 24 12:10:03 2010 +0300
+++ b/sysperfana/analyzetoolext/com.nokia.s60tools.analyzetool/src/com/nokia/s60tools/analyzetool/engine/CallstackDataParser.java	Tue Aug 24 12:16:27 2010 +0300
@@ -11,7 +11,7 @@
  *
  * Contributors:
  *
- * Description:  Definitions for the class ParseAnalyzeData
+ * Description:  Definitions for the class CallstackDataParser
  *
  */
 package com.nokia.s60tools.analyzetool.engine;
@@ -27,160 +27,194 @@
 import com.nokia.s60tools.analyzetool.engine.statistic.FreeInfo;
 import com.nokia.s60tools.analyzetool.engine.statistic.ProcessInfo;
 import com.nokia.s60tools.analyzetool.global.Constants;
+import com.nokia.s60tools.analyzetool.global.Util;
 import com.nokia.s60tools.analyzetool.global.Constants.Operation;
 
 /**
- * This class parses line of .dat file format and extracts
- * callstack data. For now this is a separate class but could
- * eventually be moved into ParseAnalyzeData after some refactoring. 
- *
+ * This class parses line of .dat file format and extracts callstack data. For
+ * now this is a separate class but could eventually be moved into
+ * ParseAnalyzeData after some re-factoring.
  */
 public class CallstackDataParser {
-	/** true if callstack reading for this BaseInfo is now complete*/
+
+	/** True, if callstack reading for this BaseInfo is now complete. */
 	boolean complete = false;
-	/** resulting callstack */
+
+	/** Resulting callstack. */
 	private List<AllocCallstack> callstack;
+
 	/** BaseInfo for the current alloc or free */
 	private BaseInfo baseInfo;
+
 	/** ProcessInfo for the current alloc or free */
 	private ProcessInfo process;
-	/** number of remaining callstack elements expected to be processed with ALLOCF or FREEF */
+
+	/**
+	 * Number of remaining callstack elements expected to be processed with ALF
+	 * or FRF.
+	 */
 	private int remainingSize;
-	
-	/** Cache for callstack items. Used when allocation fragment is parsed in the wrong order. */
-	private HashMap<Integer, List<AllocCallstack>> callstackCache = null;
-	
+
 	/**
-	 * Constructor
-	 * @param baseInfo BaseInfo for the current alloc or free
-	 * @param p ProcessInfo for the current alloc or free
+	 * Cache for callstack items. Used when allocation fragment is parsed in the
+	 * wrong order.
 	 */
-	public CallstackDataParser(BaseInfo baseInfo, ProcessInfo p) {
-		if (p == null || baseInfo == null || p.getProcessID() != baseInfo.getProcessID()){
-			throw new IllegalArgumentException("BaseInfo and ProcessInfo are mandatory and must not be null; and the process id of both must match."); //$NON-NLS-1$
+	private HashMap<Integer, List<AllocCallstack>> callstackCache = null;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param baseInfo
+	 *            BaseInfo for the current alloc or free
+	 * @param processInfo
+	 *            ProcessInfo for the current alloc or free
+	 */
+	public CallstackDataParser(BaseInfo baseInfo, ProcessInfo processInfo) {
+		if (processInfo == null || baseInfo == null
+				|| processInfo.getProcessID() != baseInfo.getProcessID()) {
+			throw new IllegalArgumentException(
+					"BaseInfo and ProcessInfo are mandatory and must not be null; and the process ID of both must match."); //$NON-NLS-1$
 		}
 		this.baseInfo = baseInfo;
-		this.process = p;
+		this.process = processInfo;
 		callstack = new ArrayList<AllocCallstack>();
 	}
 
 	/**
-	 * Parses one line of PCSS statement
+	 * Parses one line of &ltAT&gt statement.
+	 * 
 	 * @param aLine
 	 * @return true, if this callstack is now complete (all parts are available)
 	 */
 	public final boolean parseLine(final String aLine) {
-			
-		if (aLine.indexOf(Constants.PREFIX) == -1){
-			//not a PCSS statement
+
+		if (aLine.indexOf(Constants.PREFIX) == -1) {
+			// not a <AT> statement
 			return false;
 		}
-		
-		String[] lineFragments = getLineFragments(aLine);
-		if (lineFragments.length < 5){
-			//not a valid PCSS statment for callstack processing
+
+		// String[] lineFragments = getLineFragments(aLine);
+
+		int index = aLine.indexOf(Constants.PREFIX);
+
+		String time = aLine.substring(0, index).trim();
+
+		// // get logging time of line in microseconds
+		// long logTime = Util.getLogTime(time);
+
+		long logTime = Long.parseLong(time, 16);
+
+		String usedString = aLine.substring(index, aLine.length());
+
+		String[] lineFragments = usedString.split(" ");
+
+		if (lineFragments.length < 5) {
+			// not a valid <AT> statement for callstack processing
 			return false;
 		}
 		int processID = Integer.parseInt(lineFragments[1], 16);
-		if (baseInfo.getProcessID() != processID || process.getProcessID() != processID){
-			//statement is not for current process id
+		if (baseInfo.getProcessID() != processID
+				|| process.getProcessID() != processID) {
+			// statement is not for current process id
 			return false;
 		}
-		
-		//the operation must match
-		Constants.Operation op = Constants.Operation.toOperation(lineFragments[2]);
-		if (!verifyOperation(op, baseInfo)){
-			return false;
-		}
-		
-		//the memory address must match
-		long memoryAddress = Long.parseLong(lineFragments[3],16);
-		if (baseInfo.getMemoryAddress() != memoryAddress){
+
+		// the operation must match
+		Constants.Operation op = Constants.Operation
+				.toOperation(lineFragments[2]);
+		if (!verifyOperation(op, baseInfo)) {
 			return false;
 		}
-		
-		
+
+		// the memory address must match
+		long memoryAddress = Long.parseLong(lineFragments[3], 16);
+		if (baseInfo.getMemoryAddress() != memoryAddress) {
+			return false;
+		}
+
 		boolean ret = false;
-		
+
 		switch (op) {
-		case ALLOC:
-			ret = parseAlloc(lineFragments);
-			break;
-		case ALLOCH:
+		case ALH:
 			ret = parseHeader(lineFragments, 6);
 			break;
-		case FREEH:
-			int traceFileVersion = process.getTraceDataVersion();
-			ret = parseHeader(lineFragments, traceFileVersion > 1 ? 5 : 4);
+		case FRH:
+			ret = parseHeader(lineFragments, 5);
 			break;
-		case ALLOCF:
-			//fall through
-		case FREEF:
-			ret = parseFragment(lineFragments);				
+		case ALF:
+			// fall through
+		case FRF:
+			ret = parseFragment(lineFragments, logTime);
 			break;
 		default:
 			// ignore this line
 			break;
 		}
-		
 		return ret;
 	}
-	
+
 	private static boolean verifyOperation(Operation op, BaseInfo aBaseInfo) {
-		return ((aBaseInfo instanceof AllocInfo && (op == Constants.Operation.ALLOC
-				|| op == Constants.Operation.ALLOCH || op == Constants.Operation.ALLOCF)) 
-				|| (aBaseInfo instanceof FreeInfo && (op == Constants.Operation.FREEH 
-				|| op == Constants.Operation.FREEF)));
+		return ((aBaseInfo instanceof AllocInfo && (op == Constants.Operation.ALH || op == Constants.Operation.ALF)) || (aBaseInfo instanceof FreeInfo && (op == Constants.Operation.FRH || op == Constants.Operation.FRF)));
 	}
 
+	// /**
+	// * Returns the line fragments of the AT statement
+	// *
+	// * @param aLine
+	// * the AT statement
+	// * @return the line fragments separated by space
+	// */
+	// private String[] getLineFragments(final String aLine) {
+	// int index = aLine.indexOf(Constants.PREFIX); // lines should be preceded
+	//
+	// if (index == -1) {
+	// return new String[0];
+	// }
+	//
+	// String usedString = (index == 0) ? aLine : aLine.substring(index, aLine
+	// .length());
+	//		return usedString.split(" "); //$NON-NLS-1$
+	// }
+
+	// /**
+	// * Parses an ALC statement. This statement contains a complete callstack.
+	// *
+	// * @param fragments
+	// * the line fragments of the statement to process
+	// * @return true if statement is complete (this method will always return
+	// * true)
+	// */
+	// private boolean parseAlloc(String[] fragments) {
+	//
+	// if (fragments.length > 5) {
+	// createCallstack(fragments, process, callstack, 6);
+	// }
+	//
+	// complete = true;
+	// return true; // we are done; there are no fragments for this alloc
+	// }
+
 	/**
-	 * Returns the line fragments of the PCSS statement
-	 * @param aLine the PCSS statement
-	 * @return the line fragments separated by space
-	 */
-	private String[] getLineFragments(final String aLine){
-		int index = aLine.indexOf(Constants.PREFIX); // lines should be preceded
-		
-		if (index == -1){
-			return new String[0];
-		}
-		
-		String usedString = (index == 0) ? aLine : aLine.substring(index, aLine.length());
-		return usedString.split(" "); //$NON-NLS-1$
-	}
-	
-	/**
-	 * Parses an ALLOC statement. This statement contains a complete callstack.
-	 * @param fragments the line fragments of the statement to process
-	 * @return true if statement is complete (this method will always return true)
-	 */
-	private boolean parseAlloc(String[] fragments) {
-		
-		if (fragments.length > 5) {
-			createCallstack(fragments, process, callstack, 6);
-		}
-		
-		complete = true;
-		return true; //we are done; there are no fragments for this alloc
-	}
-	
-	/**
-	 * Parses an ALLOCH or FREEH statement
-	 * @param fragments the line fragments of the statement to process
-	 * @param startIndex index at which the callstack size is to be found
-	 * @return true if callstack is complete, false if callstack fragment is expected
+	 * Parses an ALH or FRH statement
+	 * 
+	 * @param fragments
+	 *            the line fragments of the statement to process
+	 * @param startIndex
+	 *            index at which the callstack size is to be found
+	 * @return true if callstack is complete, false if callstack fragment is
+	 *         expected
 	 */
 	private boolean parseHeader(String[] fragments, int startIndex) {
-		
+
 		if (callstack.size() > 0 || remainingSize > 0) {
 			throw new IllegalStateException(
-					"Callstack list should still be empty when starting to process ALLOCH"); //$NON-NLS-1$
+					"Callstack list should still be empty when starting to process ALH or FRH"); //$NON-NLS-1$
 		}
 
 		if (fragments.length > startIndex) {
 
 			int callstackSize = Integer.parseInt(fragments[startIndex], 16);
-			startIndex ++;
+			startIndex++;
 
 			createCallstack(fragments, process, callstack, startIndex);
 
@@ -192,34 +226,37 @@
 				complete = true;
 			}
 		} else {
-			complete = true; // this header doesn't have callstacks - a bit strange
+			complete = true; // this header doesn't have callstacks - a bit
+			// strange
 		}
 		return complete;
 	}
-	
+
 	/**
-	 * Parses an ALLOCF or FREEF callstack fragment
-	 * @param fragments the line fragments of the statement to process
+	 * Parses an ALF or FRF callstack fragment
+	 * 
+	 * @param fragments
+	 *            the line fragments of the statement to process
 	 * @return true if callstack is now complete; false otherwise
 	 */
-	private boolean parseFragment(String[] fragments) {
-		long time = Long.parseLong(fragments[4],16);
-		int packetNumber = Integer.parseInt(fragments[5], 16);
-	
+	private boolean parseFragment(String[] fragments, long logTime) {
+		long time = process.getStartTime() + (logTime - process.getLogTime());
+		int packetNumber = Integer.parseInt(fragments[4], 16);
+
 		if (baseInfo.getTime() == time) {
 			List<AllocCallstack> tmpCallstack = new ArrayList<AllocCallstack>();
-			createCallstack(fragments, process, tmpCallstack, 6);
+			createCallstack(fragments, process, tmpCallstack, 5);
 			updateFragment(tmpCallstack, packetNumber);
-			
+
 			remainingSize -= tmpCallstack.size();
-			if (remainingSize <= 0){
+			if (remainingSize <= 0) {
 				complete = true;
 				finaliseCallstack();
 			}
 		}
 		return complete;
 	}
-	
+
 	private DllLoad getDllForAddress(ProcessInfo p, Long memoryAddress,
 			long time) {
 		for (DllLoad oneLoad : p.getDllLoads()) {
@@ -233,22 +270,26 @@
 		}
 		return null;
 	}
-	private void createCallstack(String[] fragments, ProcessInfo p, List<AllocCallstack> callstack, int startIndex) {
+
+	private void createCallstack(String[] fragments, ProcessInfo p,
+			List<AllocCallstack> callstack, int startIndex) {
 		for (int i = startIndex; i < fragments.length; i++) {
 			AllocCallstack callstackElem = new AllocCallstack(fragments[i]);
 
 			// find matching dll
-			DllLoad dllLoad = getDllForAddress(process, callstackElem.getMemoryAddress(), baseInfo.getTime());
+			DllLoad dllLoad = getDllForAddress(process, callstackElem
+					.getMemoryAddress(), baseInfo.getTime());
 			if (dllLoad != null) {
 				callstackElem.setDllLoad(dllLoad);
 			}
 			callstack.add(callstackElem);
 		}
 	}
+
 	/**
 	 * Updates allocation fragment. Means that given callstack is addition to
 	 * previous added alloc
-	 *
+	 * 
 	 * @param callstack
 	 *            Addition tmpcallstack items
 	 * @param packetNumber
@@ -256,69 +297,74 @@
 	 */
 	private void updateFragment(List<AllocCallstack> tmpcallstack,
 			int packetNumber) {
-		if (packetNumber == 1){
-			//special case; this can be added to the end of the list straight away
+		if (packetNumber == 1) {
+			// special case; this can be added to the end of the list straight
+			// away
 			callstack.addAll(tmpcallstack);
 		} else {
-			//packages may come out of order; this is managed in the callstackCache
-			if (callstackCache == null){
-				callstackCache = new HashMap<Integer, List<AllocCallstack>>();			
+			// packages may come out of order; this is managed in the
+			// callstackCache
+			if (callstackCache == null) {
+				callstackCache = new HashMap<Integer, List<AllocCallstack>>();
 			}
-			callstackCache.put(packetNumber, tmpcallstack);			
+			callstackCache.put(packetNumber, tmpcallstack);
 		}
 	}
+
 	/**
-	 * Optimises internal callstack data structures.
-	 * Should only be called after all data for this memory operation
-	 * has been loaded (i.e. all fragments)
+	 * 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 (callstackCache == null){
-			//nothing to do
+	public void finaliseCallstack() {
+		if (callstackCache == null) {
+			// nothing to do
 			return;
 		}
-		
-		if (!complete){
-			throw new IllegalStateException("callstack processing is not yet complete."); //$NON-NLS-1$
+
+		if (!complete) {
+			throw new IllegalStateException(
+					"callstack processing is not yet complete."); //$NON-NLS-1$
 		}
-			
-		if (callstack == null && callstackCache != null){
-			throw new IllegalStateException(); //first set of callstacks should always be in callstacks
+
+		if (callstack == null && callstackCache != null) {
+			throw new IllegalStateException(); // first set of callstacks should
+			// always be in callstacks
 		}
-		
-		if (callstackCache != null){
+
+		if (callstackCache != null) {
 			int size = callstackCache.size();
 			int i = 2;
-			while(size != 0){
+			while (size != 0) {
 				List<AllocCallstack> nextCallStacks = callstackCache.get(i);
-				if (nextCallStacks != null){
-					size --;
+				if (nextCallStacks != null) {
+					size--;
 					callstack.addAll(nextCallStacks);
-				} //TODO else: missing callstack: shall we report it or log it?
+				} // TODO else: missing callstack: shall we report it or log it?
 				i++;
 			}
 			callstackCache = null;
 		}
 	}
-	
+
 	/**
 	 * @return the completed callstack.
 	 */
-	public List<AllocCallstack> getCallstack(){
-		if (!complete){
-			throw new IllegalStateException("Callstack has not been completely processed."); //$NON-NLS-1$
+	public List<AllocCallstack> getCallstack() {
+		if (!complete) {
+			throw new IllegalStateException(
+					"Callstack has not been completely processed."); //$NON-NLS-1$
 		}
-		
+
 		finaliseCallstack();
 		return callstack;
 	}
-	
+
 	/**
-	 * Forces the callstack state to be set to complete. This should only be used when the end of file is encountered.
+	 * Forces the callstack state to be set to complete. This should only be
+	 * used when the end of file is encountered.
 	 */
-	public void forceComplete(){
+	public void forceComplete() {
 		complete = true;
 		finaliseCallstack();
 	}
-	
 }