phonebookengines/contactsmodel/tsrc/t_bench.cpp
changeset 0 e686773b3f54
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines/contactsmodel/tsrc/t_bench.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,1029 @@
+// Copyright (c) 2000-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:
+//
+
+#include <e32std.h>
+#include <e32test.h>
+#include <e32math.h>
+#include <cntdb.h>
+#include <cntitem.h>
+#include <cntfldst.h>
+#include "t_utils2.h"
+#include "t_bench.h"
+#include "T_UTILS.H"
+
+
+//
+// Configuration.
+//
+
+#define __TxEST
+#define __VxERBOSE
+
+
+//
+// Constants.
+//
+
+_LIT(KTestName,"t_bench");
+
+
+_LIT(KDbFileName,"c:contacts.cdb");
+
+_LIT(KLogFileName,"t_bench.log");
+_LIT(KBackSpace,"\x08");
+_LIT(KVisualCounterFormat,"%S%d");
+_LIT(KTimeProfileFormat,"Time taken (secs)");
+_LIT(KSystemMemoryFormat,"System memory used (Kb)");
+_LIT(KThreadMemoryFormat,"This thread memory used (Kb)");
+_LIT(KFileSizeText,"File size (bytes)");
+_LIT(KAverageTimeText,"Average time taken (secs)");
+_LIT(KResultFormatTInt,"Result #%d.%d %S [%d]");
+_LIT(KResultFormatTReal,"Result #%d.%d %S [%f]");
+_LIT(KThreadNameFormat,"T_BenchCli%2d");
+_LIT(KPhoneMatchFail,"6666666666666666");
+_LIT(KNameMatchFail,"xxxxxxxxxxxxxxxx");
+_LIT(KAsyncFindMatch,"a");
+_LIT(KNewLine,"\n");
+_LIT(KTextDefSeparator,"\t");
+
+#ifdef __VERBOSE
+_LIT(KContactSummaryFormat,"%d\t%S\t%S\t%S");
+_LIT(KAscendingSortOrder,"ascending");
+_LIT(KDescendingSortOrder,"descending");
+_LIT(KProfileResult,"Took %d\tmicrosecs for %d iteration(s)");
+#endif
+
+const TInt KNumSortClients=10;
+const TInt KClientStackSize=KDefaultStackSize;
+const TInt KClientHeapSize=0x20000;
+
+#ifdef __TEST
+const TInt KNumTypicalContacts=10;
+const TInt KNumAtypicalContacts=2;
+const TInt KNumTypicalContactsCompact=0;
+const TInt KNumAtypicalContactsCompact=0;
+#else
+const TInt KNumTypicalContacts=100;
+const TInt KNumAtypicalContacts=50;
+const TInt KNumTypicalContactsCompact=150;
+const TInt KNumAtypicalContactsCompact=50;
+#endif // __TEST
+
+
+//
+// CBenchMarker.
+//
+
+CBenchMarker::CBenchMarker() : iTest(KTestName),iVisualCounter(-1),iNumTypicalContacts(-1),iNumAtypicalContacts(-1),iNumTypicalContactsCompact(-1),iNumAtypicalContactsCompact(-1)
+	{
+	}
+
+CBenchMarker::~CBenchMarker()
+	{
+	delete iGenerator;
+	delete iDb;
+	delete iTextDef;
+	delete iLog;
+	iTest.Close();
+	iFs.Close();
+	}
+
+void CBenchMarker::ConstructL(const TDesC& aCommandLine)
+	{
+	User::LeaveIfError(iFs.Connect());
+	DecodeCommandLineL(aCommandLine);
+	iLog=CLog::NewL(iTest,iLogFileName);
+	iGenerator=CRandomContactGenerator::NewL();
+	}
+
+void CBenchMarker::DecodeCommandLineL(const TDesC& aCommandLine)
+	{
+	_LIT(KArgContactsToAdd,"-a");
+	_LIT(KArgContactsToCompact,"-c");
+	_LIT(KArgDatabaseFileName,"-d");
+	_LIT(KArgNoDataGenerationTests,"-g");
+	_LIT(KArgLogFile,"-l");
+	_LIT(KArgHelp,"-h");
+	
+	TLex cl(aCommandLine);
+	while (cl.Remainder().Length()>0)
+		{
+		TPtrC token=cl.NextToken();
+		
+		if (token.CompareF(KArgContactsToAdd)==0)
+			{
+			cl.SkipSpace();
+			User::LeaveIfError(cl.Val(iNumTypicalContacts));
+			cl.SkipSpace();
+			User::LeaveIfError(cl.Val(iNumAtypicalContacts));
+			}
+		else if (token.CompareF(KArgContactsToCompact)==0)
+			{
+			cl.SkipSpace();
+			User::LeaveIfError(cl.Val(iNumTypicalContactsCompact));
+			cl.SkipSpace();
+			User::LeaveIfError(cl.Val(iNumAtypicalContactsCompact));
+			}
+		else if (token.CompareF(KArgDatabaseFileName)==0)
+			{
+			iDbFileName=cl.NextToken();
+			}
+		else if (token.CompareF(KArgNoDataGenerationTests)==0)
+			{
+			iNoDataGenerationTests=ETrue;
+			}
+		else if (token.CompareF(KArgLogFile)==0)
+			{
+			iLogFileName=cl.NextToken();
+			}
+		else if (token.CompareF(KArgHelp)==0)
+			{
+			iTest.Printf(_L("Usage t_bench [options]\n\n"));
+			iTest.Printf(_L("-a <num_typical> <num_atypical> (default: %d %d)\n"),KNumTypicalContacts,KNumAtypicalContacts);
+			iTest.Printf(_L("-c <num_typical_comp> <num_atypical_comp> (default: %d %d)\n"),KNumTypicalContactsCompact,KNumAtypicalContactsCompact);
+			iTest.Printf(_L("-d <db_name> (default: %S)\n"),&KDbFileName);
+			iTest.Printf(_L("-l <log_name> (default: %S)\n"),&KLogFileName);
+			iTest.Printf(_L("-g skip data generation tests\n"));
+			iTest.Printf(_L("\n<hit any key>"));
+			iTest.Getch();
+			User::Leave(KErrNone);
+			}
+		}
+
+	if (iDbFileName.Length()==0)
+		{
+		iDbFileName=KDbFileName;
+		}
+
+	if (iLogFileName.Length()==0)
+		{
+		iLogFileName=KLogFileName;
+		}
+
+	if (iNoDataGenerationTests)
+		{
+		TUint att;
+		if (iFs.Att(iDbFileName,att)==KErrNotFound)
+			{
+			iTest.Printf(_L("-g switch ignored, because %S not found\n"),&iDbFileName);
+			iNoDataGenerationTests=EFalse;
+			}
+		}
+
+	if (iNumTypicalContacts<0)
+		{
+		iNumTypicalContacts=KNumTypicalContacts;
+		}
+
+	if (iNumAtypicalContacts<0)
+		{
+		iNumAtypicalContacts=KNumAtypicalContacts;
+		}
+
+	if (iNumTypicalContactsCompact<0)
+		{
+		iNumTypicalContactsCompact=KNumTypicalContactsCompact;
+		}
+
+	if (iNumAtypicalContactsCompact<0)
+		{
+		iNumAtypicalContactsCompact=KNumAtypicalContactsCompact;
+		}
+	}
+
+void CBenchMarker::RunL()
+	{
+	iTest.Printf(_L("Starting CntModel benchmarks...\n")); // This forces the console to get loaded under WINS - would otherwise scew profiles.
+
+	for (TInt i=0;i<ENumTests;++i)
+		{
+		StartProfile();
+		TInt timeMinorNumber=0;
+		TRAPD(err,timeMinorNumber=DoTestL(TTest(i)));
+		if (err)
+			{
+			iLog->LogLine(_L("Test %d left with %d"),i,err);
+			break;
+			}
+
+		LogResult(i,timeMinorNumber,KTimeProfileFormat,EndProfile());
+
+		User::CompressAllHeaps();
+		TMemoryInfoV1Buf memoryBuf;
+		UserHal::MemoryInfo(memoryBuf);
+		TMemoryInfoV1 memory(memoryBuf());
+		const TInt totalK=memory.iTotalRamInBytes>>10;
+		const TInt freeK=memory.iFreeRamInBytes>>10;
+		const TInt usedK=totalK-freeK;
+		LogResult(i,timeMinorNumber+1,KSystemMemoryFormat,usedK);
+		
+		TInt allocSize;
+		User::Heap().AllocSize(allocSize);;
+		allocSize>>=10;
+		LogResult(i,timeMinorNumber+2,KThreadMemoryFormat,allocSize);
+		}
+
+	iTest.Printf(_L("Dump log to comm port? (y/n) "));
+	TKeyCode key=iTest.Getch();
+	if (key=='y' || key=='Y')
+		{
+writelog:
+		iLog->WriteLogToCommPortL();
+		}
+	iTest.Printf(_L("\nAgain? (y/n)"));
+	key=iTest.Getch();
+	if (key=='y' || key=='Y')
+		{
+		goto writelog;
+		}
+	}
+
+TInt CBenchMarker::DoTestL(TTest aTest)
+	{
+	TInt timeMinorNumber=0;
+	iLog->Log(_L("Test   #%d   "),aTest);
+	TPtrC match;
+
+	switch (aTest)
+		{
+		case EOpenNewDb:
+			iLog->LogLine(_L("Open new database"));
+			if (iNoDataGenerationTests)
+				{
+				iDb=CContactDatabase::OpenL(iDbFileName);
+				}
+			else
+				{
+				iDb=CContactDatabase::ReplaceL(iDbFileName);
+				LogResult(aTest,0,KFileSizeText,DbFileSize());
+				timeMinorNumber=1;
+				}
+			iGenerator->SetDbL(*iDb);
+			break;
+		case ECreateSecondaryClients:
+			iLog->LogLine(_L("Create %d secondary client threads"),KNumSecondaryClients);
+			CreateSecondaryClients();
+			break;
+		case EAddContacts:
+			iLog->LogLine(_L("Add %d typical and %d atypical contacts"),iNumTypicalContacts,iNumAtypicalContacts);
+			if (!iNoDataGenerationTests)
+				{
+				LogResult(aTest,0,KAverageTimeText,AddContactsL());
+				LogResult(aTest,1,KFileSizeText,DbFileSize());
+				timeMinorNumber=2;
+				}
+			break;
+		case ECompactDb:
+			iLog->LogLine(_L("Compact database"));
+			if (!iNoDataGenerationTests)
+				{
+				iDb->CompactL();
+				LogResult(aTest,0,KFileSizeText,DbFileSize());
+				timeMinorNumber=1;
+				}
+			break;
+		case EAddAndCompact:
+			iLog->LogLine(_L("Add %d typical and %d atypical contacts (compact after each)"),iNumTypicalContactsCompact,iNumAtypicalContactsCompact);
+			if (!iNoDataGenerationTests)
+				{
+				LogResult(aTest,0,KAverageTimeText,AddContactsCompactL());
+				LogResult(aTest,1,KFileSizeText,DbFileSize());
+				timeMinorNumber=2;
+				}
+			break;
+		case EGetSortedItems:
+			iLog->LogLine(_L("Get sorted id array by firstname, lastname, company name"));
+			DoSortL();
+			break;
+		case ELogContactSummary:
+			iLog->LogLine(_L("Log contact summary"));
+			LogContactSummaryL(EFalse);
+			break;
+		case ELogContactSummaryFast:
+			iLog->LogLine(_L("Log contact summary using TContactTextDefItem"));
+			LogContactSummaryL(ETrue);
+			break;
+		case EOpenRContactView:
+			iLog->LogLine(_L("Open RContactView"));
+			OpenRContactViewL();
+			break;
+		case ESetSortOrderOfRContactView:
+			iLog->LogLine(_L("Set order of RContactView"));
+			SetSortOrderOfRContactViewL();
+			break;
+		case EGetSortOrderOfRContactView:
+			iLog->LogLine(_L("Get order of RContactView"));
+			GetSortOrderOfRContactViewL();
+			break;
+		case ELogContactSummaryWithRContactView:
+			iLog->LogLine(_L("Log contact summary using RContactView"));
+			LogContactSummaryFromRContactViewL(EFalse);
+			break;
+		case ELogContactSummaryFastWithRContactView:
+			iLog->LogLine(_L("Log contact summary using RContactView and TContactTextDefItem"));
+			LogContactSummaryFromRContactViewL(ETrue);
+			break;
+		case EFindWithRContactView:
+			iLog->LogLine(_L("Find TContactItemId from RContactView"));
+			FindInRContactViewL();
+			break;
+		case ECloseRContactView:
+			iLog->LogLine(_L("Close RContactView"));
+#ifdef __USE_NEW_INTERFACES
+			iSortedIdList.Close();
+#endif
+			break;
+		case EFindFromLargeFieldSetSuceed:
+			match.Set(iGenerator->NameMatch());
+			iLog->LogLine(_L("FindLC %S using large field set (will suceed)"),&match);
+			FindFromLargeFieldSetL(match);
+			break;
+		case EFindFromLargeFieldSetFail:
+			iLog->LogLine(_L("FindLC %S using large field set (will fail)"),&KNameMatchFail);
+			FindFromLargeFieldSetL(KNameMatchFail);
+			break;
+		case EFindFromSmallFieldSetSuceed:
+			match.Set(iGenerator->NameMatch());
+			iLog->LogLine(_L("FindLC %S using small field set (will suceed)"),&match);
+			FindFromSmallFieldSetL(match);
+			break;
+		case EFindFromSmallFieldSetFail:
+			iLog->LogLine(_L("FindLC %S using small field set (will fail)"),&KNameMatchFail);
+			FindFromSmallFieldSetL(KNameMatchFail);
+			break;
+		case EFindPhoneNumberSuceed:
+			match.Set(iGenerator->PhoneMatch());
+			iLog->LogLine(_L("FindLC %S using just phone field (will suceed)"),&match);
+			FindPhoneNumberL(match);
+			break;
+		case EFindPhoneNumberFail:
+			iLog->LogLine(_L("FindLC %S using just phone field (will fail)"),&KPhoneMatchFail);
+			FindPhoneNumberL(KPhoneMatchFail);
+			break;
+		case EFindEmailAddressSuceed:
+			match.Set(iGenerator->EmailMatch());
+			iLog->LogLine(_L("FindLC %S using just email field (will suceed)"),&match);
+			FindEmailAddressL(match);
+			break;
+		case EFindEmailAddressFail:
+			iLog->LogLine(_L("FindLC %S using just email field (will fail)"),&KNameMatchFail);
+			FindEmailAddressL(KNameMatchFail);
+			break;
+		case EFindAsyncFromLargeFieldSet:
+			iLog->LogLine(_L("FindAsyncL %S using large field set"),&KAsyncFindMatch);
+			FindAsyncFromLargeFieldSetL(KAsyncFindMatch);
+			break;
+		case EFindAsyncFromSmallFieldSet:
+			iLog->LogLine(_L("FindAsyncL %S using small field set"),&KAsyncFindMatch);
+			FindAsyncFromSmallFieldSetL(KAsyncFindMatch);
+			break;
+		case ECloseDb:
+			iLog->LogLine(_L("Close database"));
+			delete iDb;
+			iDb=NULL;
+			break;
+		case ECloseSecondaryClients:
+			iLog->LogLine(_L("Close secondary clients"));
+			CloseSecondaryClients();
+			break;
+		case EOpenExistingDb:
+			iLog->LogLine(_L("Open existing database"));
+			iDb=CContactDatabase::OpenL(iDbFileName);
+			break;
+		case EMultiClientSort:
+			iLog->LogLine(_L("%d client simultaneous sort"),KNumSortClients);
+			CreateSortClients();
+			break;
+		case ENumTests:
+			ASSERT(EFalse);
+			break;
+		}
+
+	return timeMinorNumber;
+	}
+
+void CBenchMarker::StartProfile()
+	{
+	CCntTest::ProfileReset(0,1); // reset profiles 0-1
+	CCntTest::ProfileStart(0);
+	}
+
+TReal CBenchMarker::EndProfile()
+	{
+	CCntTest::ProfileEnd(0);
+	TCntProfile profile[1];
+	CCntTest::ProfileResult(profile,0,1);
+	return TReal(profile[0].iTime/1000000.0);
+	}
+
+void CBenchMarker::StartAverageProfile()
+	{
+	iAverageProfileCounter=0;
+	iNumAverageProfiles=0;
+	CCntTest::ProfileReset(1,1);
+	CCntTest::ProfileStart(1);
+	}
+
+void CBenchMarker::UpdateAverageProfile(TInt aNumIterations)
+	{
+	CCntTest::ProfileEnd(1);
+	TCntProfile profile[1];
+	CCntTest::ProfileResult(profile,1,1);
+	iAverageProfileCounter+=profile[0].iTime;
+	iNumAverageProfiles+=aNumIterations;
+	CCntTest::ProfileReset(1,1);
+	CCntTest::ProfileStart(1);
+#ifdef __VERBOSE
+	iLog->LogLineNoEcho(KProfileResult,profile[0].iTime,aNumIterations);	
+#endif
+	}
+
+TReal CBenchMarker::EndAverageProfile()
+	{
+	CCntTest::ProfileEnd(1);
+	if (iNumAverageProfiles>0)
+		{
+		return TReal((iAverageProfileCounter/iNumAverageProfiles)/1000000.0);
+		}
+
+	return TReal(0.0);
+	}
+
+TReal CBenchMarker::AddContactsL()
+	{
+	iTest.Printf(_L("Adding "));
+	StartAverageProfile();
+
+	TInt ii;
+	for (ii=0;ii<iNumTypicalContacts;++ii)
+		{
+		IncVisualCounter();
+		iGenerator->AddTypicalRandomContactL();
+		UpdateAverageProfile(1);
+		}
+
+	for (ii=0;ii<iNumAtypicalContacts;++ii)
+		{
+		IncVisualCounter();
+		iGenerator->AddAtypicalRandomContactL();
+		UpdateAverageProfile(1);
+		}
+
+	EndVisualCounter();
+	return EndAverageProfile();
+	}
+
+TReal CBenchMarker::AddContactsCompactL()
+	{
+	iTest.Printf(_L("Adding "));
+	StartAverageProfile();
+
+	TInt ii;
+	for (ii=0;ii<iNumTypicalContactsCompact;++ii)
+		{
+		IncVisualCounter();
+		iGenerator->AddTypicalRandomContactL();
+		iDb->CompactL();
+		UpdateAverageProfile(1);
+		}
+
+	for (ii=0;ii<iNumAtypicalContactsCompact;++ii)
+		{
+		IncVisualCounter();
+		iGenerator->AddAtypicalRandomContactL();
+		iDb->CompactL();
+		UpdateAverageProfile(1);
+		}
+
+	EndVisualCounter();
+	return EndAverageProfile();
+	}
+
+#ifdef __USE_NEW_INTERFACES
+void CBenchMarker::LogContactSummaryFromRContactViewL(TBool aFaster)
+	{
+	iTest.Printf(_L("Logging "));
+	const TInt numContacts(iSortedIdList.Count());
+	for (TInt ii=0;ii<numContacts;++ii)
+		{
+		IncVisualCounter();
+		LogContactSummaryL(aFaster,iSortedIdList.GetL(ii));
+		}
+	EndVisualCounter();
+	}
+#else
+void CBenchMarker::LogContactSummaryFromRContactViewL(TBool)
+	{
+	}
+#endif
+
+void CBenchMarker::OpenRContactViewL()
+	{
+#ifdef __USE_NEW_INTERFACES
+	User::LeaveIfError(iSortedIdList.Open(*iDb));
+#endif
+	}
+
+void CBenchMarker::SetSortOrderOfRContactViewL()
+	{
+#ifdef __USE_NEW_INTERFACES
+	CArrayFix<CContactDatabase::TSortPref>* sortOrder=new(ELeave)CArrayFixFlat<CContactDatabase::TSortPref>(2);
+	CleanupStack::PushL(sortOrder);
+	sortOrder->AppendL(CContactDatabase::TSortPref(KUidContactFieldGivenName));
+	sortOrder->AppendL(CContactDatabase::TSortPref(KUidContactFieldFamilyName));
+	sortOrder->AppendL(CContactDatabase::TSortPref(KUidContactFieldCompanyName));
+	iSortedIdList.ChangeSortOrderL(*sortOrder);
+	CleanupStack::PopAndDestroy(); // sortOrder
+#endif
+	}
+
+void CBenchMarker::GetSortOrderOfRContactViewL()
+	{
+#ifdef __USE_NEW_INTERFACES
+	const CArrayFix<CContactDatabase::TSortPref>& sortOrder=iSortedIdList.SortOrderLC();
+#ifdef __VERBOSE
+	const TInt numSortPrefs=sortOrder.Count();
+	for (TInt ii=0;ii<numSortPrefs;++ii)
+		{
+		iLog->LogLineNoEcho(_L("Sort pref %d field type: %x order: %S"),ii,sortOrder[ii].iFieldType,(sortOrder[ii].iOrder==CContactDatabase::TSortPref::EAsc) ? &KAscendingSortOrder : &KDescendingSortOrder);
+		}
+#else
+	sortOrder.Count();
+#endif
+	CleanupStack::PopAndDestroy(); // sortOrder
+#endif
+	}
+
+void CBenchMarker::FindInRContactViewL()
+	{
+#ifdef __USE_NEW_INTERFACES
+	const TContactItemId id=iSortedIdList.GetL(iSortedIdList.Count()-1);
+	const TInt index=iSortedIdList.Find(id);
+	ASSERT(index==iSortedIdList.Count()-1);
+	iLog->LogLine(_L("Found TContactItemId %d for index %d"),id,index);
+#endif
+	}
+
+void CBenchMarker::LogContactSummaryL(TBool aFaster)
+	{
+	iTest.Printf(_L("Logging "));
+	const TInt numContacts(iSortedItems->Count());
+	for (TInt ii=0;ii<numContacts;++ii)
+		{
+		IncVisualCounter();
+		LogContactSummaryL(aFaster,(*iSortedItems)[ii]);
+		}
+	EndVisualCounter();
+	}
+
+void CBenchMarker::LogContactSummaryL(TBool aFaster,TContactItemId aContactItemId)
+	{
+	if (aFaster)
+		{
+		if (iTextDef==NULL)
+			{
+			iTextDef=CContactTextDef::NewL();
+			iTextDef->AppendL(TContactTextDefItem(KUidContactFieldGivenName,KTextDefSeparator));
+			iTextDef->AppendL(TContactTextDefItem(KUidContactFieldFamilyName,KTextDefSeparator));
+			iTextDef->AppendL(TContactTextDefItem(KUidContactFieldCompanyName,KTextDefSeparator));
+			}
+
+		TBuf<128> buf;
+		iDb->ReadContactTextDefL(aContactItemId,buf,iTextDef);
+#ifdef __VERBOSE
+		iLog->LogLineNoEcho(buf);
+#endif
+		}
+	else
+		{
+		CContactItem* thisContactItem=iDb->ReadContactLC(aContactItemId);
+		CTestContact* thisContact=CTestContact::NewLC(*thisContactItem);
+
+#ifdef __VERBOSE
+		const TPtrC firstName(thisContact->FirstNameL());
+		const TPtrC lastName(thisContact->LastNameL());
+		const TPtrC companyName(thisContact->CompanyNameL());
+		iLog->LogLineNoEcho(KContactSummaryFormat,thisContactItem->Id(),&firstName,&lastName,&companyName);
+#else
+		thisContact->FirstNameL();
+		thisContact->LastNameL();
+		thisContact->CompanyNameL();
+#endif
+		CleanupStack::PopAndDestroy(2); // thisContact, thisContactItem.
+		}
+	}
+
+
+void CBenchMarker::DoSortL()
+	{
+	CContactTextDef* textDef=CContactTextDef::NewLC();
+	textDef->AppendL(TContactTextDefItem(KUidContactFieldGivenName));
+	textDef->AppendL(TContactTextDefItem(KUidContactFieldFamilyName));
+	textDef->AppendL(TContactTextDefItem(KUidContactFieldCompanyName));
+	iDb->SetTextDefinitionL(textDef); // Takes ownership.
+	CleanupStack::Pop(); // textDef.
+	CArrayFix<CContactDatabase::TSortPref>* sortOrder=new(ELeave)CArrayFixFlat<CContactDatabase::TSortPref>(2);
+	CleanupStack::PushL(sortOrder);
+	sortOrder->AppendL(CContactDatabase::TSortPref(KUidContactFieldDefinedText));
+	iDb->SortL(sortOrder); // Takes ownership.
+	CleanupStack::Pop(); // sortOrder
+	iSortedItems=iDb->SortedItemsL();
+	}
+
+void CBenchMarker::FindFromLargeFieldSetL(const TDesC& aTextToFind)
+	{
+	CContactItemFieldDef* def=new(ELeave) CContactItemFieldDef();
+	CleanupStack::PushL(def);
+	def->AppendL(KUidContactFieldGivenName);
+	def->AppendL(KUidContactFieldFamilyName);
+	def->AppendL(KUidContactFieldCompanyName);
+	def->AppendL(KUidContactFieldPhoneNumber);
+	def->AppendL(KUidContactFieldFax);
+	def->AppendL(KUidContactFieldEMail);
+	def->AppendL(KUidContactFieldUrl);
+	def->AppendL(KUidContactFieldAddress);
+	def->AppendL(KUidContactFieldLocality);
+	def->AppendL(KUidContactFieldRegion);
+	def->AppendL(KUidContactFieldPostcode);
+	def->AppendL(KUidContactFieldCountry);
+	def->AppendL(KUidContactFieldNote);
+	DoFindL(aTextToFind,*def);
+	CleanupStack::PopAndDestroy(); // def.
+	}
+
+void CBenchMarker::FindFromSmallFieldSetL(const TDesC& aTextToFind)
+	{
+	CContactItemFieldDef* def=new(ELeave) CContactItemFieldDef();
+	CleanupStack::PushL(def);
+	def->AppendL(KUidContactFieldGivenName);
+	def->AppendL(KUidContactFieldFamilyName);
+	def->AppendL(KUidContactFieldCompanyName);
+	DoFindL(aTextToFind,*def);
+	CleanupStack::PopAndDestroy(); // def.
+	}
+
+void CBenchMarker::FindPhoneNumberL(const TDesC& aTextToFind)
+	{
+	CContactItemFieldDef* def=new(ELeave) CContactItemFieldDef();
+	CleanupStack::PushL(def);
+	def->AppendL(KUidContactFieldPhoneNumber);
+	DoFindL(aTextToFind,*def);
+	CleanupStack::PopAndDestroy(); // def.
+	}
+
+void CBenchMarker::FindEmailAddressL(const TDesC& aTextToFind)
+	{
+	CContactItemFieldDef* def=new(ELeave) CContactItemFieldDef();
+	CleanupStack::PushL(def);
+	def->AppendL(KUidContactFieldEMail);
+	DoFindL(aTextToFind,*def);
+	CleanupStack::PopAndDestroy(); // def.
+	}
+
+TReal CBenchMarker::FindAsyncFromLargeFieldSetL(const TDesC& aTextToFind)
+	{
+	CContactItemFieldDef* def=new(ELeave) CContactItemFieldDef();
+	CleanupStack::PushL(def);
+	def->AppendL(KUidContactFieldGivenName);
+	def->AppendL(KUidContactFieldFamilyName);
+	def->AppendL(KUidContactFieldCompanyName);
+	def->AppendL(KUidContactFieldPhoneNumber);
+	def->AppendL(KUidContactFieldFax);
+	def->AppendL(KUidContactFieldEMail);
+	def->AppendL(KUidContactFieldUrl);
+	def->AppendL(KUidContactFieldAddress);
+	def->AppendL(KUidContactFieldLocality);
+	def->AppendL(KUidContactFieldRegion);
+	def->AppendL(KUidContactFieldPostcode);
+	def->AppendL(KUidContactFieldCountry);
+	def->AppendL(KUidContactFieldNote);
+	TReal averageTime=DoFindAsyncL(aTextToFind,*def);
+	CleanupStack::PopAndDestroy(); // def.
+	return averageTime;
+	}
+
+TReal CBenchMarker::FindAsyncFromSmallFieldSetL(const TDesC& aTextToFind)
+	{
+	CContactItemFieldDef* def=new(ELeave) CContactItemFieldDef();
+	CleanupStack::PushL(def);
+	def->AppendL(KUidContactFieldGivenName);
+	def->AppendL(KUidContactFieldFamilyName);
+	def->AppendL(KUidContactFieldCompanyName);
+	TReal averageTime=DoFindAsyncL(aTextToFind,*def);
+	CleanupStack::PopAndDestroy(); // def.
+	return averageTime;
+	}
+
+void CBenchMarker::DoFindL(const TDesC& aTextToFind,const CContactItemFieldDef& aFieldDef)
+	{
+	CContactIdArray* matchList=iDb->FindLC(aTextToFind,&aFieldDef);
+
+#ifdef __VERBOSE
+	const TInt numIds=matchList->Count();
+	iLog->LogLine(_L("Matched %d contact(s)"),numIds);
+	for (TInt ii=0;ii<numIds;++ii)
+		{
+		LogContactSummaryL(ETrue,(*matchList)[ii]);
+		}
+#else
+	matchList->Count();
+#endif
+
+	CleanupStack::PopAndDestroy(); // matchList.
+	}
+
+TReal CBenchMarker::DoFindAsyncL(const TDesC& aTextToFind,const CContactItemFieldDef& aFieldDef)
+	{
+	iTest.Printf(_L("Found "));
+	StartAverageProfile();
+	iIdleFinder=iDb->FindAsyncL(aTextToFind,&aFieldDef,this);
+	CleanupStack::PushL(iIdleFinder); // Handle on cleanup stack because object is very temporary.
+	CActiveScheduler::Start();
+
+	EndVisualCounter();
+#ifdef __VERBOSE
+	CContactIdArray* matchList=iIdleFinder->TakeContactIds();
+	CleanupStack::PushL(matchList);
+	const TInt numIds=matchList->Count();
+	iLog->LogLine(_L("Matched %d contact(s)"),numIds);
+	for (TInt ii=0;ii<numIds;++ii)
+		{
+		LogContactSummaryL(ETrue,(*matchList)[ii]);
+		}
+	CleanupStack::PopAndDestroy(); // matchList.
+#endif
+	
+	CleanupStack::PopAndDestroy(); // iIdleFinder.
+	return EndAverageProfile();
+	}
+
+void CBenchMarker::IdleFindCallback()
+	{
+	IncVisualCounter();
+	UpdateAverageProfile(1);
+	if (iIdleFinder->IsComplete())
+		{
+		CActiveScheduler::Stop();
+		}
+	}
+
+#ifndef __USE_NEW_INTERFACES
+GLDEF_C void DoSortL(CContactDatabase& aDb)
+	{
+	CContactTextDef* textDef=CContactTextDef::NewLC();
+	textDef->AppendL(TContactTextDefItem(KUidContactFieldGivenName));
+	textDef->AppendL(TContactTextDefItem(KUidContactFieldFamilyName));
+	textDef->AppendL(TContactTextDefItem(KUidContactFieldCompanyName));
+	aDb.SetTextDefinitionL(textDef); // Takes ownership.
+	CleanupStack::Pop(); // textDef.
+	CArrayFix<CContactDatabase::TSortPref>* sortOrder=new(ELeave)CArrayFixFlat<CContactDatabase::TSortPref>(2);
+	CleanupStack::PushL(sortOrder);
+	sortOrder->AppendL(CContactDatabase::TSortPref(KUidContactFieldDefinedText));
+	aDb.SortL(sortOrder); // Takes ownership.
+	CleanupStack::Pop(); // sortOrder
+	}
+#endif
+
+GLDEF_C TInt T_BenchClientThreadStart(TAny* aPtr)
+	{
+	TThreadCommandLine* comLine=STATIC_CAST(TThreadCommandLine*, aPtr);
+	RThread owningThread=comLine->iOwningThread;
+	TRequestStatus* initialStatus=comLine->iInitialStatus;
+	TRequestStatus* completionStatus=comLine->iCompletionStatus;
+	TFileName dbFileName=comLine->iDbFileName;
+	if (comLine->iExitAfterSort)
+		{
+		owningThread.RequestComplete(initialStatus,KErrNone);
+		}
+
+	__UHEAP_MARK;
+	TInt err;
+	CActiveScheduler* scheduler=new CActiveScheduler;
+	if (scheduler)
+		{
+		CActiveScheduler::Install(scheduler);
+		CTrapCleanup* cleanup=CTrapCleanup::New();
+		if (cleanup)
+			{
+			CContactDatabase* db=NULL;
+#ifdef __USE_NEW_INTERFACES
+			RContactView sortedIdList;
+			TRAP(err,
+				db=CContactDatabase::OpenL(dbFileName);
+				User::LeaveIfError(sortedIdList.Open(*db));
+				);
+#else
+			TRAP(err,
+				db=CContactDatabase::OpenL(dbFileName);
+				DoSortL(*db);
+				);
+#endif
+			if (!comLine->iExitAfterSort)
+				{
+				owningThread.RequestComplete(initialStatus,KErrNone);
+				CActiveScheduler::Start();
+				}
+#ifdef __USE_NEW_INTERFACES
+			sortedIdList.Close();
+#endif
+			delete db;
+			delete cleanup;
+			}
+		else
+			{
+			err=KErrNoMemory;
+			}
+		delete scheduler;
+		}
+	else
+		{
+		err=KErrNoMemory;
+		}
+	__UHEAP_MARKEND;
+
+	if (comLine->iExitAfterSort)
+		{
+		owningThread.RequestComplete(completionStatus,err);
+		}
+	owningThread.Close();
+	return KErrNone;
+	}
+
+void CBenchMarker::CreateSecondaryClients()
+	{
+	// Create a set of client threads.
+	for (TInt ii=0;ii<KNumSecondaryClients;++ii)
+		{
+		TRequestStatus initialStatus(KRequestPending);
+		TThreadCommandLine comLine(&initialStatus,NULL,iDbFileName,EFalse);
+		TBuf<32> threadName;
+		threadName.Format(KThreadNameFormat,ii);
+		secondaryClient[ii].Create(threadName,T_BenchClientThreadStart,KClientStackSize,KClientHeapSize,KClientHeapSize,&comLine);
+		comLine.iOwningThread.Duplicate(secondaryClient[ii]);
+		secondaryClient[ii].Resume();
+		User::WaitForRequest(initialStatus);
+		}
+	}
+
+void CBenchMarker::CloseSecondaryClients()
+	{
+	for (TInt ii=0;ii<KNumSecondaryClients;++ii)
+		{
+		secondaryClient[ii].Kill(KErrNone);
+		secondaryClient[ii].Close();
+		}
+	}
+
+void CBenchMarker::CreateSortClients()
+	{
+	TRequestStatus completionStatus[KNumSortClients];
+
+	// Create a set of client threads.
+	for (TInt ii=0;ii<KNumSortClients;++ii)
+		{
+		completionStatus[ii]=KRequestPending;
+		TRequestStatus initialStatus(KRequestPending);
+		TThreadCommandLine comLine(&initialStatus,&(completionStatus[ii]),iDbFileName,ETrue);
+		RThread thread;
+		TBuf<32> threadName;
+		threadName.Format(KThreadNameFormat,ii);
+		thread.Create(threadName,T_BenchClientThreadStart,KClientStackSize,KClientHeapSize,KClientHeapSize,&comLine);
+		comLine.iOwningThread.Duplicate(thread);
+		thread.Resume();
+		thread.Close();
+		User::WaitForRequest(initialStatus);
+		}
+
+	// Wait for all the clients to finish.
+	TBool moreClientsToComplete;
+	TInt numWaits=-1;
+	do
+		{
+		++numWaits;
+		User::WaitForAnyRequest();
+		moreClientsToComplete=EFalse;
+		for (TInt ii=0;ii<KNumSortClients;++ii)
+			{
+			if (completionStatus[ii].Int()==KRequestPending)
+				{
+				moreClientsToComplete=ETrue;
+				break;
+				}
+			}
+		}
+		while (moreClientsToComplete);
+
+	while (numWaits<(KNumSortClients-1))
+		{
+		++numWaits;
+		User::WaitForAnyRequest();
+		}
+	}
+
+void CBenchMarker::IncVisualCounter()
+	{
+	TBuf<8> backSpaceBuf;
+
+	if (iVisualCounter>=0)
+		{
+		TInt numDigits=1;
+		TInt divisor=10;
+
+		FOREVER
+			{
+			if (iVisualCounter/divisor>0)
+				{
+				divisor*=10;
+				++numDigits;
+				}
+			else
+				{
+				break;
+				}
+			}
+
+		for (TInt ii=0;ii<numDigits;++ii)
+			{
+			backSpaceBuf.Append(KBackSpace);
+			}
+		}
+
+	iTest.Printf(KVisualCounterFormat,&backSpaceBuf,++iVisualCounter);
+	}
+
+void CBenchMarker::EndVisualCounter()
+	{
+	iTest.Printf(KNewLine);
+	iVisualCounter=-1;
+	}
+
+TInt CBenchMarker::DbFileSize()
+	{
+	TEntry dbEntry;
+	TInt err=iFs.Entry(iDbFileName,dbEntry);
+	if (err==KErrNone)
+		{
+		return dbEntry.iSize;
+		}
+
+	return err;
+	}
+
+void CBenchMarker::LogResult(TInt aMajorTestNum,TInt aMinorTestNum,const TDesC& aDescription,TInt aResult)
+	{
+	iLog->LogLine(KResultFormatTInt,aMajorTestNum,aMinorTestNum,&aDescription,aResult);
+	}
+
+void CBenchMarker::LogResult(TInt aMajorTestNum,TInt aMinorTestNum,const TDesC& aDescription,TReal aResult)
+	{
+	iLog->LogLine(KResultFormatTReal,aMajorTestNum,aMinorTestNum,&aDescription,aResult);
+	}
+
+
+//
+// Main.
+//
+
+GLDEF_C TInt E32Main()
+	{
+	RDebug::Print(_L("t_bench started"));
+	__UHEAP_MARK;
+	TBuf<256> commandLine;
+	User::CommandLine(commandLine);
+	
+	CActiveScheduler* scheduler=new CActiveScheduler;
+	if (scheduler)
+		{
+		CActiveScheduler::Install(scheduler);
+		CTrapCleanup* cleanup=CTrapCleanup::New();
+		if (cleanup)
+			{
+			CBenchMarker* benchMarker=new CBenchMarker();
+			if (benchMarker)
+				{
+				TRAPD(err,
+					benchMarker->ConstructL(commandLine);
+					benchMarker->RunL();
+					);
+				RDebug::Print(_L("t_bench finish with %d error"),err);
+				delete benchMarker;
+				}
+			delete cleanup;
+			}
+		delete scheduler;
+		}
+	__UHEAP_MARKEND;
+	return KErrNone;
+    }