diff -r 000000000000 -r f0f2b8682603 memana/analyzetoolclient/commandlineengine/internal/src/CATParseTraceFile.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/memana/analyzetoolclient/commandlineengine/internal/src/CATParseTraceFile.cpp Thu Feb 11 15:51:35 2010 +0200 @@ -0,0 +1,585 @@ +/* +* 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 + +#define MAIN_ID "PCSS" +#define ALLOC_ID "ALLOC" // < V.1.6 allocation. +#define ALLOCH_ID "ALLOCH" // Header of multi message allocation. +#define ALLOCF_ID "ALLOCF" // Fragment of multi message allocation. +#define FREE_ID "FREE" +#define FREEH_ID "FREEH" // Header of multi message free. +#define FREEF_ID "FREEF" // Fragment of multi message free. +#define HANDLE_LEAK_ID "HANDLE_LEAK" + +const string ERROR_OCCURED = "ERROR_OCCURED"; // Error messages. +const string INCORRECT_ATOOL_VERSION = "INCORRECT_ATOOL_VERSION"; +/** +* Invalid characters in trace file line content. +* These will be filtered out before actuall parsing of line. +10 = LF +13 = CR +124 = | +*/ +const char cINVALID_TRACE_FILE_CHARS[] = { 10, 13, 124 }; + +// ----------------------------------------------------------------------------- +// 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 ) +{ + LOG_FUNC_ENTRY("CATParseTraceFile::StartParse"); + + // Return value, will be changed to true if process start found. + bool bRet = 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; + } + + // 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 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; + + // Delete all characters before main ID + sRestOfLine.erase( 0, sRestOfLine.find( MAIN_ID ) ); + + // 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 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; + } + unsigned long iProcessID = _httoi( sTemp.c_str() ); + + 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; + continue; + } + + // Check is process ongoing if not skip other tags. + if( vProcessList[iProcessIDinList].bProcessOnGoing == false ) + continue; + + // "Old style" allocation (< v.1.6) + if( ! _stricmp( pCommand, ALLOC_ID ) ) + { + // Add alloc + vProcessList[iProcessIDinList].Alloc( sRestOfLine ); + + // Subtests running? + vector::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 ) ) + { + // Add alloc + vProcessList[iProcessIDinList].AllocH( sRestOfLine ); + + // Subtests running? + vector::iterator viSubTestIter = vProcessList[iProcessIDinList].vSubTests.begin(); + while( viSubTestIter != vProcessList[iProcessIDinList].vSubTests.end() ) + { + if( viSubTestIter->bRunning ) + { + // Save alloc also to sub test + viSubTestIter->AllocH( sRestOfLine ); + } + viSubTestIter++; + } + } + // Allocation fragment (call stack). + else if ( ! _stricmp( pCommand, ALLOCF_ID ) ) + { + // Add alloc fragment + vProcessList[iProcessIDinList].AllocF( sRestOfLine ); + + // Subtests running? + vector::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 ); + } + viSubTestIter++; + } + } + // Command free + else if( ! _stricmp( pCommand, FREE_ID ) ) + { + // Send free + vProcessList[iProcessIDinList].Free( sRestOfLine ); + + // Subtests running? + vector::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 ) ) + { + // Send free + vProcessList[iProcessIDinList].FreeH( sRestOfLine ); + + // Subtests running? + vector::iterator viSubTestIter = vProcessList[iProcessIDinList].vSubTests.begin(); + while( viSubTestIter != vProcessList[iProcessIDinList].vSubTests.end() ) + { + if( viSubTestIter->bRunning ) + { + // Send free to subtest + viSubTestIter->FreeH( sRestOfLine ); + } + viSubTestIter++; + } + + } + else if( ! _stricmp( pCommand, FREEF_ID ) ) + { + // Not used currently. + } + // Command process end + else if( ! _stricmp( pCommand, LABEL_PROCESS_END ) ) + { + // Set process has ended. + vProcessList[iProcessIDinList].bProcessOnGoing = false; + + // Save leaks + vector vLeaks; + vector::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::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::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::iterator it = viSubTestIter->vData.begin(); + it != viSubTestIter->vData.end(); it++ ) + { + vProcessList[iProcessIDinList].vData.push_back( (*it) ); + } + + // Subtest leaks. + vector vSubLeaks; + vector::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 ) ) + { + // Make whole line + sTemp.append( " " ); + sTemp.append( sRestOfLine ); + vProcessList[iProcessIDinList].vHandleLeaks.push_back( sTemp ); + } + else if( ! _stricmp( pCommand, LABEL_DLL_LOAD ) ) + { + // Add module load to process data. + vProcessList[iProcessIDinList].vData.push_back( sWholeTempLine ); + // Add module load to subtest data if test running. + for( vector::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 ) ) + { + // Add module load to process data. + vProcessList[iProcessIDinList].vData.push_back( sWholeTempLine ); + // Add module unload to subtest data if test running. + for( vector::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 ) + { + vProcessList[iProcessIDinList].vData.push_back( sWholeTempLine ); + } + else if( ! _stricmp( pCommand, LABEL_TEST_START ) ) + { + 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 ) ) + { + // 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::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++; + } + } + } + } + + // 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 vLeaks; + vector::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::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::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::iterator it = viSubTestIter->vData.begin(); + it != viSubTestIter->vData.end(); it++ ) + { + m_DataSaver.AddString( (*it).c_str() ); + m_DataSaver.AddLineToLast(); + } + + // Subtest leaks. + vector vSubLeaks; + vector::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; +} +//EOF