debugsrv/runmodedebug/rmdebug_test/rm_debug/performance_test/t_rmdebug_performance_test.cpp
// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "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:
// Tests performance of run mode debug device component
//
#include <e32base.h>
#include <e32property.h>
#include <e32test.h>
#include <e32def.h>
#include <e32const.h>
#include <hal.h>
#include "t_rmdebug_performance_test.h"
#include "t_debug_logging.h"
#include "t_rmdebug_app.h"
const TVersion securityServerVersion(0,1,1);
_LIT(KTestName, "T_RMDEBUG_PERFORMANCE_TEST");
LOCAL_D RTest test(KTestName);
using namespace Debug;
CRunModeAgent* CRunModeAgent::NewL()
{
LOG_ENTRY();
CRunModeAgent* self = new(ELeave) CRunModeAgent();
self->ConstructL();
LOG_EXIT();
return self;
}
void CRunModeAgent::ConstructL()
{
// ConstructL list does not match destruction list as R-Class member variables are implicitly open.
// DebugDriver().Connect() is conditionally set depending on the test case hence not part of this function.
LOG_ENTRY();
User::LeaveIfError(iIntegerProperty.Attach(RProcess().SecureId(), EPropertyTimeOfCrash, EOwnerThread));
LOG_EXIT();
}
CRunModeAgent::~CRunModeAgent()
{
LOG_ENTRY();
DebugDriver().Close();
iTimeDifs.Close();
iIntegerProperty.Close();
RProperty::Delete(EPropertyTimeOfCrash);
LOG_EXIT();
}
void CRunModeAgent::ClientAppL()
{
LOG_ENTRY();
if ( ParseCommandLine() == EDisplayHelp )
{
DisplayUsage();
}
else
{
static _LIT_SECURITY_POLICY_PASS(KAllowAllPolicy);
RProperty::Define(RProcess().SecureId(), EPropertyTimeOfCrash, RProperty::EInt, KAllowAllPolicy, KAllowAllPolicy);
StartTest();
}
LOG_EXIT();
}
TInt CRunModeAgent::GetTimeInMs()
{
return User::NTickCount() * iTickPeriodMs;
}
void CRunModeAgent::GetStartTime()
{
LOG_ENTRY();
test ( KErrNone == iIntegerProperty.Get(iParams.iCountStart) );
LOG_MSG2("iParams.iCountStart %d", iParams.iCountStart);
LOG_EXIT();
}
void CRunModeAgent::GetNanoTickPeriod()
{
LOG_ENTRY();
TInt period = 0;
User::LeaveIfError(HAL::Get(HALData::ENanoTickPeriod, period));
iTickPeriodMs = period / 1000;
LOG_MSG("iTickPeriodMs = %d\n", iTickPeriodMs);
LOG_EXIT();
}
void CRunModeAgent::StartTest()
{
LOG_ENTRY();
GetNanoTickPeriod();
if (iParams.iTestType == PerformanceTestParams::EBenchMarkTest)
{
RunBenchMarkTest();
}
else
{
TestDriverPerformance();
}
CalculatePerformance();
LOG_EXIT();
}
// This function allows us to provide a benchmark when comparing the performance with the
// old and new APIs using the TestDriverPerformance function below. The two possible
// configurations are as follows:
// 1. Run t_rmdebug_app with a prefetch abort configuration and measure the time from the
// point of crash to the logon request completion.
// 2. Load the debug-system and then run the above configuration.
void CRunModeAgent::RunBenchMarkTest()
{
LOG_ENTRY();
test.Start(_L("RunBenchMarkTest"));
RProcess process;
TRequestStatus status;
if (iParams.iDriver)
{
RDebug::Printf("RunBenchMarkTest() - DebugDriver().Connect()");
test(KErrNone == DebugDriver().Connect(securityServerVersion));
}
LOG_MSG("iParams.iNumOfTestRuns = %d", iParams.iNumOfTestRuns);
for ( TUint i = 0; i < iParams.iNumOfTestRuns; i++ )
{
// Start test application
test( KErrNone == LaunchProcessL(process, KRMDebugTestApplication(), KTargetOptions()) );
process.Logon(status);
User::WaitForRequest(status);
// Stop timer on logon request completion
iParams.iCountEnd = GetTimeInMs();
LOG_MSG("iParams.iCountEnd = %d", iParams.iCountEnd);
LOG_MSG( "status.Int() = %d " , status.Int() );
// prefetch abort should raise a KERN-EXEC 3
test(3 == status.Int());
process.Close();
GetStartTime();
// NTickCount shouldn't overflow, so no reason why this assertion should fail
test(iParams.iCountEnd > iParams.iCountStart);
iTimeDifs.Append( iParams.iCountEnd - iParams.iCountStart );
}
LOG_EXIT();
}
// This function can be used to compare the performance with the old (e.g. attachExe) and new
// (e.g. attachAll) APIs depending depending on the parameters passed in when running this test.
void CRunModeAgent::TestDriverPerformance()
{
LOG_ENTRY();
test.Start(_L("TestDriverPerformance"));
RProcess process;
test(KErrNone == DebugDriver().Connect(securityServerVersion));
LOG_MSG("iParams.iNumOfTestRuns = %d", iParams.iNumOfTestRuns);
for ( TUint i = 0; i < iParams.iNumOfTestRuns; i++ )
{
ilaunchCompleted = EFalse;
Attach();
SetEventAction();
test(KErrNone == LaunchProcessL(process, KRMDebugTestApplication(), KTargetOptions));
LOG_MSG("CRunModeAgent::TestDriverPerformance - process.Logon");
while ( !ilaunchCompleted )
{
LOG_MSG("CRunModeAgent::TestDriverPerformance - DebugDriver().GetEvent");
GetEvent();
LOG_MSG("CRunModeAgent::TestDriverPerformance - User::WaitForRequest");
User::WaitForRequest(iStatus);
LOG_MSG( "iStatus.Int() = %d " , iStatus.Int() );
LOG_MSG("CRunModeAgent::TestDriverPerformance - HandleEvent");
HandleEvent(iSEventInfo.iEventInfo);
}
process.Logon(iStatus);
LOG_MSG("CRunModeAgent::TestDriverPerformance - process.Logon, User::WaitForRequest");
User::WaitForRequest(iStatus);
LOG_MSG( "iStatus.Int() = %d " , iStatus.Int() );
// Stop timer on logon request completion as in benchmark performance test
iParams.iCountEnd = GetTimeInMs();
// prefetch abort should raise a KERN-EXEC 3
test(3 == iStatus.Int());
Detach();
process.Close();
GetStartTime();
// NTickCount shouldn't overflow, so no reason why this assertion should fail
test(iParams.iCountEnd > iParams.iCountStart);
iTimeDifs.Append( iParams.iCountEnd - iParams.iCountStart );
}
LOG_EXIT();
}
void CRunModeAgent::CalculatePerformance()
{
LOG_ENTRY();
TUint median;
TUint arrayCount = iTimeDifs.Count();
for (TInt i = 0; i < arrayCount; i++)
{
RDebug::Printf("iTimeDifs[%d] = %d ",i,iTimeDifs[i]);
}
// Sort in ascending order
iTimeDifs.Sort();
//If the number of elements is odd, the middle element in the sorted array is the median.
//If the number of elements is even, the median is the average of the two midmost elements.
if ( arrayCount%2 != 0 )
{
median = iTimeDifs[arrayCount/2];
}
else
{
median = (iTimeDifs[arrayCount/2] + iTimeDifs[arrayCount/2 -1])/2;
}
RDebug::Printf("Median time %d ms", median );
LOG_EXIT();
}
/**
Launch a process
@param aExeName the executable used to create the process
@param aCommandLine the commandline parameters passed to the new process file name of the executable used to create the process
@return KErrNone on success, or one of the other system wide error codes
*/
TInt CRunModeAgent::LaunchProcessL( RProcess& aProcess, const TDesC& aExeName, const TDesC& aCommandLine )
{
LOG_ENTRY();
RBuf launcherOptions;
launcherOptions.CleanupClosePushL();
const TInt additionalWords = 1;
launcherOptions.CreateL( aCommandLine.Length() + additionalWords );
launcherOptions.Format( aCommandLine, iParams.iTestTargetPriority);
LOG_DES(_L("launcherOptions %S"), &launcherOptions);
TInt err = aProcess.Create( aExeName, launcherOptions );
CleanupStack::PopAndDestroy();
// check that there was no error raised
if (err != KErrNone)
return err;
// rendezvous with process
TRequestStatus status = KRequestPending;
aProcess.Rendezvous(status);
// start the test target
aProcess.Resume();
User::WaitForRequest(status);
if(KErrNone != status.Int())
{
aProcess.Kill(KErrNone);
}
LOG_EXIT();
return status.Int();
}
void CRunModeAgent::SetEventAction()
{
LOG_ENTRY();
if (iParams.iTestType == PerformanceTestParams::EAttachExe)
{
test(KErrNone == DebugDriver().SetEventAction( KRMDebugTestApplication(), EEventsKillThread, EActionContinue));
if ( iParams.iEvents )
{
test(KErrNone == DebugDriver().SetEventAction( KRMDebugTestApplication(), EEventsAddLibrary, EActionContinue));
test(KErrNone == DebugDriver().SetEventAction( KRMDebugTestApplication(), EEventsUserTrace, EActionContinue));
test(KErrNone == DebugDriver().SetEventAction( KRMDebugTestApplication(), EEventsStartThread, EActionContinue));
test(KErrNone == DebugDriver().SetEventAction( KRMDebugTestApplication(), EEventsAddProcess, EActionContinue));
test(KErrNone == DebugDriver().SetEventAction( KRMDebugTestApplication(), EEventsRemoveProcess, EActionContinue));
}
}
else
{
test(KErrNone == DebugDriver().SetEventAction( EEventsKillThread, EActionContinue));
if ( iParams.iEvents )
{
test(KErrNone == DebugDriver().SetEventAction( EEventsAddLibrary, EActionContinue));
test(KErrNone == DebugDriver().SetEventAction( EEventsUserTrace, EActionContinue));
test(KErrNone == DebugDriver().SetEventAction( EEventsStartThread, EActionContinue));
test(KErrNone == DebugDriver().SetEventAction( EEventsAddProcess, EActionContinue));
test(KErrNone == DebugDriver().SetEventAction( EEventsRemoveProcess, EActionContinue));
}
}
LOG_EXIT();
}
void CRunModeAgent::Attach()
{
LOG_ENTRY();
if( iParams.iTestType == PerformanceTestParams::EAttachExe )
{
// Attach to process non-passively
test(KErrNone == DebugDriver().AttachExecutable( KRMDebugTestApplication(), EFalse));
LOG_MSG("DebugDriver().AttachExecutable");
}
else
{
// Attach to all the processes on the system
test(KErrNone == DebugDriver().AttachAll());
LOG_MSG("DebugDriver().AttachAll()");
}
LOG_EXIT();
}
void CRunModeAgent::GetEvent()
{
LOG_ENTRY();
if( iParams.iTestType == PerformanceTestParams::EAttachExe )
{
DebugDriver().GetEvent( KRMDebugTestApplication(), iStatus, iSEventInfo.iEventInfoBuf );
}
else
{
DebugDriver().GetEvent( iStatus, iSEventInfo.iEventInfoBuf );
}
LOG_EXIT();
}
void CRunModeAgent::Detach()
{
LOG_ENTRY();
if( iParams.iTestType == PerformanceTestParams::EAttachExe )
{
test (KErrNone == DebugDriver().DetachExecutable(KRMDebugTestApplication()));
}
else
{
test(KErrNone == DebugDriver().DetachAll());
}
LOG_EXIT();
}
void CRunModeAgent::HandleEvent(TEventInfo& aEventInfo)
{
LOG_ENTRY();
switch ( aEventInfo.iEventType )
{
case EEventsAddProcess:
{
LOG_MSG(">>> EEventsAddProcess");
break;
}
case EEventsStartThread:
{
LOG_MSG(">>> EEventsStartThread");
break;
}
case EEventsUserTrace:
{
LOG_MSG(">>> EEventsUserTrace");
break;
}
case EEventsRemoveProcess:
{
LOG_MSG(">>> EEventsRemoveProcess");
break;
}
case EEventsKillThread:
{
LOG_MSG(">>> EEventsKillThread");
ilaunchCompleted = ETrue;
break;
}
default:
{
LOG_MSG( ">>> Unknown event ");
break;
}
}
LOG_EXIT();
}
void CRunModeAgent::SetDefaultParamValues()
{
LOG_ENTRY();
iParams.iNumOfTestRuns = KNumOfTestRuns;
iParams.iTestType = PerformanceTestParams::EBenchMarkTest;
iParams.iTestTargetPriority = 0;
iParams.iEvents = 0;
iParams.iDriver = 0;
LOG_EXIT();
}
TInt CRunModeAgent::ParseCommandLine()
{
LOG_ENTRY();
TBool ifDisplayHelp = EDontDisplayHelp;
SetDefaultParamValues();
TInt argc = User::CommandLineLength();
LOG_MSG( "Launcher Process() argc=%d", argc );
if( argc )
{
HBufC* commandLine = NULL;
commandLine = HBufC::NewLC(argc);
TPtr commandLineBuffer = commandLine->Des();
User::CommandLine(commandLineBuffer);
LOG_DES(_L("CommandLine = %S"), &commandLineBuffer);
// create a lexer and read through the command line
TLex lex(*commandLine);
while (!lex.Eos())
{
// only look for options with first character '-', other switches are for the targets
if (lex.Get() == '-')
{
TChar arg = lex.Get();
switch (arg)
{
case 'n':
lex.Val( iParams.iNumOfTestRuns );
LOG_MSG("Number of test runs %d", iParams.iNumOfTestRuns);
break;
case 't':
lex.Val( iParams.iTestType );
LOG_MSG("parsed testType as %d", iParams.iTestType );
break;
case 'p':
lex.Val( iParams.iTestTargetPriority );
LOG_MSG("parsed test target priority as %d", iParams.iTestTargetPriority );
break;
case 'e':
lex.Val( iParams.iEvents );
LOG_MSG("parsed events as %d", iParams.iEvents );
break;
case 'd':
lex.Val( iParams.iDriver );
LOG_MSG("parsed iDriver as %d", iParams.iDriver );
break;
case 'h':
LOG_MSG( "Display help" );
ifDisplayHelp = EDisplayHelp;
default:
LOG_MSG( "Default usage" );
break;
}
}
}
CleanupStack::PopAndDestroy(commandLine);
}
LOG_EXIT();
return ifDisplayHelp;
}
void CRunModeAgent::DisplayUsage()
{
LOG_ENTRY();
test.Printf(_L("\nUsage: t_rmdebug_performance_test [options] \nOptions:\n"));
test.Printf(_L("\t-t \t\ttest type\n"));
test.Printf(_L("\t\t\t 0 - AttachAll\n"));
test.Printf(_L("\t\t\t 1 - AttachExe\n"));
test.Printf(_L("\t\t\t 2 - None\n"));
test.Printf(_L("\t-n \t\tnumber of iterations\n"));
test.Printf(_L("\t-e \t\ttest with events\n"));
test.Printf(_L("\t\t\t 0 - No\n"));
test.Printf(_L("\t\t\t 1 - Yes\n"));
test.Printf(_L("\t-p \t\tpriority of test target thread\n"));
test.Printf(_L("\t\t\t %d - EPriorityAbsoluteVeryLow \n"), EPriorityAbsoluteVeryLow);
test.Printf(_L("\t\t\t %d - EPriorityAbsoluteLowNormal \n"), EPriorityAbsoluteLowNormal);
test.Printf(_L("\t\t\t %d - EPriorityAbsoluteLow \n"), EPriorityAbsoluteLow);
test.Printf(_L("\t\t\t %d - EPriorityAbsoluteBackgroundNormal \n"), EPriorityAbsoluteBackgroundNormal);
test.Printf(_L("\t\t\t %d - EPriorityAbsoluteBackground \n"), EPriorityAbsoluteBackground);
test.Printf(_L("\t\t\t %d - EPriorityAbsoluteForegroundNormal \n"), EPriorityAbsoluteForegroundNormal);
test.Printf(_L("\t\t\t %d - EPriorityAbsoluteForeground \n"), EPriorityAbsoluteForeground);
test.Printf(_L("\t\t\t %d - EPriorityAbsoluteHighNormal \n"), EPriorityAbsoluteHighNormal);
test.Printf(_L("\t\t\t %d - EPriorityAbsoluteHigh \n"), EPriorityAbsoluteHigh);
test.Printf(_L("\t\t\t %d - EPriorityAbsoluteRealTime1 \n"), EPriorityAbsoluteRealTime1);
test.Printf(_L("\t\t\t %d - EPriorityAbsoluteRealTime2 \n"), EPriorityAbsoluteRealTime2);
test.Printf(_L("\t\t\t %d - EPriorityAbsoluteRealTime3 \n"), EPriorityAbsoluteRealTime3);
test.Printf(_L("\t\t\t %d - EPriorityAbsoluteRealTime4 \n"), EPriorityAbsoluteRealTime4);
test.Printf(_L("\t\t\t %d - EPriorityAbsoluteRealTime5 \n"), EPriorityAbsoluteRealTime5);
test.Printf(_L("\t\t\t %d - EPriorityAbsoluteRealTime6 \n"), EPriorityAbsoluteRealTime6);
test.Printf(_L("\t\t\t %d - EPriorityAbsoluteRealTime7 \n"), EPriorityAbsoluteRealTime7);
test.Printf(_L("\t\t\t %d - EPriorityAbsoluteRealTime8 \n"), EPriorityAbsoluteRealTime8);
test.Printf(_L("\t-d \t\tload driver\n"));
test.Printf(_L("\t\t\t 0 - No\n"));
test.Printf(_L("\t\t\t 1 - Yes\n"));
test.Printf(_L("\t-h \t\tdisplay usage information\n\n"));
test.Printf(_L("Press any key...\n"));
test.Getch();
LOG_EXIT();
}
GLDEF_C TInt E32Main()
{
__UHEAP_MARK;
TInt ret = KErrNone;
CTrapCleanup* trap = CTrapCleanup::New();
if (!trap)
return KErrNoMemory;
test.Start(KTestName);
CRunModeAgent *runModeAgent = CRunModeAgent::NewL();
if (runModeAgent != NULL)
{
TRAP(ret,runModeAgent->ClientAppL());
LOG_MSG( "ClientAppL() returned %d", ret );
delete runModeAgent;
}
test.End();
test.Close();
delete trap;
__UHEAP_MARKEND;
return ret;
}