sysperfana/analyzetoolext/com.nokia.s60tools.analyzetool/src/com/nokia/s60tools/analyzetool/engine/ParseAnalyzeData.java
changeset 6 f65f740e69f9
parent 1 1050670c6980
child 15 0367d2db2c06
--- a/sysperfana/analyzetoolext/com.nokia.s60tools.analyzetool/src/com/nokia/s60tools/analyzetool/engine/ParseAnalyzeData.java	Wed Apr 21 15:14:16 2010 +0300
+++ b/sysperfana/analyzetoolext/com.nokia.s60tools.analyzetool/src/com/nokia/s60tools/analyzetool/engine/ParseAnalyzeData.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"
@@ -23,22 +23,26 @@
 import java.io.IOException;
 import java.util.AbstractList;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
 
 import org.eclipse.core.runtime.IStatus;
 
 import com.nokia.s60tools.analyzetool.Activator;
 import com.nokia.s60tools.analyzetool.engine.statistic.AllocCallstack;
 import com.nokia.s60tools.analyzetool.engine.statistic.AllocInfo;
+import com.nokia.s60tools.analyzetool.engine.statistic.BaseInfo;
 import com.nokia.s60tools.analyzetool.engine.statistic.DllLoad;
 import com.nokia.s60tools.analyzetool.engine.statistic.FreeInfo;
 import com.nokia.s60tools.analyzetool.engine.statistic.ProcessInfo;
 import com.nokia.s60tools.analyzetool.global.Constants;
 
 /**
- * Parses trace messages which comes thru tracing utility.
- * If one message contains PCSS prefix the message will saved to the data file Data file will be saved
+ * Parses trace messages which comes thru TraceViewer.
+ * If one message contains PCSS prefix the message will be saved to the data file. Data file will be saved
  * to the project [bld.inf location]\atool_temp folder.
  *
  * @author kihe
@@ -74,25 +78,33 @@
 
 	/**
 	 * Allocation cache
-	 * Used when one free info is separated to multiple lines.
+	 * Used when one alloc info is separated to multiple lines.
 	 */
-	private final Hashtable<Long, AllocInfo> allocCache;
+	private Hashtable<Long, AllocInfo> allocCache = null;
+	
+	/**
+	 * For each memory operation, keeps count of how many 
+	 * callstacks are outstanding. This is used to clean up 
+	 * after all fragments have been processed.
+	 * 
+	 * Zero callstack counts should not be kept.
+	 */
+	private Map<BaseInfo, Integer> remainingCallstacksMap = null;
 
 
 	/**
 	 * Deallocation cache.
 	 * Used when one free info is separated to multiple lines.
 	 */
-	private final Hashtable<Long, FreeInfo> freeCache;
-
-
+	private Hashtable<Long, FreeInfo> freeCache = null;
+	
 	/**
 	 * Cache for dll loads.
 	 * We must find dll load item for every allocation callstack item.
 	 * This is heavy process and usually we must find more than thousand times.
 	 * So when using cache for found items => it makes finding process more rapid than without it.
 	 */
-	private final Hashtable<Long, DllLoad> dllLoadCache;
+	private Hashtable<Long, DllLoad> dllLoadCache = null;
 
 
 	/**
@@ -103,23 +115,78 @@
 	boolean saveDataToFile;
 
 	boolean createGraphModel;
+	
+	/** When set to true, ignore any callstack information. Can be used decrease memory consumption of the model */
+	boolean ignoreCallstacks;
+	
+	/** Callstacks will be read later on demand directly from file */
+	private boolean deferCallstacks;
+	/** file position showing current write position, this is saved in BaseInfo for deferred callstack reading */
+	private long filePos;
+	
+	long lastTime = 0;
+	private int lineBreakSize;
+	
+	
 	/**
 	 * Constructor.
-	 * @param saveData Need to save data to file.
+	 * 
+	 * @param saveData
+	 *            if true, save PCSS statements to file. Typical use case is for
+	 *            TraceWrapper
+	 * @param createModel
+	 *            boolean indicating whether to create a graph model. Used to
+	 *            improve performance.
+	 * @param deferCallstackReading
+	 *            true, if callstack reading is to be done later. This requires
+	 *            saving the file position during parse phase, so saveData must
+	 *            be true or use constructor with FileChannel.
 	 */
-	public ParseAnalyzeData(boolean saveData, boolean createModel) {
+	public ParseAnalyzeData(boolean saveData, boolean createModel, boolean deferCallstackReading) {
+		this(saveData, createModel, deferCallstackReading, 0);
+	}	
+	
+	/**
+	 * Constructor. Use this constructor when working with deferred callstacks and not
+	 * saving an output file.
+	 * 
+	 * @param saveData
+	 *            if true, save PCSS statements to file. Typical use case is for
+	 *            TraceWrapper
+	 * @param createModel
+	 *            boolean indicating whether to create a graph model. Used to
+	 *            improve performance.
+	 * @param deferCallstackReading
+	 *            true, if callstack reading is to be done later. This requires
+	 *            saving the file position during parse phase, so saveData must
+	 *            be true or use constructor with FileChannel.
+	 * @param lineBreakSize
+	 *            Size of line break, usually 1 for device-side file, and 2 for host-side file
+	 */
+	public ParseAnalyzeData(boolean saveData, boolean createModel, boolean deferCallstackReading, int lineBreakSize) {
+		
+		if (deferCallstackReading && !saveData && lineBreakSize == 0){
+			throw new IllegalArgumentException("linebreak size must be specified when trying to use deferred callstack reading with a .dat input file ");
+		}
 
 		processStart = new Hashtable<String, Integer>();
 		processEnd = new ArrayList<Integer>();
 		processes = new Hashtable<Integer, ProcessInfo>();
 		processList = new ArrayList<ProcessInfo>();
-		allocCache = new Hashtable<Long, AllocInfo>();
 		saveDataToFile = saveData;
-		dllLoadCache = new Hashtable<Long, DllLoad>();
-		freeCache = new Hashtable<Long, FreeInfo>();
+		deferCallstacks = deferCallstackReading; //orig data input might be streamed through TraceWrapper
 		createGraphModel = createModel;
+		ignoreCallstacks = !createGraphModel ; 
+		if (!ignoreCallstacks && !deferCallstacks){
+			allocCache = new Hashtable<Long, AllocInfo>();
+			freeCache = new Hashtable<Long, FreeInfo>();
+			remainingCallstacksMap = new HashMap<BaseInfo, Integer>();
+			dllLoadCache = new Hashtable<Long, DllLoad>();
+		}
+		filePos = deferCallstacks ? 0 : -1;//set to beginning of file if applicable
+		this.lineBreakSize = lineBreakSize;
 	}
-
+	
 	/**
 	 * Add one dllLoad object to process related list
 	 *
@@ -177,6 +244,7 @@
 				// clear file and fis
 				file = null;
 				fis = null;
+				filePos = 0;
 			}
 		} catch (IOException ioe) {
 			ioe.printStackTrace();
@@ -207,9 +275,18 @@
 		processes.clear();
 		processStart.clear();
 		processEnd.clear();
-		allocCache.clear();
-		freeCache.clear();
-		dllLoadCache.clear();
+		if (allocCache != null){
+			allocCache.clear();			
+		}
+		if (freeCache != null){
+			freeCache.clear();
+		}
+		if (dllLoadCache != null){
+			dllLoadCache.clear();			
+		}
+		if (remainingCallstacksMap != null){
+			remainingCallstacksMap.clear();
+		}
 	}
 
 	/**
@@ -322,6 +399,7 @@
 	 *
 	 * @param data
 	 *            File name to be used
+	 * @return true on success
 	 */
 	public final boolean parse(final String data) {
 
@@ -333,6 +411,8 @@
 				//some unexpected error occurs
 				return true;
 			}
+			
+			
 
 			// if data must be saved to project group\atool_temp folder
 			if(saveDataToFile) {
@@ -346,6 +426,10 @@
 			if (contains) {
 				writeDataToFile(data);
 			}
+
+			if (deferCallstacks && !saveDataToFile){
+				filePos += (data.length()+lineBreakSize);
+			}
 			return true;
 		}catch(OutOfMemoryError oome) {
 			return false;
@@ -374,10 +458,13 @@
 			//thats why we must check which version is used.
 			if( processInfo.getTraceDataVersion() > 1 && splittedText.length > 6 ) {
 				dllLoad.setLoadTime(splittedText[4]);
+				lastTime = dllLoad.getLoadTime();
 				dllLoad.setStartAddress(splittedText[5]);
 				dllLoad.setEndAddress(splittedText[6]);
 			}
 			else {
+				//load time note present - assume last available time (typically from an alloc or process start)
+				dllLoad.setLoadTime(lastTime);
 				dllLoad.setStartAddress(splittedText[4]);
 				dllLoad.setEndAddress(splittedText[5]);
 			}
@@ -398,9 +485,9 @@
 		// which is forth item of trace data
 		if( splitted.length > 3 ) {
 			String processID = splitted[1];
-			FreeInfo freeInfo = new FreeInfo();
+			FreeInfo freeInfo = new FreeInfo(splitted[3]);
 			freeInfo.setProcessID(processID);
-			freeInfo.setMemoryAddress(splitted[3]);
+			freeInfo.setFilePos(-1);//a free doesn't have a callstack
 			removeMemAddress(freeInfo);
 		}
 	}
@@ -408,15 +495,14 @@
 
 	/**
 	 * Parse dealloction header from the line
-	 * @param line Allocation header line
+	 * @param splitted Split trace message
 	 */
 	private void parseFreeHeader(String[] splitted) {
 		//get free line info
 		String processID = splitted[1];
-		FreeInfo freeInfo = new FreeInfo();
+		FreeInfo freeInfo = new FreeInfo(splitted[3]);
 		freeInfo.setProcessID(processID);
-
-		freeInfo.setMemoryAddress(splitted[3]);
+		freeInfo.setFilePos(splitted.length > 6 ? filePos : -1);
 		
 		if( createGraphModel ) {
 		
@@ -426,7 +512,7 @@
 				ProcessInfo processInfo = processes.get(freeInfo.getProcessID());
 				traceFileVersion = processInfo.getTraceDataVersion();
 			}
-			// how many callstakc items
+			// how many callstack items
 			int callstackCount = 0;
 
 			// index where the callstack addresses begins
@@ -435,22 +521,27 @@
 			//if using the new trace file format
 			if( traceFileVersion > 1 ) {
 				freeInfo.setTime(splitted[4]);
+				lastTime = freeInfo.getTime();
 				callstackCount = Integer.parseInt(splitted[5], 16);
 				startIndex = 6;
 			}
 			else {
-				callstackCount = Integer.parseInt(splitted[5], 16);
+				callstackCount = Integer.parseInt(splitted[4], 16);
 			}
 
-			AbstractList<AllocCallstack> callstack = new ArrayList<AllocCallstack>();
-			createCallstack(splitted, freeInfo.getProcessID(), callstack, startIndex);
-			freeInfo.addCallstack(callstack);
-			
-			//if this free item contains fragments
-			//so we must store this info to cache
-			//and rest of the callstack items later
-			if( callstackCount > (splitted.length-startIndex) ) {
-				freeCache.put(freeInfo.getMemoryAddress(), freeInfo);
+			if (!ignoreCallstacks && !deferCallstacks){
+				AbstractList<AllocCallstack> callstack = new ArrayList<AllocCallstack>();
+				createCallstack(splitted, freeInfo.getProcessID(), callstack, startIndex, lastTime);
+				freeInfo.addCallstack(callstack);
+				
+				//if this free item contains fragments
+				//so we must store this info to cache
+				//and rest of the callstack items later
+				if( callstackCount > (splitted.length-startIndex) ) {
+					freeCache.put(freeInfo.getMemoryAddress(), freeInfo);
+					//expect fragments
+					remainingCallstacksMap.put(freeInfo, callstackCount - callstack.size());
+				}				
 			}
 		}
 		
@@ -462,7 +553,7 @@
 
 	/**
 	 * Parse dealloction fragment from the line
-	 * @param line Allocation fragment line
+	 * @param splitted Split trace message
 	 */
 	private void parseFreeFragment(String[] splitted)
 	{
@@ -473,6 +564,7 @@
 				String memAddr = splitted[3];
 				Long memoryAddress =Long.parseLong(memAddr, 16);
 				Long time = Long.parseLong(splitted[4],16);
+				lastTime = time;
 				String packetNumber = splitted[5];
 
 				//if cache contains corresponding free info
@@ -480,44 +572,75 @@
 					FreeInfo info = freeCache.get(memoryAddress);
 					if (info.getMemoryAddress() == memoryAddress && info.getTime() == time ) {
 						AbstractList<AllocCallstack> callstack = new ArrayList<AllocCallstack>();
-						createCallstack(splitted, processId, callstack, 6);
+						createCallstack(splitted, processId, callstack, 6, time);
 						info.updateFragment(callstack, packetNumber);
+
+						int callstackCount = callstack.size();
+						int remaining = remainingCallstacksMap.get(info);
+						remaining -= callstackCount;
+						if (remaining <= 0){
+							remainingCallstacksMap.remove(info);
+							freeCache.remove(info);
+							info.finaliseCallstack();
+						} else {
+							remainingCallstacksMap.put(info, remaining);
+						}
 					}
+					
 				}
 			}
 		}
 	}
 	
 	/**
-	 * Remove dll load from the list.
+	 * Mark dll as unloaded
 	 * This provides functionality for dynamically loaded dll loads
-	 * @param dllLoad DllLoad item to unload
+	 * @param lineFragments elements of text to parse for unloading dll
 	 */
-	private void unloadDll( DllLoad dllLoad )
+	private void unloadDll(String[] lineFragments)
 	{
-		if (processes.containsKey(dllLoad.getProcessID())) {
-			ProcessInfo tempProcessInfo = processes.get(dllLoad.getProcessID());
-			tempProcessInfo.unloadOneDll(dllLoad);
+		int processID = Integer.parseInt(lineFragments[1], 16);
+		
+		if(processes.containsKey(processID)) {
+			ProcessInfo processInfo = processes.get(processID);
+			String dllName = lineFragments[3];
 
+			//timestamp only exists for more recent trace versions
+			long dllUnloadTime;
+			long startAddr;
+			long endAddr;
+			
+			if( processInfo.getTraceDataVersion() > 1 && lineFragments.length > 6 ) {
+				dllUnloadTime = Long.parseLong(lineFragments[4], 16);
+				lastTime = dllUnloadTime;
+				startAddr = Long.parseLong(lineFragments[5], 16);
+				endAddr = Long.parseLong(lineFragments[6], 16);
+			}
+			else {
+				//load time note present - assume last available time (typically from an alloc or process start)
+				dllUnloadTime = lastTime;
+				startAddr = Long.parseLong(lineFragments[4], 16);
+				endAddr = Long.parseLong(lineFragments[5], 16);
+			}
+			
+			ProcessInfo p = processes.get(processID);
+			DllLoad dll = p.unloadOneDll(dllName, startAddr, endAddr, dllUnloadTime);
+			
 			//remove found dll load item from cache
-			for( java.util.Enumeration<Long> e = dllLoadCache.keys(); e.hasMoreElements();)
-			{
-				Long key = e.nextElement();
-				DllLoad tempDllLoad = dllLoadCache.get(key);
-
-				// if values equals remove it from the list
-				if (tempDllLoad.getProcessID() == dllLoad.getProcessID() && tempDllLoad.getStartAddress() == dllLoad.getStartAddress()
-						&& tempDllLoad.getEndAddress() == dllLoad.getEndAddress() && tempDllLoad.getName() == tempDllLoad.getName()) {
-					dllLoadCache.remove(key);
+			if (!ignoreCallstacks && !deferCallstacks && dll != null){
+				for (Entry<Long, DllLoad> entry : dllLoadCache.entrySet()) {
+					if (entry.getValue().equals(dll)){
+						dllLoadCache.remove(entry.getKey());
+						System.out.println("dllLoadCache.removedEntry for"+dll.getName());
+					}
 				}
 			}
-
 		}
 	}
 
 	/**
 	 * Parse allocation header info from the line
-	 * @param line Allocation line
+	 * @param splitted Split trace message
 	 */
 	private void parseAllocHeader(String[] splitted)
 	{
@@ -525,20 +648,29 @@
 			String procID = splitted[1];
 			int processID = Integer.parseInt(procID, 16);
 			if (processes.containsKey(processID)) {
-				AllocInfo oneAlloc = new AllocInfo();
+				AllocInfo oneAlloc = new AllocInfo(splitted[3]);
 				oneAlloc.setProcessID(procID);
-				oneAlloc.setMemoryAddress(splitted[3]);
+				oneAlloc.setFilePos(splitted.length > 6 ? filePos : -1);
 				if( createGraphModel ) {
 					oneAlloc.setTime(splitted[4]);
+					lastTime = oneAlloc.getTime();
 					
 					oneAlloc.setSizeInt(Integer.parseInt(splitted[5], 16));
 					// if one trace message contains callstack
-					if (splitted.length > 6) {
+					if (!ignoreCallstacks && !deferCallstacks && splitted.length > 6) {
+						
+						int callstackSize = Integer.parseInt(splitted[6], 16);
 
 						AbstractList<AllocCallstack> callstack = new ArrayList<AllocCallstack>();
-						createCallstack(splitted, processID, callstack, 7);
+						createCallstack(splitted, processID, callstack, 7, oneAlloc.getTime());
 						oneAlloc.addCallstack(callstack);
-						allocCache.put(oneAlloc.getMemoryAddress(), oneAlloc);
+						
+						callstackSize -= callstack.size();
+						if (callstackSize > 0){
+							//expect fragments
+							remainingCallstacksMap.put(oneAlloc, callstackSize);
+							allocCache.put(oneAlloc.getMemoryAddress(), oneAlloc);
+						}
 					}
 				}
 				addMemAddress(oneAlloc);
@@ -552,8 +684,7 @@
 	/**
 	 * Parse allocation fragment from the line
 	 * 
-	 * @param line
-	 *            Allocation fragment line
+	 * @param splitted Split trace message
 	 */
 	private void parseAllocFragment(String[] splitted) {
 		if( createGraphModel ) {
@@ -561,16 +692,28 @@
 			int processId = Integer.parseInt(procId, 16);
 			if (processes.containsKey(processId)) {
 				String memAddr = splitted[3];
-				Long memoryAddress = Long.parseLong(memAddr,16);
-				Long time = Long.parseLong(splitted[4],16);
+				long memoryAddress = Long.parseLong(memAddr,16);
+				long time = Long.parseLong(splitted[4],16);
+				lastTime = time;
 				String packetNumber = splitted[5];
 
 				if (allocCache.containsKey(memoryAddress)) {
 					AllocInfo info = allocCache.get(memoryAddress);
 					if (info.getMemoryAddress() == memoryAddress && info.getTime() == time) {
 						AbstractList<AllocCallstack> callstack = new ArrayList<AllocCallstack>();
-						createCallstack(splitted, processId, callstack, 6);
+						createCallstack(splitted, processId, callstack, 6, time);
 						info.updateFragment(callstack, packetNumber);
+						
+						int callstackCount = callstack.size();
+						int remaining = remainingCallstacksMap.get(info);
+						remaining -= callstackCount;
+						if (remaining <= 0){
+							remainingCallstacksMap.remove(info);
+							info.finaliseCallstack();
+							allocCache.remove(info);
+						} else {
+							remainingCallstacksMap.put(info, remaining);
+						}
 					}
 				}
 			}
@@ -589,15 +732,14 @@
 	 * @param startIndex
 	 *            Index where to start parse callstack values
 	 */
-	private void createCallstack(String[] splitted, int processId, AbstractList<AllocCallstack> callstack, int startIndex) {
+	private void createCallstack(String[] splitted, int processId, AbstractList<AllocCallstack> callstack, int startIndex, long time) {
 		// append whole callstack as a one memory address
 		for (int i = startIndex; i < splitted.length; i++) {
 			try{
-				AllocCallstack allocCAll = new AllocCallstack();
-				allocCAll.setMemoryAddress(splitted[i]);
+				AllocCallstack allocCAll = new AllocCallstack(splitted[i]);
 
 				// define dll load for current alloc
-				DllLoad dllLoad = getDllLoadName(processId, Long.parseLong(splitted[i],16));
+				DllLoad dllLoad = getDllLoadName(processId, Long.parseLong(splitted[i],16), time);
 				if( dllLoad != null ) {
 					allocCAll.setDllLoad(dllLoad);
 					callstack.add(allocCAll);	
@@ -617,30 +759,28 @@
 	 * message whole callstack to one memory address. This memory address is
 	 * used to calculate most used memory allocation location.
 	 * 
-	 * @param line
-	 *            One trace message
+	 * @param splitted Split trace message
 	 */
 	private void parseMemAddressesFromLine(String[] splitted) {
 
-		//TODO
 		String processID = splitted[1];
 		if (processes.containsKey(processID)) {
-			AllocInfo oneAlloc = new AllocInfo();
+			AllocInfo oneAlloc = new AllocInfo(splitted[3]);
 			oneAlloc.setProcessID(processID);
-			oneAlloc.setMemoryAddress(splitted[3]);
+			oneAlloc.setFilePos(splitted.length > 5 ? filePos : -1);
 			oneAlloc.setTime(splitted[4]);
+			lastTime = oneAlloc.getTime();
 			oneAlloc.setSizeInt(Integer.parseInt(splitted[5], 16));
 
 			// if one trace message contains callstack
-			if (splitted.length > 5) {
+			if (!ignoreCallstacks && !deferCallstacks && splitted.length > 5) {
 				AbstractList<AllocCallstack> callstack = new ArrayList<AllocCallstack>();
 				// append whole callstack as a one memory address
 				for (int i = 6; i < splitted.length; i++) {
-					AllocCallstack allocCAll = new AllocCallstack();
-					allocCAll.setMemoryAddress(splitted[i]);
+					AllocCallstack allocCAll = new AllocCallstack(splitted[i]);
 
 					// define dll load for current alloc
-					DllLoad dllLoad = getDllLoadName(oneAlloc.getProcessID(), allocCAll.getMemoryAddress());
+					DllLoad dllLoad = getDllLoadName(oneAlloc.getProcessID(), allocCAll.getMemoryAddress(), lastTime);
 					if (dllLoad != null) {
 						allocCAll.setDllLoad(dllLoad);
 					}
@@ -648,8 +788,8 @@
 					callstack.add(allocCAll);
 				}
 				oneAlloc.addCallstack(callstack);
-				addMemAddress(oneAlloc);
 			}
+			addMemAddress(oneAlloc);
 		}
 	}
 
@@ -663,10 +803,8 @@
 	 *            Memory address
 	 * @return DllLoad item if found otherwise null
 	 */
-	private DllLoad getDllLoadName(int processId, Long memoryAddress) {
+	private DllLoad getDllLoadName(int processId, Long memoryAddress, long time) {
 		if (processes.containsKey(processId)) {
-			ProcessInfo tempProcessInfo = processes.get(processId);
-			Hashtable<String, DllLoad> loads = tempProcessInfo.getDllLoads();
 
 			// check does cache contains already corresponding item
 			if (dllLoadCache.containsKey(memoryAddress)) {
@@ -674,20 +812,13 @@
 			}
 
 			// no item found in the cache loop thru the loaded dlls
-			for (java.util.Enumeration<String> e = loads.keys(); e.hasMoreElements();) {
-				try {
-					String key = e.nextElement();
-					DllLoad oneLoad = loads.get(key);
-					Long start = oneLoad.getStartAddress();
-					Long end =  oneLoad.getEndAddress();
-					Long actual = memoryAddress;
-					if (actual >= start && actual <= end) {
-						// dll load found => save it to cache and return it
-						dllLoadCache.put(memoryAddress, oneLoad);
-						return oneLoad;
-					}
-				} catch (java.lang.NumberFormatException nfe) {
-					// trace message corrupt?
+			ProcessInfo p = processes.get(processId);
+
+			for (DllLoad oneLoad : p.getDllLoads()) {
+				if (memoryAddress >= oneLoad.getStartAddress() && memoryAddress <= oneLoad.getEndAddress() && time >= oneLoad.getLoadTime() && time <= oneLoad.getUnloadTime()) {
+					// dll load found => save it to cache and return it
+					dllLoadCache.put(memoryAddress, oneLoad);
+					return oneLoad;
 				}
 			}
 		}
@@ -747,13 +878,17 @@
 				parseFreeHeader(lineFragments);
 				break;
 			case ALLOCF:
-				parseAllocFragment(lineFragments);
+				if (!ignoreCallstacks && !deferCallstacks){
+					parseAllocFragment(lineFragments);				
+				}
 				break;
 			case FREEF:
-				parseFreeFragment(lineFragments);
+				if (!ignoreCallstacks && !deferCallstacks){
+					parseFreeFragment(lineFragments);				
+				}
 				break;
 			case DLL_LOAD:
-				if(createGraphModel) {
+				if(createGraphModel && !ignoreCallstacks) {
 					dllLoad = new DllLoad();
 					dllLoad.setProcessID(lineFragments[1]);
 					dllLoad.setName(lineFragments[3]);
@@ -762,18 +897,15 @@
 				}
 				break;
 			case DLL_UNLOAD:
-				if(createGraphModel) {
-					dllLoad = new DllLoad();
-					dllLoad.setProcessID(lineFragments[1]);
-					dllLoad.setName(lineFragments[3]);
-					fillDllLoadInfo(dllLoad, lineFragments);
-					unloadDll(dllLoad);
+				if(createGraphModel && !ignoreCallstacks) {
+					unloadDll(lineFragments);
 				}
 				break;
 			default:
 				// ignore this line
 				break;
 			}
+			
 		}catch(Exception e) {
 			Activator.getDefault().log(IStatus.ERROR, "Error while parsing data", e);
 		}
@@ -798,12 +930,14 @@
 		if (processes.containsKey(processId)) {
 			if( lineFragments.length > 4 ){
 				//check is ABNORMAL process end and that there are enough data to parse
+				ProcessInfo p = processes.get(processId); 
 				if( lineFragments[4].equals(KEYWORD_ABNORMAL) && lineFragments.length > 5 ) {
-					processes.get(processId).setEndTime(lineFragments[5]);	
+					p.setEndTime(lineFragments[5]);	
 				}
 				else {
-					processes.get(processId).setEndTime(lineFragments[4]);
+					p.setEndTime(lineFragments[4]);
 				}	
+				lastTime = p.getEndTime();
 			}
 			
 
@@ -836,7 +970,9 @@
 
 			// clear the founded dll load items list
 			// this prevent that results between runs do not mixed up
-			dllLoadCache.clear();
+			if (dllLoadCache != null){
+				dllLoadCache.clear();				
+			}
 		}
 	}
 
@@ -858,6 +994,7 @@
 
 		if (lineFragments.length > 5) {
 			processInfo.setStartTime(lineFragments[5]);
+			lastTime = processInfo.getStartTime();
 		}
 
 		// set trace data version number
@@ -924,10 +1061,21 @@
 
 				// write data
 				fis.write(dataAndLineFeed.getBytes("UTF-8"));
+				filePos = deferCallstacks ? fis.getChannel().position() : -1;
 			}
 
 		} catch (IOException ioe) {
 			return;
 		}
 	}
+	
+	/**
+	 * Returns true if callstack reading from file is done
+	 * on demand; false if callstacks are made available during parsing
+	 * phase.
+	 * @return true for deferred callstack reading
+	 */
+	public boolean hasDeferredCallstacks(){
+		return deferCallstacks;
+	}
 }