perfsrv/analyzetool/commandlineengine/src/CATParseTraceFile.cpp
changeset 48 516af714ebb4
child 52 c2f44e33b468
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/perfsrv/analyzetool/commandlineengine/src/CATParseTraceFile.cpp	Fri Sep 17 08:38:31 2010 +0300
@@ -0,0 +1,973 @@
+/*
+* 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:  Definitions for the class CATParseTraceFile.
+*
+*/
+
+
+#include "../inc/ATCommonDefines.h"
+#include "../inc/CATParseTraceFile.h"
+#include "../inc/catdatasaver.h"
+#include "../inc/CATDatParser.h"
+#include "../inc/CATProcessData.h"
+
+#include <time.h>
+
+
+
+// -----------------------------------------------------------------------------
+// CATParseTraceFile::CATParseTraceFile
+// Constructor.
+// -----------------------------------------------------------------------------
+CATParseTraceFile::CATParseTraceFile()
+{
+	LOG_FUNC_ENTRY("CATParseTraceFile::CATParseTraceFile");
+	m_DataSaver.SetPrintFlag( false );
+}
+
+// -----------------------------------------------------------------------------
+// CATParseTraceFile::StartParse
+// Main function to start trace parsing.
+// -----------------------------------------------------------------------------
+bool CATParseTraceFile::StartParse( const char* pFileName, const char* pOutputFileName, const char* pCleanedTraceFile )
+{
+	LOG_FUNC_ENTRY("CATParseTraceFile::StartParse");
+
+	// Return value, will be changed to true if process start found.
+	bool bRet = false;
+	bool bCreateCleanedTraces = false;
+
+	// Check pointers
+	if ( pFileName == NULL  )
+		return bRet;
+
+	if( pOutputFileName == NULL )
+		return bRet;
+
+	if ( ! FileExists( pFileName ) )
+	{
+		cout << AT_MSG << "Error, input file \""
+			<< pFileName
+			<< "\" does not exist." << endl;
+		return bRet;
+	}
+
+	ofstream cleanedTraces;
+
+	// check is creation of file needed
+	if( pCleanedTraceFile != NULL )
+	{
+		// if yes open file for cleaned traces
+	    // (<AT> messages with cleaned timestamps)
+		bCreateCleanedTraces = true;
+
+		cleanedTraces.open(pCleanedTraceFile);
+
+		if( !cleanedTraces.good() )
+		{
+			printf( "Can not open file: %s\n", pCleanedTraceFile );
+			return bRet;
+		}
+	}
+
+	// Open data file
+	ifstream in( pFileName );
+
+	// Check file opened ok
+	if ( !in.good() )
+		return false;
+
+	// Get stream size
+	size_t streamPos = in.tellg();
+	in.seekg( 0, ios::end);
+	size_t streamEnd = in.tellg();
+	in.seekg( 0, ios::beg);
+
+	//Origianl characters (not filtered).
+	char cOriginalLineFromFile[MAX_LINE_LENGTH];
+
+	vector<CProcessData> vProcessList;
+	int iProcessIDinList = -1;
+
+	bool bFileVersionSaved = false;
+	// Read lines
+	while( streamPos < streamEnd )
+	{
+		// Get one line. Don't use stream flags to determinate end of file
+		// it can be found too early because trace can contain "anything".
+		in.getline( cOriginalLineFromFile, MAX_LINE_LENGTH );
+		
+		// Refresh position
+		streamPos = in.tellg();
+
+		// Check has bad bit flag raised. (i.e. device problems reading data)
+		if( in.bad() )
+		{
+			cout << AT_MSG << "Integrity error reading the trace file, reading aborted." << endl;
+			return false;
+		}
+		//Filtered characters.
+		char cLineFromFile[MAX_LINE_LENGTH];
+		char* pFiltered = cLineFromFile;
+
+		//Loop thru all characters in original line.
+		for( size_t i = 0 ; cOriginalLineFromFile[i] != 0 ; i++ )
+		{
+			//If character in line is not in invalid character array append it
+			//to filtered line.
+			if ( strchr( cINVALID_TRACE_FILE_CHARS, cOriginalLineFromFile[i] ) == 0 )
+					*pFiltered++ =  cOriginalLineFromFile[i];
+		}
+		*pFiltered++ = 0; //Add null termination to filtered line.
+
+		if( !bFileVersionSaved && *cLineFromFile != 0 )
+		{
+			bFileVersionSaved = true;
+			m_DataSaver.AddString( AT_DATA_FILE_VERSION );
+			m_DataSaver.AddLineToLast();
+		}
+
+		// Is there main ID?
+		if( strstr( cLineFromFile, MAIN_ID ) != NULL )
+		{
+			string sRestOfLine( cLineFromFile );
+			string sTemp("");
+			unsigned __int64 iTimeStamp(0);
+			string sTime("");
+			string sLineStart("");
+
+			// Get part of line before main id. This should contain time info
+			sLineStart = GetStringUntilMainId( sRestOfLine );
+			// Get message's time stamp in microseconds
+			iTimeStamp = ParseTimeStamp( sLineStart );
+			// store whole line from MAIN_ID - to be logged to cleaned traces file
+		    string sLineToCleanedFile( sRestOfLine );
+
+			// Get main ID
+			sTemp = GetStringUntilNextSpace( sRestOfLine );
+
+			// Is there more data in line?
+			if( sRestOfLine.empty() )
+			{
+				continue;
+			}
+
+			// Get next argument
+			sTemp = GetStringUntilNextSpace( sRestOfLine );
+			// This might be process id, device info message or error message
+			if ( sTemp.compare( ERROR_OCCURED ) == 0 )
+			{
+				// Api mismatch between s60 side and atool.exe
+				if ( sRestOfLine.find( INCORRECT_ATOOL_VERSION ) != string::npos )
+				{
+					cout << "Test run failed because version conflict between device binaries\nand the atool.exe version used to build the application." << endl;
+					size_t pS = sRestOfLine.find_first_of('[');
+					size_t pE =  sRestOfLine.find_first_of(']');
+					size_t pSL = sRestOfLine.find_last_of('[');
+					size_t pEL = sRestOfLine.find_last_of(']');
+					if ( pS != string::npos && pE != string::npos && pSL != string::npos && pEL != string::npos )
+					{
+						string deviceVer = sRestOfLine.substr( pS+1, pE-pS-1 );
+						string atoolVer = sRestOfLine.substr( pSL+1, pEL-pSL-1 );
+						cout << "\tdevice: " << deviceVer << endl 
+							<<  "\tatool.exe: " << atoolVer << endl;
+					}
+				}
+				else
+					cout << sRestOfLine << endl;
+				continue;
+			}
+
+			if ( sTemp.compare( LABEL_DEVICE_INFO ) == 0 ) 
+			{
+
+				if( vProcessList[iProcessIDinList].bProcessOnGoing == false )
+				continue;
+
+				// get time string from timestamp
+			    sTime = GetTimeFromTimeStamp( iTimeStamp, vProcessList[iProcessIDinList].iTimeSpan );
+
+				// device info line, log it to cleaned file for carbide
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				cleanedTraces << sTime << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << LABEL_DEVICE_INFO << " "; //add Message type
+				cleanedTraces << sRestOfLine << "\n"; //add the rest of the line
+				}
+				continue;
+			}
+
+			unsigned long iProcessID = _httoi( sTemp.c_str() );
+			// todo to be removed when reallocations are implemented
+			string sProcessID = sTemp;
+
+			iProcessIDinList = -1;
+			// Find process from list
+			for( unsigned int i = 0 ; i < vProcessList.size() ; i++ )
+			{
+				if( vProcessList[i].iProcessID == iProcessID )
+				{
+					iProcessIDinList = i;
+					break;
+				}
+			}
+			// Is Process ID found from list?
+			if( iProcessIDinList == -1 )
+			{
+				CProcessData ProcessData;
+				ProcessData.bProcessOnGoing = false;
+				ProcessData.iProcessID = iProcessID;
+				vProcessList.push_back( ProcessData );
+				iProcessIDinList = (int)vProcessList.size() - 1;
+			}
+
+			// Remove spaces from end of line
+			while( sRestOfLine[sRestOfLine.size()-1] == ' ' )
+			{
+				sRestOfLine.resize( sRestOfLine.size()-1 );
+			}
+
+			string sWholeTempLine( sRestOfLine );
+
+			// Get command
+			sTemp = GetStringUntilNextSpace( sRestOfLine );
+
+			// Use c style string for easy comparisong of command.
+			const char* pCommand = sTemp.c_str();		
+
+			// Process start.
+			if( ! _stricmp( pCommand, LABEL_PROCESS_START ) )
+			{
+				bRet = true; // Set return value true we found start.
+				vProcessList[iProcessIDinList].vData.push_back( sWholeTempLine );
+				vProcessList[iProcessIDinList].bProcessOnGoing = true;
+
+				// remove <processName> <processID> part
+				GetStringUntilNextSpace( sRestOfLine );
+				GetStringUntilNextSpace( sRestOfLine );
+				// get time
+				sTemp = GetStringUntilNextSpace( sRestOfLine );
+				unsigned __int64 iTemp(0);
+				sscanf_s( sTemp.c_str(), "%016I64x", &iTemp);
+				//calculate span between PCS time and PCS timestamp
+				vProcessList[iProcessIDinList].iTimeSpan = iTemp - iTimeStamp;
+
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				cleanedTraces << sTemp << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << sProcessID << " "; //add process ID
+				cleanedTraces << sWholeTempLine << "\n"; //add the rest of the line
+				}
+
+				continue;
+			}
+
+			// Check is process ongoing if not skip other tags.
+			if( vProcessList[iProcessIDinList].bProcessOnGoing == false )
+				continue;
+
+			// get time string from timestamp
+			sTime = GetTimeFromTimeStamp( iTimeStamp, vProcessList[iProcessIDinList].iTimeSpan );
+
+			// TODO version with reallocation
+			//cleanedTraces << sTime << " "; //add time
+			//cleanedTraces << sLineToCleanedFile << "\n"; //add the rest of the line
+
+			// "Old style" allocation (< v.1.6)
+			if( ! _stricmp( pCommand, ALLOC_ID ) )
+			{
+				// Add alloc
+				vProcessList[iProcessIDinList].Alloc( sRestOfLine );
+
+				// Subtests running?
+				vector<CSubTestData>::iterator viSubTestIter = vProcessList[iProcessIDinList].vSubTests.begin();
+				while( viSubTestIter != vProcessList[iProcessIDinList].vSubTests.end() )
+				{
+					if( viSubTestIter->bRunning )
+					{
+						// Save alloc also to sub test
+						viSubTestIter->Alloc( sRestOfLine );
+					}
+					viSubTestIter++;
+				}
+			}
+			else if ( ! _stricmp( pCommand, ALLOCH_ID ) )
+			{
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				cleanedTraces << sTime << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << sProcessID << " "; //add process ID
+				cleanedTraces << sWholeTempLine << "\n"; //add the rest of the line
+				}
+
+				// Add alloc
+				vProcessList[iProcessIDinList].AllocH( sRestOfLine, sTime );
+
+				// Subtests running?
+				vector<CSubTestData>::iterator viSubTestIter = vProcessList[iProcessIDinList].vSubTests.begin();
+				while( viSubTestIter != vProcessList[iProcessIDinList].vSubTests.end() )
+				{
+					if( viSubTestIter->bRunning )
+					{
+						// Save alloc also to sub test
+						viSubTestIter->AllocH( sRestOfLine, sTime );
+					}
+					viSubTestIter++;
+				}
+			}
+			// Allocation fragment (call stack).
+			else if ( ! _stricmp( pCommand, ALLOCF_ID ) )
+			{
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				cleanedTraces << sTime << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << sProcessID << " "; //add process ID
+				cleanedTraces << sWholeTempLine << "\n"; //add the rest of the line
+				}
+
+				// Add alloc fragment
+				vProcessList[iProcessIDinList].AllocF( sRestOfLine, sTime );
+				
+				// Subtests running?
+				vector<CSubTestData>::iterator viSubTestIter = vProcessList[iProcessIDinList].vSubTests.begin();
+				while( viSubTestIter != vProcessList[iProcessIDinList].vSubTests.end() )
+				{
+					if( viSubTestIter->bRunning )
+					{
+						// Save alloc fragment also to sub test
+						viSubTestIter->AllocF( sRestOfLine, sTime );
+					}
+					viSubTestIter++;
+				}
+			}
+			else if ( ! _stricmp( pCommand, REALLOCH_ID ) )
+			{
+				// Add free
+
+				// get 'free' line from realloc line
+				string sFreeRestOfLine = sRestOfLine;
+				string sFreeLine = "";
+				sFreeLine.append( GetStringUntilNextSpace( sFreeRestOfLine, true ) ); //append freed memory address
+				sFreeLine.append( " " );
+				// next two strings are for 'alloc' (address and size) - lets remove them
+				GetStringUntilNextSpace( sFreeRestOfLine, true );
+				GetStringUntilNextSpace( sFreeRestOfLine, true );
+				// add rest of line to 'free' line
+				sFreeLine.append( sFreeRestOfLine );
+				//add 'free' line
+				vProcessList[iProcessIDinList].FreeH( sFreeLine, sTime );
+
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				// construct 'free' header trace
+				cleanedTraces << sTime << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << sProcessID << " "; //add process ID
+				cleanedTraces << FREEH_ID << " "; //add FRH
+				cleanedTraces << sFreeLine << "\n"; //add the rest of the line
+				}
+
+				// Add alloc
+
+				//get 'alloc' line from realloc line
+				// only first string is unnecessary, lets remove it
+				GetStringUntilNextSpace( sRestOfLine );
+     			// add 'alloc' line
+				vProcessList[iProcessIDinList].AllocH( sRestOfLine, sTime );
+
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				// construct 'alloc' header trace
+				cleanedTraces << sTime << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << sProcessID << " "; //add process ID
+				cleanedTraces << ALLOCH_ID << " "; //add FRH
+				cleanedTraces << sRestOfLine << "\n"; //add the rest of the line
+				}
+
+				// Subtests running?
+				vector<CSubTestData>::iterator viSubTestIter = vProcessList[iProcessIDinList].vSubTests.begin();
+				while( viSubTestIter != vProcessList[iProcessIDinList].vSubTests.end() )
+				{
+					if( viSubTestIter->bRunning )
+					{
+						// Save realloc also to sub test
+						// Add free
+
+						// get 'free' line from realloc line
+						string sFreeRestOfLine = sRestOfLine;
+						string sFreeLine = "";
+						sFreeLine.append( GetStringUntilNextSpace( sFreeRestOfLine, true ) ); //append freed memory address
+						sFreeLine.append( " " );
+						// next two strings are for 'alloc' (address and size) - lets remove them
+						GetStringUntilNextSpace( sFreeRestOfLine, true );
+						GetStringUntilNextSpace( sFreeRestOfLine, true );
+						// add rest of line to 'free' line
+						sFreeLine.append( sFreeRestOfLine );
+						//add 'free' line
+						vProcessList[iProcessIDinList].FreeH( sFreeLine, sTime );
+
+						// Add alloc
+
+						//get 'alloc' line from realloc line
+						// only first string is unnecessary, lets remove it
+						GetStringUntilNextSpace( sRestOfLine );
+     					// add 'alloc' line
+						vProcessList[iProcessIDinList].AllocH( sRestOfLine, sTime );
+					}
+					viSubTestIter++;
+				}
+			}
+			// rellocation fragment (call stack).
+			else if ( ! _stricmp( pCommand, REALLOCF_ID ) )
+			{
+				// Add free fragment 
+
+				// get 'free' line from realloc line
+				string sFreeRestOfLine = sRestOfLine;
+				string sFreeLine = "";
+				sFreeLine.append( GetStringUntilNextSpace( sFreeRestOfLine, true ) ); //append freed memory address
+				sFreeLine.append( " " );
+				// next string is for 'alloc' (address) - lets remove it
+				GetStringUntilNextSpace( sFreeRestOfLine, true );
+				// add rest of line to 'free' line
+				sFreeLine.append( sFreeRestOfLine );
+				//add 'free' line
+				vProcessList[iProcessIDinList].FreeH( sFreeLine, sTime );
+
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				// construct 'free' fragment trace
+				cleanedTraces << sTime << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << sProcessID << " "; //add process ID
+				cleanedTraces << FREEF_ID << " "; //add FRF
+				cleanedTraces << sFreeLine << "\n"; //add the rest of the line
+				}
+
+				// Add alloc fragment
+
+				// first string is for 'free' (address), lets remove it first
+				GetStringUntilNextSpace( sRestOfLine, true );
+				//add 'alloc' line
+				vProcessList[iProcessIDinList].AllocF( sRestOfLine, sTime );
+
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				// construct 'alloc' fragment trace
+				cleanedTraces << sTime << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << sProcessID << " "; //add process ID
+				cleanedTraces << ALLOCF_ID << " "; //add FRF
+				cleanedTraces << sRestOfLine << "\n"; //add the rest of the line
+				}
+				
+				// Subtests running?
+				vector<CSubTestData>::iterator viSubTestIter = vProcessList[iProcessIDinList].vSubTests.begin();
+				while( viSubTestIter != vProcessList[iProcessIDinList].vSubTests.end() )
+				{
+					if( viSubTestIter->bRunning )
+					{
+						// Save alloc fragment also to sub test
+						// Add free fragment 
+
+						// get 'free' line from realloc line
+						string sFreeRestOfLine = sRestOfLine;
+						string sFreeLine = "";
+						sFreeLine.append( GetStringUntilNextSpace( sFreeRestOfLine, true ) ); //append freed memory address
+						sFreeLine.append( " " );
+						// next string is for 'alloc' (address) - lets remove it
+						GetStringUntilNextSpace( sFreeRestOfLine, true );
+						// add rest of line to 'free' line
+						sFreeLine.append( sFreeRestOfLine );
+						//add 'free' line
+						vProcessList[iProcessIDinList].FreeH( sFreeLine, sTime );
+
+						// Add alloc fragment
+
+						// first string is for 'free' (address), lets remove it first
+						GetStringUntilNextSpace( sRestOfLine, true );
+						//add 'alloc' line
+						vProcessList[iProcessIDinList].AllocF( sRestOfLine, sTime );
+					}
+					viSubTestIter++;
+				}
+			}
+			// Command free
+			else if( ! _stricmp( pCommand, FREE_ID ) )
+			{
+				// Send free
+				vProcessList[iProcessIDinList].Free( sRestOfLine );
+
+				// Subtests running?
+				vector<CSubTestData>::iterator viSubTestIter = vProcessList[iProcessIDinList].vSubTests.begin();
+				while( viSubTestIter != vProcessList[iProcessIDinList].vSubTests.end() )
+				{
+					if( viSubTestIter->bRunning )
+					{
+						// Send free to subtest
+						viSubTestIter->Free( sRestOfLine );
+					}
+					viSubTestIter++;
+				}
+			}
+			// Header free.
+			else if( ! _stricmp( pCommand, FREEH_ID ) )
+			{
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				cleanedTraces << sTime << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << sProcessID << " "; //add process ID
+				cleanedTraces << sWholeTempLine << "\n"; //add the rest of the line
+				}
+
+				// Send free
+				vProcessList[iProcessIDinList].FreeH( sRestOfLine, sTime );
+
+				// Subtests running?
+				vector<CSubTestData>::iterator viSubTestIter = vProcessList[iProcessIDinList].vSubTests.begin();
+				while( viSubTestIter != vProcessList[iProcessIDinList].vSubTests.end() )
+				{
+					if( viSubTestIter->bRunning )
+					{
+						// Send free to subtest
+						viSubTestIter->FreeH( sRestOfLine, sTime );
+					}
+					viSubTestIter++;
+				}
+			
+			}
+			else if( ! _stricmp( pCommand, FREEF_ID ) )
+			{
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				cleanedTraces << sTime << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << sProcessID << " "; //add process ID
+				cleanedTraces << sWholeTempLine << "\n"; //add the rest of the line
+				}
+				// Not used currently.
+			}
+			// Command process end
+			else if( ! _stricmp( pCommand, LABEL_PROCESS_END ) )
+			{
+				// append processID and time
+				sWholeTempLine.append(" ");
+				sWholeTempLine.append( sProcessID );
+				sWholeTempLine.append(" ");
+				sWholeTempLine.append( sTime );
+
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				cleanedTraces << sTime << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << sProcessID << " "; //add process ID
+				cleanedTraces << sWholeTempLine << "\n"; //add the rest of the line
+				}
+
+				// Set process has ended.
+				vProcessList[iProcessIDinList].bProcessOnGoing = false;
+
+				// Save leaks
+				vector<string> vLeaks;
+				vector<string>::iterator viLeaks;
+				vProcessList[iProcessIDinList].GetLeakList( vLeaks );
+				for ( viLeaks = vLeaks.begin(); viLeaks != vLeaks.end(); viLeaks++ )
+				{
+					sTemp.clear();
+					sTemp.append( LABEL_MEM_LEAK );
+					sTemp.append( " " );
+					sTemp.append( *viLeaks );
+					vProcessList[iProcessIDinList].vData.push_back( sTemp );
+				}
+				vProcessList[iProcessIDinList].ClearAllocs();
+
+				vector<string>::iterator viHandleIter = vProcessList[iProcessIDinList].vHandleLeaks.begin();
+				// Print handle leaks
+				while( viHandleIter != vProcessList[iProcessIDinList].vHandleLeaks.end() )
+				{
+					sTemp.clear();
+					sTemp.append( viHandleIter->c_str() );
+					vProcessList[iProcessIDinList].vData.push_back( sTemp );
+					viHandleIter++;
+				}
+				// Clear handle leaks from list
+				vProcessList[iProcessIDinList].vHandleLeaks.clear();
+
+				vector<CSubTestData>::iterator viSubTestIter = vProcessList[iProcessIDinList].vSubTests.begin();
+				// Print sub test leaks
+				while( viSubTestIter != vProcessList[iProcessIDinList].vSubTests.end() )
+				{
+					// Print sub test start
+					string sLine( LABEL_TEST_START ); sLine.append( " " );
+					sLine.append( viSubTestIter->sStartTime ); sLine.append( " " );
+					sLine.append( viSubTestIter->sSubTestName ); sLine.append( " " );
+					sLine.append( viSubTestIter->sSubTestStartHandleCount );
+					vProcessList[iProcessIDinList].vData.push_back( sLine );
+					sLine.clear();
+
+					// DLL Loads.
+					for( vector<string>::iterator it = viSubTestIter->vData.begin();
+						it != viSubTestIter->vData.end(); it++ )
+					{
+						vProcessList[iProcessIDinList].vData.push_back( (*it) );
+					}
+
+					// Subtest leaks.
+					vector<string> vSubLeaks;
+					vector<string>::iterator viSubLeaks;
+					viSubTestIter->GetLeakList( vSubLeaks );
+					for ( viSubLeaks = vSubLeaks.begin(); viSubLeaks != vSubLeaks.end(); viSubLeaks++ )
+					{
+						sLine.append( LABEL_MEM_LEAK );
+						sLine.append( " " );
+						sLine.append( *viSubLeaks );
+						vProcessList[iProcessIDinList].vData.push_back( sLine );
+						sLine.clear();
+					}
+					viSubTestIter->ClearAllocs();
+
+					if( !viSubTestIter->sEndTime.empty() )
+					{
+						// Print sub test end
+						sLine.append( LABEL_TEST_END ); sLine.append( " " );
+						sLine.append( viSubTestIter->sEndTime ); sLine.append( " " );
+						sLine.append( viSubTestIter->sSubTestName ); sLine.append( " " );
+						sLine.append( viSubTestIter->sSubTestEndHandleCount );
+						vProcessList[iProcessIDinList].vData.push_back( sLine );
+					}
+					viSubTestIter++;
+				}
+
+				// Clear sub tests from list
+				vProcessList[iProcessIDinList].vSubTests.clear();
+				vProcessList[iProcessIDinList].vData.push_back( sWholeTempLine );
+			}
+			else if( ! _stricmp( pCommand, LABEL_HANDLE_LEAK ) )
+			{
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				cleanedTraces << sTime << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << sProcessID << " "; //add process ID
+				cleanedTraces << sWholeTempLine << "\n"; //add the rest of the line
+				}
+
+				// Make whole line
+				sTemp.append( " " );
+				sTemp.append( sRestOfLine );
+				vProcessList[iProcessIDinList].vHandleLeaks.push_back( sTemp );
+			}
+			else if( ! _stricmp( pCommand, LABEL_DLL_LOAD ) )
+			{
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				cleanedTraces << sTime << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << sProcessID << " "; //add process ID
+				cleanedTraces << sWholeTempLine << "\n"; //add the rest of the line
+				}
+
+				// append time to the end of the line
+				sWholeTempLine.append( " " );
+				sWholeTempLine.append( sTime );
+
+				// Add module load to process data.
+				vProcessList[iProcessIDinList].vData.push_back( sWholeTempLine );
+				// Add module load to subtest data if test running.
+				for( vector<CSubTestData>::iterator it = vProcessList[iProcessIDinList].vSubTests.begin();
+					it != vProcessList[iProcessIDinList].vSubTests.end(); it++ )
+				{
+					if( it->bRunning )
+						it->vData.push_back( sWholeTempLine );
+				}
+
+			}
+			else if( ! _stricmp( pCommand, LABEL_DLL_UNLOAD ) )
+			{
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				cleanedTraces << sTime << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << sProcessID << " "; //add process ID
+				cleanedTraces << sWholeTempLine << "\n"; //add the rest of the line
+				}
+
+				// append time to the end of the line
+				sWholeTempLine.append( " " );
+				sWholeTempLine.append( sTime );
+
+				// Add module load to process data.
+				vProcessList[iProcessIDinList].vData.push_back( sWholeTempLine );
+				// Add module unload to subtest data if test running.
+				for( vector<CSubTestData>::iterator it = vProcessList[iProcessIDinList].vSubTests.begin();
+					it != vProcessList[iProcessIDinList].vSubTests.end(); it++ )
+				{
+					if( it->bRunning )
+						it->vData.push_back( sWholeTempLine );
+				}
+			}
+			else if( sTemp.find( LABEL_LOGGING_CANCELLED ) != string::npos ||
+				     sTemp.find( LABEL_PROCESS_END ) != string::npos || sTemp.find( LABEL_ERROR_OCCURED ) != string::npos ||
+					 sTemp.find( LABEL_HANDLE_LEAK ) != string::npos )
+			{
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				cleanedTraces << sTime << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << sProcessID << " "; //add process ID
+				cleanedTraces << sWholeTempLine << "\n"; //add the rest of the line
+				}
+
+				vProcessList[iProcessIDinList].vData.push_back( sWholeTempLine );
+			}
+			else if( ! _stricmp( pCommand, LABEL_TEST_START ) )
+			{
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				cleanedTraces << sTime << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << sProcessID << " "; //add process ID
+				cleanedTraces << sWholeTempLine << "\n"; //add the rest of the line
+				}
+
+				bRet = true; // Set return value true we found start.
+				// Get sub test time
+				string sSubTestTime = GetStringUntilNextSpace( sRestOfLine );
+				// Get sub test name
+				string sSubTestName = GetStringUntilNextSpace( sRestOfLine );
+				// Get sub test start handle count
+				string sSubTestStartHandleCount = GetStringUntilNextSpace( sRestOfLine );
+
+				CSubTestData SubTestData;
+				SubTestData.bRunning = true;
+				SubTestData.sStartTime = sSubTestTime;
+				SubTestData.sSubTestName = sSubTestName;
+				SubTestData.sSubTestStartHandleCount = sSubTestStartHandleCount.c_str();
+
+				vProcessList[iProcessIDinList].vSubTests.push_back( SubTestData );
+			}
+			else if( ! _stricmp( pCommand, LABEL_TEST_END ) )
+			{
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				cleanedTraces << sTime << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << sProcessID << " "; //add process ID
+				cleanedTraces << sWholeTempLine << "\n"; //add the rest of the line
+				}
+
+				// Get sub test time
+				string sSubTestEnd = GetStringUntilNextSpace( sRestOfLine );
+				// Get sub test name
+				string sSubTestName = GetStringUntilNextSpace( sRestOfLine );
+				// Get sub test end handle count
+				string sSubTestEndHandleCount = GetStringUntilNextSpace( sRestOfLine );
+
+				// Find subtest
+				vector<CSubTestData>::iterator viSubTestIter = vProcessList[iProcessIDinList].vSubTests.begin();
+				while( viSubTestIter != vProcessList[iProcessIDinList].vSubTests.end() )
+				{
+					if( viSubTestIter->sSubTestName == sSubTestName && viSubTestIter->sEndTime.empty() )
+					{
+						viSubTestIter->sEndTime = sSubTestEnd;
+						viSubTestIter->bRunning = false;
+						viSubTestIter->sSubTestEndHandleCount = sSubTestEndHandleCount.c_str();
+					}
+					viSubTestIter++;
+				}
+			}
+			else if( ! _stricmp( pCommand, LABEL_THREAD_START ) )
+			{
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				cleanedTraces << sTime << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << sProcessID << " "; //add process ID
+				cleanedTraces << sWholeTempLine << "\n"; //add the rest of the line
+				}
+
+				//currently not used
+			}
+			else if( ! _stricmp( pCommand, LABEL_THREAD_END ) )
+			{
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				cleanedTraces << sTime << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << sProcessID << " "; //add process ID
+				cleanedTraces << sWholeTempLine << "\n"; //add the rest of the line
+				}
+
+				//currently not used
+			}
+			else
+			{
+				// unknown tag, log it to cleaned file for carbide
+				if( bCreateCleanedTraces )
+				{
+				// add message to cleaned traces file
+				cleanedTraces << sTime << " "; //add time
+				cleanedTraces << MAIN_ID << " "; //add MAIN_ID
+				cleanedTraces << sProcessID << " "; //add process ID
+				cleanedTraces << sWholeTempLine << "\n"; //add the rest of the line
+				}
+			}
+		}
+	}
+
+	if( bCreateCleanedTraces )
+	{
+	// close stream
+	cleanedTraces.close();
+	}
+
+	// Print all saved data from processes
+	for( unsigned int i = 0 ; i < vProcessList.size() ; i++ )
+	{
+		// Print saved lines
+		for( unsigned int iDataCounter = 0 ; iDataCounter < vProcessList[i].vData.size() ; iDataCounter++ )
+		{
+			m_DataSaver.AddString( vProcessList[i].vData[iDataCounter].c_str() );
+			m_DataSaver.AddLineToLast();
+		}
+
+		string sTemp;
+
+		// Save leaks
+		vector<string> vLeaks;
+		vector<string>::iterator viLeaks;
+		vProcessList[i].GetLeakList( vLeaks );
+		for ( viLeaks = vLeaks.begin(); viLeaks != vLeaks.end(); viLeaks++ )
+		{
+			sTemp.clear();
+			sTemp.append( LABEL_MEM_LEAK );
+			sTemp.append( " " );
+			sTemp.append( *viLeaks );
+			m_DataSaver.AddString( sTemp.c_str() );
+			m_DataSaver.AddLineToLast();
+		}
+
+		vector<string>::iterator viHandleIter = vProcessList[i].vHandleLeaks.begin();
+		// Print handle leaks, if there is data left, there was no process end.
+		while( viHandleIter != vProcessList[i].vHandleLeaks.end() )
+		{
+			sTemp.clear();
+			sTemp.append( viHandleIter->c_str() );
+			m_DataSaver.AddString( sTemp.c_str() );
+			m_DataSaver.AddLineToLast();
+			viHandleIter++;
+		}
+		vector<CSubTestData>::iterator viSubTestIter = vProcessList[i].vSubTests.begin();
+		// Print sub test data, if there is data left, there was no process end.
+		while( viSubTestIter != vProcessList[i].vSubTests.end() )
+		{
+			// Print sub test start
+			string sLine( LABEL_TEST_START ); sLine.append( " " );
+			sLine.append( viSubTestIter->sStartTime ); sLine.append( " " );
+			sLine.append( viSubTestIter->sSubTestName ); sLine.append( " " );
+			sLine.append( viSubTestIter->sSubTestStartHandleCount );
+			m_DataSaver.AddString( sLine.c_str() );
+			m_DataSaver.AddLineToLast();
+			sLine.clear();
+
+			// DLL Loads.
+			for( vector<string>::iterator it = viSubTestIter->vData.begin();
+				it != viSubTestIter->vData.end(); it++ )
+			{
+				m_DataSaver.AddString( (*it).c_str() );
+				m_DataSaver.AddLineToLast();
+			}
+
+			// Subtest leaks.
+			vector<string> vSubLeaks;
+			vector<string>::iterator viSubLeaks;
+			viSubTestIter->GetLeakList( vSubLeaks );
+			for ( viSubLeaks = vSubLeaks.begin(); viSubLeaks != vSubLeaks.end(); viSubLeaks++ )
+			{
+				sLine.append( LABEL_MEM_LEAK );
+				sLine.append( " " );
+				sLine.append( *viSubLeaks );
+				m_DataSaver.AddString( sLine.c_str() );
+				m_DataSaver.AddLineToLast();
+				sLine.clear();
+			}
+
+			// Print sub test end
+			sLine.append( LABEL_TEST_END ); sLine.append( " " );
+			sLine.append( viSubTestIter->sEndTime ); sLine.append( " " );
+			sLine.append( viSubTestIter->sSubTestName ); sLine.append( " " );
+			sLine.append( viSubTestIter->sSubTestEndHandleCount );
+			m_DataSaver.AddString( sLine.c_str() );
+			m_DataSaver.AddLineToLast();
+
+			viSubTestIter++;
+		}
+	}
+	// Save lines to file.
+	m_DataSaver.SaveLinesToFile( pOutputFileName, TEXT_DATA );
+	// Close file.
+	in.close();
+	return bRet;
+}
+
+// -----------------------------------------------------------------------------
+// CATParseTraceFile::GetDataSaver
+// Gets data saver object.
+// -----------------------------------------------------------------------------
+CATDataSaver* CATParseTraceFile::GetDataSaver(void)	
+{
+	LOG_LOW_FUNC_ENTRY("CATParseTraceFile::GetDataSaver");
+	return &m_DataSaver;
+}
+
+
+// -----------------------------------------------------------------------------
+// CATBase::GetTimeFromTimeStamp
+// Gets time from timestamp in microseconds as string
+// -----------------------------------------------------------------------------
+string CATParseTraceFile::GetTimeFromTimeStamp( unsigned __int64 iTimeStamp, unsigned __int64 iTimeSpan )
+{
+	unsigned __int64 iTime = iTimeStamp + iTimeSpan;
+	stringstream ss;
+	ss <<  std::hex << iTime;
+
+    return ss.str();
+}
+
+//EOF