// Copyright (c) 2005-2009 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:
// e32test\debug\t_btrace.cpp
// Overview:
// Tests generation of traces using the BTrace APIs
// and captuirng of these by BTRACE.LDD and BTRACEC.DLL.
// API Information:
// class BTrace
// class RBTrace
// BTrace0
// BTrace4
// BTrace8
// BTrace12
// BTraceN
// BTraceBig
// BTracePc0
// BTracePc4
// BTracePc8
// BTracePc12
// BTracePcN
// BTracePcBig
// BTraceContext0
// BTraceContext4
// BTraceContext8
// BTraceContext12
// BTraceContextN
// BTraceContextBig
// BTraceContextPc0
// BTraceContextPc4
// BTraceContextPc8
// BTraceContextPc12
// BTraceContextPcN
// BTraceContextPcBig
// 
//

#define __E32TEST_EXTENSION__
#include <e32test.h>
#include <e32svr.h>
#include <e32def.h>
#include <e32def_private.h>

#include "../../../kernel/eka/include/d32btrace.h"
#include "../../../kernel/eka/include/e32btrace.h"
#include "d_btrace.h"

#define __TRACE_LINE__()	test.Printf(_L("%d\n"),__LINE__)

RTest test(_L("T_BTRACE"));

TUint BaseSize;		// Size of a standard test trace with no data

RBTrace Trace;
RBTraceTest TraceTest;

TInt ContextOffset(const TUint8* aData)
	{
	TInt size = 4; // header size
	if(aData[BTrace::EFlagsIndex]&BTrace::EHeader2Present)
		size += 4;
	if(aData[BTrace::EFlagsIndex]&BTrace::ETimestampPresent)
		size += 4;
	if(aData[BTrace::EFlagsIndex]&BTrace::ETimestamp2Present)
		size += 4;
	return size;
	}


TInt ExtraSize(const TUint8* aData)
	{
	TInt size = ContextOffset(aData);
	if(aData[BTrace::EFlagsIndex]&BTrace::EContextIdPresent)
		size += 4;
	if(aData[BTrace::EFlagsIndex]&BTrace::EPcPresent)
		size += 4;
	if(aData[BTrace::EFlagsIndex]&BTrace::EExtraPresent)
		size += 4;
	return size;
	}


TUint32* Body(const TUint8* aData)
	{
	return (TUint32*)(aData+ExtraSize(aData));
	}


TPtrC8 Text(const TUint8* aData)
	{
	TInt size = aData[BTrace::ESizeIndex];
	TInt extra = ExtraSize(aData);
	extra += 8; // skip past first 2 32bit args
	size -= extra;
	return TPtrC8(aData+extra,size);
	}


const TUint KTest1SubCategory = 0x81;
const TUint KTest2SubCategory = 0xc3;

TUint8 KTestTrace1[KMaxBTraceRecordSize*2] = { BTrace::ETest1, KTest1SubCategory };
TUint8 KTestTrace2[KMaxBTraceRecordSize*2] = { BTrace::ETest2, KTest2SubCategory };
TUint32 BigFilter2[KNumBTraceFilterTestUids];

void Trace1(TInt aSize, TInt aDelay=0)
	{
	test_KErrNone(TraceTest.Trace(0,KTestTrace1,aSize,aDelay));
	}

void Trace2(TInt aSize, TInt aDelay=0)
	{
	test_KErrNone(TraceTest.Trace(0,KTestTrace2,aSize,aDelay));
	}

TBool CheckTrace1(TUint8* aData, TInt aSize, TInt aSubCategory=KTest1SubCategory)
	{
	if(((aData[BTrace::ESizeIndex]+3)&~3)!=aSize)
		return EFalse;
	if(aData[BTrace::ECategoryIndex]!=BTrace::ETest1)
		return EFalse;
	if(aData[BTrace::ESubCategoryIndex]!=aSubCategory)
		return EFalse;
	TInt extra = ExtraSize(aData);
	aSize = aData[BTrace::ESizeIndex]-extra;
	aData += extra;
	while(--aSize>=0)
		{
		if(((TUint8*)KTestTrace1)[4+aSize]!=aData[aSize])
			return EFalse;
		}
	return ETrue;
	}

TBool CheckTrace2(TUint8* aData, TInt aSize, TInt aSubCategory=KTest2SubCategory)
	{
	if(((aData[BTrace::ESizeIndex]+3)&~3)!=aSize)
		return EFalse;
	if(aData[BTrace::ECategoryIndex]!=BTrace::ETest2)
		return EFalse;
	if(aData[BTrace::ESubCategoryIndex]!=aSubCategory)
		return EFalse;
	TInt extra = ExtraSize(aData);
	aSize = aData[BTrace::ESizeIndex]-extra;
	aData += extra;
	while(--aSize>=0)
		{
		if(((TUint8*)KTestTrace2)[4+aSize]!=aData[aSize])
			return EFalse;
		}
	return ETrue;
	}


TBool CheckSize(const TUint8* aData, TInt aSize, TInt aExpected)
	{
	TInt extra = ExtraSize(aData);
	if(aSize==((extra+aExpected+3)&~3))
		return 1;
	else
		{
		TInt actual_size = aData[0];
		if (aSize > actual_size)
			actual_size = aSize;
		test.Printf(_L("Trace data:\n"));
		TInt i;
		for (i=0; i<actual_size; ++i)
			{
			test.Printf(_L(" %02x"), aData[i]);
			if ((i&15)==15 || i==actual_size-1)
				test.Printf(_L("\n"));
			}
		test.Printf(_L("extra=%d aExp=%d aSize=%d\n"), extra, aExpected, aSize);
		return 0;
		}
	}


TInt Trace1Sequence = 0;
TInt Trace2Sequence = 0;

TUint8* TraceData;
TInt TraceDataSize;

TInt BadTrace(TUint8* aData)
	{
	Trace.SetMode(0);
	TUint8* buffer = Trace.DataChunk().Base();
	test.Printf(_L("BAD TRACE: data=%x buffer=%x (dataRead=%x,%x)\n"),aData,buffer,TraceData,TraceDataSize);
	TUint8* bufferEnd =  buffer+((TUint32*)buffer)[1]; // TBTraceBuffer.iEnd
	while(buffer<bufferEnd)
		{
		RDebug::Printf("%08x  %02x %02x %02x %02x  %02x %02x %02x %02x  %02x %02x %02x %02x  %02x %02x %02x %02x",
			buffer,buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6],buffer[7],
			buffer[8],buffer[9],buffer[10],buffer[11],buffer[12],buffer[13],buffer[14],buffer[15]);
		buffer += 16;
		}
	buffer = Trace.DataChunk().Base();
	TInt size = ((TUint32*)buffer)[9];
	buffer += ((TUint32*)buffer)[8];
	bufferEnd = buffer+size;
	test.Printf(_L("copyBuffer=%x\n"),buffer,0);
	while(buffer<bufferEnd)
		{
		RDebug::Printf("%08x  %02x %02x %02x %02x  %02x %02x %02x %02x  %02x %02x %02x %02x  %02x %02x %02x %02x",
			buffer,buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6],buffer[7],
			buffer[8],buffer[9],buffer[10],buffer[11],buffer[12],buffer[13],buffer[14],buffer[15]);
		buffer += 16;
		}
	return 0;
	}

void CheckTraceData(TUint8* aData, TUint aSize)
	{
	TraceData = aData;
	TraceDataSize = aSize;
	TUint8* end = aData+aSize;
	while(aData<end)
		{
		TUint size = (aData[BTrace::ESizeIndex]+3)&~3;
		if(aData+size>end)
			test(BadTrace(aData));
		TUint subCategory = aData[BTrace::ESubCategoryIndex];
		if(aData[BTrace::EFlagsIndex]&(BTrace::EMissingRecord))
			{
			Trace1Sequence = -1;
			Trace2Sequence = -1;
			}
		if(aData[BTrace::ECategoryIndex]==BTrace::ETest1)
			{
			if(subCategory!=(TUint)Trace1Sequence && Trace1Sequence!=-1)
				{
				test.Printf(_L("Sequence wrong %02x!=%02x\n"),subCategory,Trace1Sequence);
				test(BadTrace(aData));
				}
			if(!CheckTrace1(aData,size,subCategory))
				test(BadTrace(aData));
			Trace1Sequence = subCategory+1;
			Trace1Sequence &= 0xff;
			}
		else
			{
			if(aData[BTrace::ECategoryIndex]!=BTrace::ETest2)
				test(BadTrace(aData));
			if(subCategory!=(TUint)Trace2Sequence && Trace2Sequence!=-1)
				{
				test.Printf(_L("Sequence wrong %02x!=%02x\n"),subCategory,Trace2Sequence);
				test(BadTrace(aData));
				}
			if(!CheckTrace2(aData,size,subCategory))
				test(BadTrace(aData));
			Trace2Sequence = subCategory+1;
			Trace2Sequence &= 0xff;
			}
		aData = BTrace::NextRecord(aData);
		}
	}


void DumpTrace()
	{
	TBuf8<(80+KMaxBTraceDataArray*9/4)*2> buf;
	for(;;)
		{
		TUint8* record;
		TInt dataSize = Trace.GetData(record);
		if(!dataSize)
			break;
		TUint8* end = record+dataSize;
		while(record<end)
			{
			TUint size = record[BTrace::ESizeIndex];
			TUint flags = record[BTrace::EFlagsIndex];
			TUint category = record[BTrace::ECategoryIndex];
			TUint subCategory = record[BTrace::ESubCategoryIndex];
			TUint8* data = record+4;
			size -= 4;

			buf.Zero();
			TUint32 header2 = 0;
			if(flags&(BTrace::EHeader2Present))
				{
				header2 = *(TUint32*)data;
				data += 4;
				size -= 4;
				}

			if((flags&(BTrace::ETimestampPresent|BTrace::ETimestamp2Present))==(BTrace::ETimestampPresent|BTrace::ETimestamp2Present))
				{
				buf.AppendFormat(_L8("time:%08x:%08x "),((TUint32*)data)[1],*(TUint32*)data);
				data += 8;
				size -= 8;
				}
			else if(flags&(BTrace::ETimestampPresent|BTrace::ETimestamp2Present))
				{
				buf.AppendFormat(_L8("time:%08x "),*(TUint32*)data);
				data += 4;
				size -= 4;
				}

			if(flags&(BTrace::EContextIdPresent))
				{
				buf.AppendFormat(_L8("context:%08x "),*(TUint32*)data);
				data += 4;
				size -= 4;
				}
			else
				{
				buf.AppendFormat(_L8("                 "));
				}

			if(flags&(BTrace::EPcPresent))
				{
				buf.AppendFormat(_L8("pc:%08x "),*(TUint32*)data);
				data += 4;
				size -= 4;
				}

			TUint32 extra = 0;
			if(flags&(BTrace::EExtraPresent))
				{
				extra = *(TUint32*)data;
				data += 4;
				size -= 4;
				}

			TUint32 data0 = (size>0) ? *(TUint32*)(data) : 0;
			TUint32 data1 = (size>4) ? *(TUint32*)(data+4) : 0;
			TUint32 data2 = (size>8) ? *(TUint32*)(data+8) : 0;
			TPtrC8 des(0,0);
			if(size>=8)
				des.Set(data+8,size-8);
			switch(category)
				{
			case BTrace::EKernPrintf:
			case BTrace::ERDebugPrintf:
			case BTrace::EPlatsecPrintf:
				{
				if(category==BTrace::EKernPrintf)
					buf.Append(_L8("Kern::Printf "));
				else if(category==BTrace::ERDebugPrintf)
					buf.Append(_L8("RDebug::Printf "));
				else
					buf.Append(_L8("PlatSecPrintf "));
				switch(header2&BTrace::EMultipartFlagMask)
					{
					case BTrace::EMultipartFirst:
						buf.AppendFormat(_L8("seq:%d size:%d thread-id:%d \"%S\""),extra,data0,data1,&des);
						break;
					case BTrace::EMultipartMiddle:
					case BTrace::EMultipartLast:
						buf.AppendFormat(_L8("seq:%d size:%d offset:%d \"%S\""),extra,data0,data1,&des);
						break;
					default:
						des.Set(data+4,size-4);
						buf.AppendFormat(_L8("thread-id:%d \"%S\""),data0,&des);
						break;
						}
				}
				break;

			case BTrace::EThreadIdentification:
				{
				switch(subCategory)
					{
				case BTrace::ENanoThreadCreate:
					buf.AppendFormat(_L8("NanoThreadCreate  thrd:%08x"),data0);
					break;
				case BTrace::ENanoThreadDestroy:
					buf.AppendFormat(_L8("NanoThreadDestroy thrd:%08x"),data0);
					break;
				case BTrace::EThreadCreate:
					buf.AppendFormat(_L8("ThreadCreate      thrd:%08x proc:%08x name:%S"),data0,data1,&des);
					break;
				case BTrace::EThreadDestroy:
					buf.AppendFormat(_L8("ThreadDestroy     thrd:%08x proc:%08x id:%d"),data0,data1,data2);
					break;
				case BTrace::EThreadName:
					buf.AppendFormat(_L8("ThreadName        thrd:%08x proc:%08x name:%S"),data0,data1,&des);
					break;
				case BTrace::EThreadId:
					buf.AppendFormat(_L8("ThreadId          thrd:%08x proc:%08x id:%d"),data0,data1,data2);
					break;
				case BTrace::EProcessName:
					buf.AppendFormat(_L8("ProcessName       thrd:%08x proc:%08x name:%S"),data0,data1,&des);
					break;
					}
				}
				break;

			case BTrace::ECpuUsage:
				{
				switch(subCategory)
					{
				case BTrace::EIrqStart:
					buf.AppendFormat(_L8("IrqStart"));
					break;
				case BTrace::EIrqEnd:
					buf.AppendFormat(_L8("IrqEnd"));
					break;
				case BTrace::EFiqStart:
					buf.AppendFormat(_L8("FiqStart"));
					break;
				case BTrace::EFiqEnd:
					buf.AppendFormat(_L8("FiqEnd"));
					break;
				case BTrace::EIDFCStart:
					buf.AppendFormat(_L8("IDFCStart"));
					break;
				case BTrace::EIDFCEnd:
					buf.AppendFormat(_L8("IDFCEnd"));
					break;
				case BTrace::ENewThreadContext:
					buf.AppendFormat(_L8("NewThreadContext"));
					break;
					}
				break;
				}

			case BTrace::EClientServer:
				{
				switch(subCategory)
					{
				case BTrace::EServerCreate:
					buf.AppendFormat(_L8("EServerCreate     serv:%08x name:%S"),data0,&des);
					break;
				case BTrace::EServerDestroy:
					buf.AppendFormat(_L8("EServerDestroy    serv:%08x"),data0);
					break;
				case BTrace::ESessionAttach:
					buf.AppendFormat(_L8("ESessionAttach    sess:%08x serv:%08x"),data0,data1);
					break;
				case BTrace::ESessionDetach:
					buf.AppendFormat(_L8("ESessionDetach    sess:%08x"),data0);
					break;
				case BTrace::EMessageSend:
					buf.AppendFormat(_L8("EMessageSend      mess:%08x func:%08x sess:%08x"),data0,data1,data2);
					break;
				case BTrace::EMessageReceive:
					buf.AppendFormat(_L8("EMessageReceive   mess:%08x"),data0);
					break;
				case BTrace::EMessageComplete:
					buf.AppendFormat(_L8("EMessageComplete  mess:%08x reas:%08x"),data0,data1);
					break;
					}
				break;
				}

			case BTrace::ERequests:
				{
				switch(subCategory)
					{
				case BTrace::ERequestComplete:
					buf.AppendFormat(_L8("ERequestComplete  thrd:%08x stat:%08x resn:%08x"),data0,data1,data2);
					break;
					}
				break;
				}

			default:
				{
				buf.AppendFormat(_L8("size:%d flags:%02x cat:%d,%d data: "),size,flags,category,subCategory);
				for(TUint i=0; i<size; i+=4)
					buf.AppendFormat(_L8("%08x "),*(TUint32*)(data+i));
				}
				break;
				}
			buf.Append('\r');
			buf.Append('\n');
			RDebug::RawPrint(buf.Expand());

			record = BTrace::NextRecord(record);
			}
		Trace.DataUsed();
		}
	}


//---------------------------------------------
//! @SYMTestCaseID KBASE-T_BTRACE-0058-0059
//! @SYMTestType UT
//! @SYMPREQ PREQ1030
//! @SYMTestCaseDesc Basic functionality tests which run in both 'sample' and 'free-running' modes.
//! @SYMTestActions Test basic functionality provided by the functions:
//!		RBTrace::SetFilter(), RBTrace::Empty(),
//!		RBTrace::GetData(), RBTrace::DataUsed(),
//!		RBTrace::RequestData(), RBTrace::CancelRequestData(),
//!		RBTrace::BufferSize(), and RBTrace::ResizeBuffer()
//! @SYMTestExpectedResults Function produce expected results.
//! @SYMTestPriority High
//! @SYMTestStatus Implemented
//---------------------------------------------
void TestBasics(TUint aMode)
	{
	aMode |= RBTrace::EEnable;

	TUint8* data;
	TInt size;

	test.Start(_L("Check a second Open() fails"));
	RBTrace dummy;
	TInt r = dummy.Open();
	test_Equal(KErrInUse,r);
	r = dummy.Open();
	test_Equal(KErrInUse,r);

	test.Next(_L("Reset trace buffer"));
	Trace.SetMode(0);
	Trace.Empty();
	Trace.SetMode(aMode);

	TUint8* buffer_base = Trace.DataChunk().Base();
	test.Printf(_L("Buffer base %08x\n"), buffer_base);

	test.Next(_L("Test SetFilter() and GetData()"));
	Trace.SetFilter(BTrace::ETest1,0);
	Trace.SetFilter(BTrace::ETest2,0);
	size = Trace.GetData(data);
	test_Equal(0,size);
	Trace1(4);
	size = Trace.GetData(data);
	test_Equal(0,size);
	Trace2(4);
	size = Trace.GetData(data);
	test_Equal(0,size);
	Trace.SetFilter(BTrace::ETest1,1);
	Trace2(4);
	size = Trace.GetData(data);
	test_Equal(0,size);
	Trace1(4);
	size = Trace.GetData(data);
	test(CheckSize(data,size,4));
	BaseSize = size - 4;
	test.Printf(_L("BaseSize=%d\n"), BaseSize);

	test.Next(_L("Test Empty()"));
	Trace.Empty();
	size = Trace.GetData(data);
	test_Equal(0,size);

	test.Next(_L("Test DataUsed()"));
	Trace1(0);
	size = Trace.GetData(data);
	test(CheckSize(data,size,0));
	Trace.DataUsed();
	size = Trace.GetData(data);
	test_Equal(0,size);

	test.Next(_L("Test RequestData()"));
	TRequestStatus s1;
	TRequestStatus s2;
	RTimer timer;
	test_KErrNone(timer.CreateLocal());

	// immediate notification...
	Trace.RequestData(s1,0);
	test_Equal(KRequestPending, s1.Int());
	timer.After(s2,5*1000000);
	Trace1(4);
	User::WaitForRequest(s1,s2);
	test_KErrNone(s1.Int());
	timer.Cancel();
	User::WaitForRequest(s2);

	// immediate notification with size>n ...
	Trace.RequestData(s1,BaseSize+8);
	test_Equal(KRequestPending,s1.Int());
	timer.After(s2,5*1000000);
	Trace1(20);
	User::WaitForRequest(s1,s2);
	test_KErrNone(s1.Int());
	timer.Cancel();
	User::WaitForRequest(s2);

	size = Trace.GetData(data);
	test_Compare(size, >= , BaseSize+8);
	Trace.DataUsed();
	size = Trace.GetData(data);
	test_Equal(0,size);

	// delayed notification...
	Trace.RequestData(s1,0);
	timer.After(s2,5*1000000);
	Trace1(4,500000);
	test_Equal(KRequestPending,s1.Int());
	User::WaitForRequest(s1,s2);
	test_KErrNone(s1.Int());
	timer.Cancel();
	User::WaitForRequest(s2);
	size = Trace.GetData(data);
	test(CheckSize(data,size,4));
	Trace.DataUsed();

	// delayed notification with size>n...
	Trace.RequestData(s1,BaseSize+8);
	Trace1(4,500000);
	test_Equal(KRequestPending,s1.Int());
	timer.After(s2,1000000);
	User::WaitForRequest(s1,s2);
	test_KErrNone(s2.Int());
	timer.After(s2,5*1000000);
	Trace1(20,500000);
	test_Equal(KRequestPending,s1.Int());
	User::WaitForRequest(s1,s2);
	test_KErrNone(s1.Int());
	timer.Cancel();
	User::WaitForRequest(s2);

	size = Trace.GetData(data);
	test_Compare(size, >=, BaseSize+8);
	Trace.DataUsed();
	size = Trace.GetData(data);
	test_Equal(0,size);

	test.Next(_L("Test RequestData() when data is already available"));
	Trace1(4);
	Trace.RequestData(s1,0);
	test_KErrNone(s1.Int());
	User::WaitForRequest(s1);
	size = Trace.GetData(data);
	test(CheckSize(data,size,4));
	Trace.DataUsed();
	size = Trace.GetData(data);
	test_Equal(0,size);

	Trace1(4);
	Trace.RequestData(s1,1);
	test_KErrNone(s1.Int());
	User::WaitForRequest(s1);
	size = Trace.GetData(data);
	test(CheckSize(data,size,4));
	Trace.DataUsed();
	size = Trace.GetData(data);
	test_Equal(0,size);

	test.Next(_L("Test RequestData() for ISR disabled traces"));
	Trace.RequestData(s1,0);
	test_Equal(KRequestPending,s1.Int());
	timer.After(s2,5*1000000);
	TraceTest.Trace(RBTraceTest::EContextIntsOff,KTestTrace1,4);
	User::WaitForRequest(s1,s2);
	test_KErrNone(s1.Int());
	timer.Cancel();
	User::WaitForRequest(s2);
	size = Trace.GetData(data);
	test(CheckSize(data,size,4));
	Trace.DataUsed();
	size = Trace.GetData(data);
	test_Equal(0,size);

	test.Next(_L("Test CancelRequestData()"));
	Trace.RequestData(s1,0);
	test_Equal(KRequestPending,s1.Int());
	Trace.CancelRequestData();
	User::WaitForRequest(s1);
	test_Equal(KErrCancel,s1.Int());

	test.Next(_L("Test trace data contents"));
	Trace1(0);
	size = Trace.GetData(data);
	test(CheckSize(data,size,0));
 	test(CheckTrace1(data,size));
	if(data[BTrace::EFlagsIndex]&BTrace::ETimestampPresent)
		test.Printf(_L("Timestamps are present\n"));
	else
		test.Printf(_L("Timestamps are NOT present\n"));
	Trace.DataUsed();

	Trace1(4);
	size = Trace.GetData(data);
	test(CheckSize(data,size,4));
	test(CheckTrace1(data,size));
	Trace.DataUsed();

	TInt i;
	for(i=0; i<=8+(TInt)KMaxBTraceDataArray; i++)
		{
		Trace1(i);
		size = Trace.GetData(data);
		test(CheckSize(data,size,i));
		test(CheckTrace1(data,size));
		Trace.DataUsed();
		}
	Trace1(i);
	size = Trace.GetData(data);
	test(data[BTrace::EFlagsIndex]&BTrace::ERecordTruncated);
	test(CheckSize(data,size,i-1));
	test(CheckTrace1(data,size));
	Trace.DataUsed();

	test.Next(_L("Test BufferSize() and ResizeBuffer()"));
	TInt oldSize = Trace.BufferSize();
	Trace1(50);
	size = Trace.GetData(data);
	test(CheckSize(data,size,50));
	r = Trace.ResizeBuffer(oldSize+0x1000);
	test_KErrNone(r);
	size = Trace.BufferSize();
	test_Equal(oldSize+0x1000,size);
	Trace.SetMode(aMode);
	size = Trace.GetData(data);
	test_Equal(0,size);
	Trace1(40);
	size = Trace.GetData(data);
	test(CheckSize(data,size,40));
	Trace.DataUsed();
	r = Trace.ResizeBuffer(oldSize);
	test_KErrNone(r);
	size = Trace.BufferSize();
	test_Equal(oldSize,size);

	test.End();
	}




//---------------------------------------------
//! @SYMTestCaseID KBASE-T_BTRACE-0060
//! @SYMTestType UT
//! @SYMPREQ PREQ1030
//! @SYMTestCaseDesc Test traces generated from user code.
//! @SYMTestActions Generate traces using BTrace0, BTrace4, BTrace8, BTrace12,
//!		and BTraceN macros.
//! @SYMTestExpectedResults All trace contents captured by RBTrace match those specified
//!		at point of trace generation.
//! @SYMTestPriority High
//! @SYMTestStatus Implemented
//---------------------------------------------
void TestUserTrace(TUint aMode)
	{
	aMode |= RBTrace::EEnable;

	TUint8* data;
	TInt size;

	test.Start(_L("Reset trace buffer"));
	Trace.SetMode(0);
	Trace.Empty();
	Trace.SetMode(RBTrace::EEnable);
	Trace.SetFilter(BTrace::ETest1,1);
	Trace.SetFilter(BTrace::ETest2,0);

	test.Next(_L("BTrace0"));
	BTrace0(BTrace::ETest1,KTest1SubCategory);
	size = Trace.GetData(data);
	test(CheckSize(data,size,0));
	test(CheckTrace1(data,size));
	Trace.DataUsed();

	test.Next(_L("BTrace4"));
	BTrace4(BTrace::ETest1,KTest1SubCategory,*(TUint32*)(KTestTrace1+4));
	size = Trace.GetData(data);
	test(CheckSize(data,size,4));
	test(CheckTrace1(data,size));
	Trace.DataUsed();

	test.Next(_L("BTrace8"));
	BTrace8(BTrace::ETest1,KTest1SubCategory,*(TUint32*)(KTestTrace1+4),*(TUint32*)(KTestTrace1+8));
	size = Trace.GetData(data);
	test(CheckSize(data,size,8));
	test(CheckTrace1(data,size));
	Trace.DataUsed();

	test.Next(_L("BTrace12"));
	BTrace12(BTrace::ETest1,KTest1SubCategory,*(TUint32*)(KTestTrace1+4),*(TUint32*)(KTestTrace1+8),*(TUint32*)(KTestTrace1+12));
	size = Trace.GetData(data);
	test(CheckSize(data,size,12));
	test(CheckTrace1(data,size));
	Trace.DataUsed();

	test.Next(_L("BTraceN"));
	TInt i;
	for(i=8; i<=8+(TInt)KMaxBTraceDataArray; i++)
		{
		BTraceN(BTrace::ETest1,KTest1SubCategory,*(TUint32*)(KTestTrace1+4),*(TUint32*)(KTestTrace1+8),KTestTrace1+12,i-8);
		size = Trace.GetData(data);
		test(CheckSize(data,size,i));
		test(CheckTrace1(data,size));
		Trace.DataUsed();
		}
	BTraceN(BTrace::ETest1,KTest1SubCategory,*(TUint32*)(KTestTrace1+4),*(TUint32*)(KTestTrace1+8),KTestTrace1+12,i-8);
	size = Trace.GetData(data);
	test(data[BTrace::EFlagsIndex]&BTrace::ERecordTruncated);
	test(CheckSize(data,size,i-1));
	test(CheckTrace1(data,size));
	Trace.DataUsed();

	test.End();
	}


TBool CompareFilter2(const TUint32* aUids, TInt aNumUids, TInt aGlobalFilter)
	{
	TUint32* filter2Buffer = (TUint32*)-1; // initialise to invalid value
	TInt filter2Global = 0x80000000; // initialise to invalid value
	TInt filter2Size = Trace.Filter2(filter2Buffer,filter2Global);

	TBool pass = ETrue;
	if(filter2Size!=aNumUids)
		pass = EFalse;
	else if(filter2Global!=aGlobalFilter)
		pass = EFalse;
	else if(0!=Mem::Compare((TUint8*)filter2Buffer,filter2Size,(TUint8*)aUids,aNumUids))
		pass = EFalse;

	delete filter2Buffer;
	return pass;
	}


void TestFilter2()
	{
	test.Start(_L("Get filter2"));
	TUint32* filter2Buffer = (TUint32*)-1; // initialise to invalid value
	TInt filter2Global = 0x80000000; // initialise to invalid value
	TInt filter2Size = Trace.Filter2(filter2Buffer,filter2Global);
	test_NotNegative(filter2Size);
	test_Compare(filter2Buffer, != , (TUint32*)-1);
	test_Compare(filter2Global, != , -1);
	test(CompareFilter2(filter2Buffer,filter2Size,filter2Global));
	Trace.SetFilter(BTrace::ETest1,1);
	TInt r;

	test.Next(_L("Clear filter2"));
	r = Trace.SetFilter2((TUint32*)0,0);
	test_KErrNone(r);
	Trace.SetFilter2(0);
	test(CompareFilter2(0,0,0));

#ifdef _DEBUG
	test.Next(_L("Check SetFilter2's 'New' fails gracefully"));
	__KHEAP_FAILNEXT(1);

	r = Trace.SetFilter2(KBTraceFilterTestUid1,1);
	test_Equal(KErrNoMemory, r);

	__KHEAP_RESET;
#endif

	test.Next(_L("Test set and clear single uid"));
	r = Trace.SetFilter2(KBTraceFilterTestUid1,0);
	test_KErrNone(r);
	test(CompareFilter2(0,0,0));
	r = Trace.SetFilter2(KBTraceFilterTestUid1,1);
	test_KErrNone(r);
	test(CompareFilter2(&KBTraceFilterTestUid1,1,-1));
	r = Trace.SetFilter2(KBTraceFilterTestUid1,0);
	test_Equal(1,r);
	test(CompareFilter2(0,0,0));

	test.Next(_L("Test set multiple uid API"));
	r = Trace.SetFilter2(&KBTraceFilterTestUid1,1);
	test_KErrNone(r);
	test(CompareFilter2(&KBTraceFilterTestUid1,1,-1));
	r = Trace.SetFilter2(KBTraceFilterTestUid1,0);
	test_Equal(1,r);
	test(CompareFilter2(0,0,0));

	test.Next(_L("Test set and clear uids with lots of permutations"));
	TInt itterations = 0;
	const TInt maxUids = 5;
	TInt permute[maxUids] = {0};
	TInt numUids;
	RArray<TUint32> sortedArray(maxUids);
	RArray<TUint32> array(maxUids);
	for(numUids=1; numUids<=maxUids; ++numUids)
		{
		TInt p=0;
		do
			{
			++itterations;
			if(itterations==-1)
				__BREAKPOINT(); // debuging breakpoint for a specific itteration

			// make arrays of uids
			sortedArray.Reset();
			array.Reset();
			TInt i;
			for(i=0; i<numUids; ++i)
				{
				sortedArray.InsertInUnsignedKeyOrder(KBTraceFilterTestUid+permute[i]);
				array.Append(KBTraceFilterTestUid+permute[i]);
				}

			// set filter using single uid api...
			Trace.SetFilter2(0);
			for(i=0; i<numUids; ++i)
				{
				r = Trace.SetFilter2(KBTraceFilterTestUid+permute[i],1);
				test_NotNegative(r);
				}
			test(CompareFilter2(&sortedArray[0],sortedArray.Count(),-1));

			// set filter using multiple uid api...
			Trace.SetFilter2(0);
			r = Trace.SetFilter2(&array[0],array.Count());
			test_NotNegative(r);
			test(CompareFilter2(&sortedArray[0],sortedArray.Count(),-1));

			// remove uids...
			for(i=0; i<numUids; ++i)
				{
				TUint32 removedUid = KBTraceFilterTestUid+permute[i];
				TBool removed = EFalse;
				r = sortedArray.FindInUnsignedKeyOrder(removedUid);
				if(r>=0)
					{
					test(BTrace::CheckFilter2(BTrace::ETest1,removedUid));
					sortedArray.Remove(r);
					removed = ETrue;
					}
				r = Trace.SetFilter2(removedUid,0);
				test_NotNegative(r);
				if(removed)
					{
					test(!BTrace::CheckFilter2(BTrace::ETest1,removedUid));
					}
				r = sortedArray.Count();
				if(r)
					test(CompareFilter2(&sortedArray[0],r,-1));
				else
					{
					test(CompareFilter2(0,0,0));
					break;
					}
				}

			// make next permutation
			p=0;
			while(p<numUids && ++permute[p] == numUids)
				permute[p++] = 0;
			}
		while(p<numUids);
		}

	test.Next(_L("Test global filter"));
	Trace.SetFilter2(0);
	test(CompareFilter2(0,0,0));
	Trace.SetFilter2(1);
	test(CompareFilter2(0,0,1));
	r = Trace.SetFilter2(KBTraceFilterTestUid1,1);
	test_Equal(1,r);
	test(CompareFilter2(0,0,1));
	r = Trace.SetFilter2(KBTraceFilterTestUid1,0);
	test_Equal(KErrNotSupported,r);
	test(CompareFilter2(0,0,1));
	r = Trace.SetFilter2(&KBTraceFilterTestUid1,1);
	test_KErrNone(r);
	test(CompareFilter2(&KBTraceFilterTestUid1,1,-1));

	test.Next(_L("Restore filter2"));
	r = Trace.SetFilter2(filter2Buffer,filter2Size);
	test_KErrNone(r);
	Trace.SetFilter2(filter2Global);
	Trace.SetFilter(BTrace::ETest1,0);
	delete filter2Buffer;

	test.End();
	}

TUint32 ThisTraceContextId;

void TestTrace1(TUint aType,TInt aSize)
	{
	if(!(aType&RBTraceTest::EUserTrace))
		{
		// use driver to create a kernel trace...
		TraceTest.Trace(aType,KTestTrace1,aSize);
		return;
		}

	TInt size = aSize;
	TUint32* data = (TUint32*)KTestTrace1;
	BTrace::TCategory category = BTrace::ETest1;
	TUint subCategory = KTest1SubCategory;
	TUint type = aType&0xff;
	TBool bigTrace = aType&RBTraceTest::EBigTrace;
	TBool filter2Trace = aType&RBTraceTest::EFilter2Trace;

	if(!filter2Trace)
		{
		if(type==BTrace::EPcPresent)
			{
			if(bigTrace)
				{
				BTracePcBig(category,subCategory,data[1],data+2,size-4);
				BTracePcBig(category,subCategory,data[1],data+2,size-4);
				}
			else if(size==0)
				{
				BTracePc0(category,subCategory);
				BTracePc0(category,subCategory);
				}
			else if(size<=4)
				{
				BTracePc4(category,subCategory,data[1]);
				BTracePc4(category,subCategory,data[1]);
				}
			else if(size<=8)
				{
				BTracePc8(category,subCategory,data[1],data[2]);
				BTracePc8(category,subCategory,data[1],data[2]);
				}
			else
				{
				BTracePcN(category,subCategory,data[1],data[2],data+3,size-8);
				BTracePcN(category,subCategory,data[1],data[2],data+3,size-8);
				}
			}
		else if(type==BTrace::EContextIdPresent)
			{
			if(bigTrace)
				{
				BTraceContextBig(category,subCategory,data[1],data+2,size-4);
				BTraceContextBig(category,subCategory,data[1],data+2,size-4);
				}
			else if(size==0)
				{
				BTraceContext0(category,subCategory);
				BTraceContext0(category,subCategory);
				}
			else if(size<=4)
				{
				BTraceContext4(category,subCategory,data[1]);
				BTraceContext4(category,subCategory,data[1]);
				}
			else if(size<=8)
				{
				BTraceContext8(category,subCategory,data[1],data[2]);
				BTraceContext8(category,subCategory,data[1],data[2]);
				}
			else
				{
				BTraceContextN(category,subCategory,data[1],data[2],data+3,size-8);
				BTraceContextN(category,subCategory,data[1],data[2],data+3,size-8);
				}
			}
		else if(type==BTrace::EContextIdPresent+BTrace::EPcPresent)
			{
			if(bigTrace)
				{
				BTraceContextPcBig(category,subCategory,data[1],data+2,size-4);
				BTraceContextPcBig(category,subCategory,data[1],data+2,size-4);
				}
			else if(size==0)
				{
				BTraceContextPc0(category,subCategory);
				BTraceContextPc0(category,subCategory);
				}
			else if(size<=4)
				{
				BTraceContextPc4(category,subCategory,data[1]);
				BTraceContextPc4(category,subCategory,data[1]);
				}
			else if(size<=8)
				{
				BTraceContextPc8(category,subCategory,data[1],data[2]);
				BTraceContextPc8(category,subCategory,data[1],data[2]);
				}
			else
				{
				BTraceContextPcN(category,subCategory,data[1],data[2],data+3,size-8);
				BTraceContextPcN(category,subCategory,data[1],data[2],data+3,size-8);
				}
			}
		else
			{
			if(bigTrace)
				BTraceBig(category,subCategory,data[1],data+2,size-4);
			else if(size==0)
				BTrace0(category,subCategory);
			else if(size<=4)
				BTrace4(category,subCategory,data[1]);
			else if(size<8)
				BTrace8(category,subCategory,data[1],data[2]);
			else
				BTraceN(category,subCategory,data[1],data[2],data+3,size-8);
			}
		}
	else
		{
		if(type==BTrace::EPcPresent)
			{
			if(bigTrace)
				{
				BTraceFilteredPcBig(category,subCategory,data[1],data+2,size-4);
				BTraceFilteredPcBig(category,subCategory,data[1],data+2,size-4);
				}
			else if(size<4)
				{
				// invalid
				}
			else if(size==4)
				{
				BTraceFilteredPc4(category,subCategory,data[1]);
				BTraceFilteredPc4(category,subCategory,data[1]);
				}
			else if(size<=8)
				{
				BTraceFilteredPc8(category,subCategory,data[1],data[2]);
				BTraceFilteredPc8(category,subCategory,data[1],data[2]);
				}
			else
				{
				BTraceFilteredPcN(category,subCategory,data[1],data[2],data+3,size-8);
				BTraceFilteredPcN(category,subCategory,data[1],data[2],data+3,size-8);
				}
			}
		else if(type==BTrace::EContextIdPresent)
			{
			if(bigTrace)
				{
				BTraceFilteredContextBig(category,subCategory,data[1],data+2,size-4);
				BTraceFilteredContextBig(category,subCategory,data[1],data+2,size-4);
				}
			else if(size<4)
				{
				// invalid
				}
			else if(size==4)
				{
				BTraceFilteredContext4(category,subCategory,data[1]);
				BTraceFilteredContext4(category,subCategory,data[1]);
				}
			else if(size<=8)
				{
				BTraceFilteredContext8(category,subCategory,data[1],data[2]);
				BTraceFilteredContext8(category,subCategory,data[1],data[2]);
				}
			else
				{
				BTraceFilteredContextN(category,subCategory,data[1],data[2],data+3,size-8);
				BTraceFilteredContextN(category,subCategory,data[1],data[2],data+3,size-8);
				}
			}
		else if(type==BTrace::EContextIdPresent+BTrace::EPcPresent)
			{
			if(bigTrace)
				{
				BTraceFilteredContextPcBig(category,subCategory,data[1],data+2,size-4);
				BTraceFilteredContextPcBig(category,subCategory,data[1],data+2,size-4);
				}
			else if(size<4)
				{
				// invalid
				}
			else if(size==4)
				{
				BTraceFilteredContextPc4(category,subCategory,data[1]);
				BTraceFilteredContextPc4(category,subCategory,data[1]);
				}
			else if(size<=8)
				{
				BTraceFilteredContextPc8(category,subCategory,data[1],data[2]);
				BTraceFilteredContextPc8(category,subCategory,data[1],data[2]);
				}
			else
				{
				BTraceFilteredContextPcN(category,subCategory,data[1],data[2],data+3,size-8);
				BTraceFilteredContextPcN(category,subCategory,data[1],data[2],data+3,size-8);
				}
			}
		else
			{
			if(bigTrace)
				BTraceFilteredBig(category,subCategory,data[1],data+2,size-4);
			else if(size<4)
				{
				// invalid
				}
			else if(size==4)
				BTraceFiltered4(category,subCategory,data[1]);
			else if(size<8)
				BTraceFiltered8(category,subCategory,data[1],data[2]);
			else
				BTraceFilteredN(category,subCategory,data[1],data[2],data+3,size-8);
			}
		}
	}



//---------------------------------------------
//! @SYMTestCaseID KBASE-T_BTRACE-0062-0063
//! @SYMTestType UT
//! @SYMPREQ PREQ1030
//! @SYMTestCaseDesc Test traces which specify thread context and/or program counter values.
//! @SYMTestActions Generate traces from user and kernel code using the BTracePcX,
//!		BTraceContextX and BTraceContextPcX macros. Kernel traces are additionaly
//!		generated in ISR and IDFC context.
//! @SYMTestExpectedResults All trace contents captured by RBTrace match those specified
//!		at point of trace generation. Also, where appropriate, PC and/or Context ID values
//!		are present and correct.
//! @SYMTestPriority High
//! @SYMTestStatus Implemented
//---------------------------------------------
void TestTrace(TBool aUserTrace, TBool aFilter2)
	{
	test.Start(_L("Reset trace buffer"));
	TInt oldSize = Trace.BufferSize();
	TInt r = Trace.ResizeBuffer(0x100000);
	test_KErrNone(r);
	Trace.SetMode(RBTrace::EEnable);

	// dummy trace do get current thread context id
	Trace.SetFilter(BTrace::ETest1,0);
	ThisTraceContextId = TraceTest.Trace(BTrace::EContextIdPresent,KTestTrace1,0);

	// create a test filter...
	TInt extraFlags = 0;
	if(aUserTrace)
		extraFlags |= RBTraceTest::EUserTrace;
	TInt minSize = 0;
	if(aFilter2)
		{
		extraFlags |= RBTraceTest::EFilter2Trace;
		minSize += 4;
		}

	TInt filterMode;
	for(filterMode=0; filterMode<(aFilter2?6:2); ++filterMode)
		{

		// setup filters...
		Trace.SetFilter(BTrace::ETest1,1);
		Trace.SetFilter2(BigFilter2,KNumBTraceFilterTestUids);
		if(filterMode==0 || filterMode==2)
			Trace.SetFilter(BTrace::ETest1,0); // disable in primary filter
		if(filterMode==0 || filterMode==1)
			Trace.SetFilter2(KBTraceFilterTestUid1,0); // disable in secondary filter
		if(filterMode==4)
			Trace.SetFilter2(0); // disable entire secondary filter
		if(filterMode==5)
			Trace.SetFilter2(1); // enable entire secondary filter

		// expectTrace is true if we expect trace to be output...
		TBool expectTrace = aFilter2 ? (filterMode==3 || filterMode==5) : filterMode&1;

		switch(filterMode)
			{
		case 0: test.Next(_L("Test with primary filter OFF, secondary filter OFF")); break;
		case 1: test.Next(_L("Test with primary filter ON, secondary filter OFF")); break;
		case 2: test.Next(_L("Test with primary filter OFF, secondary filter ON")); break;
		case 3: test.Next(_L("Test with primary filter ON, secondary filter ON")); break;
		case 4: test.Next(_L("Test with primary filter ON, global secondary filter OFF")); break;
		case 5: test.Next(_L("Test with primary filter ON, global secondary filter ON")); break;
			}

		test.Start(_L("Traces without special context"));
		TInt i;
		for(i=minSize; i<=8+(TInt)KMaxBTraceDataArray; i++)
			{
			TestTrace1(extraFlags,i);

			TUint8* data;
			TInt size;
			size = Trace.GetData(data);
			if(!expectTrace)
				{
				test(!size);
				continue;
				}

			test(CheckSize(data,size,i));
			test(CheckTrace1(data,size,KTest1SubCategory));

			test(!(data[BTrace::EFlagsIndex]&BTrace::EContextIdPresent));
			test(!(data[BTrace::EFlagsIndex]&BTrace::EPcPresent));

			Trace.DataUsed();
			}

		test.Next(_L("Traces with PC"));
		for(i=minSize; i<=8+(TInt)KMaxBTraceDataArray; i++)
			{
			TestTrace1(BTrace::EPcPresent|extraFlags,i);

			TUint8* data;
			TUint8* data2;
			TInt size;
			size=Trace.GetData(data);
			if(!expectTrace)
				{
				test(!size);
				continue;
				}
			size /= 2;
			data2 = data+size;

			test(CheckSize(data,size,i));
			test(CheckTrace1(data,size,KTest1SubCategory));

			test(CheckSize(data2,size,i));
			test(CheckTrace1(data2,size,KTest1SubCategory));

			test(!(data[BTrace::EFlagsIndex]&BTrace::EContextIdPresent));
			test((data[BTrace::EFlagsIndex]&BTrace::EPcPresent));

			TInt offset = ContextOffset(data);
			test_Compare( ((TUint32*)(data+offset))[0], != ,((TUint32*)(data2+offset))[0]);

			Trace.DataUsed();
			}

		test.Next(_L("Traces with Context ID"));
		for(i=minSize; i<=8+(TInt)KMaxBTraceDataArray; i++)
			{
			TestTrace1(BTrace::EContextIdPresent|extraFlags,i);

			TUint8* data;
			TUint8* data2;
			TInt size;
			size=Trace.GetData(data);
			if(!expectTrace)
				{
				test(!size);
				continue;
				}
			size /= 2;
			data2 = data+size;

			test(CheckSize(data,size,i));
			test(CheckTrace1(data,size,KTest1SubCategory));

			test(CheckSize(data2,size,i));
			test(CheckTrace1(data2,size,KTest1SubCategory));

			test((data[BTrace::EFlagsIndex]&BTrace::EContextIdPresent));
			test(!(data[BTrace::EFlagsIndex]&BTrace::EPcPresent));

			TUint offset = ContextOffset(data);
			test_Equal(ThisTraceContextId, ((TUint32*)(data+offset))[0]);
			test_Equal(ThisTraceContextId, ((TUint32*)(data2+offset))[0]);
			Trace.DataUsed();
			}

		test.Next(_L("Traces with Context ID and PC"));
		for(i=minSize; i<=8+(TInt)KMaxBTraceDataArray; i++)
			{
			TestTrace1(BTrace::EContextIdPresent|BTrace::EPcPresent|extraFlags,i);

			TUint8* data;
			TUint8* data2;
			TInt size;
			size=Trace.GetData(data);
			if(!expectTrace)
				{
				test(!size);
				continue;
				}
			size /= 2;
			data2 = data+size;

			test(CheckSize(data,size,i));
			test(CheckTrace1(data,size,KTest1SubCategory));

			test(CheckSize(data2,size,i));
			test(CheckTrace1(data2,size,KTest1SubCategory));

			test((data[BTrace::EFlagsIndex]&BTrace::EContextIdPresent));
			test((data[BTrace::EFlagsIndex]&BTrace::EPcPresent));

			TUint offset = ContextOffset(data);

			test_Equal(ThisTraceContextId, ((TUint32*)(data+offset))[0]);
			test_Equal(ThisTraceContextId, ((TUint32*)(data2+offset))[0]);
			test_Compare( ((TUint32*)(data+offset))[1], != ,((TUint32*)(data2+offset))[1]);

			Trace.DataUsed();
			}

		if(!aUserTrace)
			{
			test.Next(_L("Traces with Context ID in ISR mode"));
			for(i=minSize; i<=8+(TInt)KMaxBTraceDataArray; i++)
				{
				TraceTest.Trace(BTrace::EContextIdPresent|RBTraceTest::EContextIsr|extraFlags,KTestTrace1,i);

				TUint8* data;
				TUint8* data2;
				TInt size;
				size=Trace.GetData(data);
				if(!expectTrace)
					{
					test(!size);
					continue;
					}
				size /= 2;
				data2 = data+size;

				test(CheckSize(data,size,i));
				test(CheckTrace1(data,size,KTest1SubCategory));

				test(CheckSize(data2,size,i));
				test(CheckTrace1(data2,size,KTest1SubCategory));

				test((data[BTrace::EFlagsIndex]&BTrace::EContextIdPresent));
				test(!(data[BTrace::EFlagsIndex]&BTrace::EPcPresent));

				TUint offset = ContextOffset(data);
				test( ((TUint32*)(data+offset))[0] == 2 );
				test( ((TUint32*)(data2+offset))[0] == 2 );

				Trace.DataUsed();
				}

			test.Next(_L("Traces with Context ID in IDFC mode"));
			for(i=minSize; i<=8+(TInt)KMaxBTraceDataArray; i++)
				{
				TraceTest.Trace(BTrace::EContextIdPresent|RBTraceTest::EContextIDFC|extraFlags,KTestTrace1,i);

				TUint8* data;
				TUint8* data2;
				TInt size;
				size=Trace.GetData(data);
				if(!expectTrace)
					{
					test(!size);
					continue;
					}
				size /= 2;
				data2 = data+size;

				test(CheckSize(data,size,i));
				test(CheckTrace1(data,size,KTest1SubCategory));

				test(CheckSize(data2,size,i));
				test(CheckTrace1(data2,size,KTest1SubCategory));

				test((data[BTrace::EFlagsIndex]&BTrace::EContextIdPresent));
				test(!(data[BTrace::EFlagsIndex]&BTrace::EPcPresent));

				TUint offset = ContextOffset(data);
				test( ((TUint32*)(data+offset))[0] == 3 );
				test( ((TUint32*)(data2+offset))[0] == 3 );

				Trace.DataUsed();
				}
			}
		test.End();
		r = Trace.ResizeBuffer(0x100000);	// avoid buffer wrap problems
		test_KErrNone(r);
		Trace.SetMode(RBTrace::EEnable);
		}

	test.Next(_L("Restore buffer"));
	r = Trace.ResizeBuffer(oldSize);
	test_KErrNone(r);
	Trace.SetFilter2(0);

	test.End();
	}


TUint32 BigTraceId = 0;

TBool BigTraceFirst = 0;
TBool BigTraceMiddle = 0;
TBool BigTraceEnd = 0;

void BigTraceBeginTest()
	{
	BigTraceFirst = 0;
	BigTraceMiddle = 0;
	BigTraceEnd = 0;
	}

TBool BigTraceEndTest()
	{
	return BigTraceFirst&&BigTraceMiddle&&BigTraceEnd;
	}

TBool DoCheckBigTrace1(TUint8*& aData, TUint32 aOutSize, TUint32& aOffset, TUint32 aExtraIds = 0)
	{
	TUint32* ptr = (TUint32*)aData;
	if(aData[BTrace::ECategoryIndex]!=BTrace::ETest1)
		return EFalse;
	if(aData[BTrace::ESubCategoryIndex]!=KTest1SubCategory)
		return EFalse;
//	TUint32 header = *ptr++;
	++ptr;

	if(aData[BTrace::EFlagsIndex]&BTrace::ERecordTruncated)
		return EFalse;

	if(!(aData[BTrace::EFlagsIndex]&BTrace::EHeader2Present))
		return EFalse;
	TUint32 header2 = *ptr++;
	if(aData[BTrace::EFlagsIndex]&BTrace::ETimestampPresent)
		++ptr;
	if(aData[BTrace::EFlagsIndex]&BTrace::ETimestamp2Present)
		++ptr;

	if(aData[BTrace::EFlagsIndex]&BTrace::EContextIdPresent)
		++ptr;
	if(aData[BTrace::EFlagsIndex]&BTrace::EPcPresent)
		++ptr;

	if(!(aData[BTrace::EFlagsIndex]&BTrace::EExtraPresent))
		return EFalse;
	TUint id = *ptr++;

	if(*ptr++ != aOutSize)
		return EFalse;

	if(aOffset && *ptr++ != aOffset)
		return EFalse;

	TInt size = aData[BTrace::ESizeIndex]-((TInt)ptr-(TInt)aData);
	TUint8* data = (TUint8*)ptr;
	TUint8* out = (TUint8*)KTestTrace1+4+aOffset;

	if(!aOffset)
		{
		if((header2&BTrace::EMultipartFlagMask) != BTrace::EMultipartFirst)
			return EFalse;
		BigTraceId = id;
		aOffset += size-4-aExtraIds;
		BigTraceFirst = ETrue;
		}
	else
		{
		if(id!=BigTraceId)
			return EFalse;
		aOffset += size;
		out += 4 + aExtraIds;
		if(aOffset==aOutSize)
			{
			if((header2&BTrace::EMultipartFlagMask) != BTrace::EMultipartLast)
				return EFalse;
			BigTraceEnd = ETrue;
			}
		else
			{
			if((header2&BTrace::EMultipartFlagMask) != BTrace::EMultipartMiddle)
				return EFalse;
			BigTraceMiddle = ETrue;
			}
		}
	if(aOffset>aOutSize)
		return EFalse;

	while(--size>=0)
		if(*data++!=*out++)
			return EFalse;
	aData = data;

	return ETrue;
	}



TBool CheckBigTrace1(TUint8* aData, TInt aSize, TInt aOutSize, TInt aSubCategory=KTest1SubCategory, TUint32 aExtraIds = 0)
	{
	if(aOutSize<=(TInt)KMaxBTraceDataArray+8)
		{
		if(!CheckSize(aData,aSize,aOutSize))
			return EFalse;
		if(!CheckTrace1(aData,aSize,aSubCategory))
			return EFalse;
		}
	else
		{
		TUint8* end = aData+aSize;
		aOutSize -= 4 + aExtraIds; // first 4 bytes of trace are always present, and don't count towards 'size' of multipart trace
		TUint32 aOffset = 0;
		while(aOffset<TUint32(aOutSize))
			if(!DoCheckBigTrace1(aData,aOutSize,aOffset,aExtraIds))
				return EFalse;
		aData = (TUint8*)(((TInt)aData+3)&~3);
		if(aData != end)
			return EFalse;
		}
	return ETrue;
	}


//---------------------------------------------
//! @SYMTestCaseID KBASE-T_BTRACE-0061
//! @SYMTestType UT
//! @SYMPREQ PREQ1030
//! @SYMTestCaseDesc Test Big (mutipart) kernel traces.
//! @SYMTestActions Generate traces from kernel code using the BTraceBig,
//!		BTracePcBig, BTraceContextBig and BTraceContextPcBig macros.
//! @SYMTestExpectedResults Traces where broken down into mutiple parts and
//!		all trace contents captured by RBTrace matched those specified
//!		at point of trace generation. Also, where appropriate, PC and/or
//!		Context ID values are present and correct.
//! @SYMTestPriority High
//! @SYMTestStatus Implemented
//---------------------------------------------
void TestBig(TBool aUserTrace, TBool aFilter2)
	{
	test.Start(_L("Reset trace buffer"));
	TInt oldSize = Trace.BufferSize();
	TInt r = Trace.ResizeBuffer(0x100000);
	test_KErrNone(r);
	Trace.SetMode(RBTrace::EEnable);

	// dummy trace do get current thread context id
	Trace.SetFilter(BTrace::ETest1,0);
	ThisTraceContextId = TraceTest.Trace(BTrace::EContextIdPresent,KTestTrace1,0);

	// create a test filter...
	TInt extraFlags = 0;
	if(aUserTrace)
		extraFlags |= RBTraceTest::EUserTrace;
	TInt minSize = 4;
	if(aFilter2)
		{
		extraFlags |= RBTraceTest::EFilter2Trace;
		minSize += 4;
		}

	TInt filterMode;
	for(filterMode=0; filterMode<(aFilter2?6:2); ++filterMode)
		{

		// setup filters...
		Trace.SetFilter(BTrace::ETest1,1);
		Trace.SetFilter2(BigFilter2,KNumBTraceFilterTestUids);
		if(filterMode==0 || filterMode==2)
			Trace.SetFilter(BTrace::ETest1,0); // disable in primary filter
		if(filterMode==0 || filterMode==1)
			Trace.SetFilter2(KBTraceFilterTestUid1,0); // disable in secondary filter
		if(filterMode==4)
			Trace.SetFilter2(0); // disable entire secondary filter
		if(filterMode==5)
			Trace.SetFilter2(1); // enable entire secondary filter

		// expectTrace is true if we expect trace to be output...
		TBool expectTrace = aFilter2 ? (filterMode==3 || filterMode==5) : filterMode&1;

		switch(filterMode)
			{
		case 0: test.Next(_L("Test with primary filter OFF, secondary filter OFF")); break;
		case 1: test.Next(_L("Test with primary filter ON, secondary filter OFF")); break;
		case 2: test.Next(_L("Test with primary filter OFF, secondary filter ON")); break;
		case 3: test.Next(_L("Test with primary filter ON, secondary filter ON")); break;
		case 4: test.Next(_L("Test with primary filter ON, global secondary filter OFF")); break;
		case 5: test.Next(_L("Test with primary filter ON, global secondary filter ON")); break;
			}

		test.Start(_L("Big traces without special context"));
		TInt i;
		for(i=minSize; i<=(TInt)sizeof(KTestTrace1)-4; i++)
			{
			TestTrace1(RBTraceTest::EBigTrace|extraFlags,i);

			TUint8* data;
			TInt size;
			size = Trace.GetData(data);
			if(!expectTrace)
				{
				test(!size);
				continue;
				}
			test(CheckBigTrace1(data,size,i,KTest1SubCategory));
			Trace.DataUsed();
			}

		test.Next(_L("Big traces with PC"));
		BigTraceBeginTest();
		for(i=minSize; i<=(TInt)sizeof(KTestTrace1)-4; i++)
			{
			TraceTest.Trace(RBTraceTest::EBigTrace|BTrace::EPcPresent|extraFlags,KTestTrace1,i);

			TUint8* data;
			TUint8* data2;
			TInt size;
			size=Trace.GetData(data);
			if(!expectTrace)
				{
				test(!size);
				continue;
				}
			size /= 2;
			data2 = data+size;

			test(CheckBigTrace1(data,size,i,KTest1SubCategory));
			test(CheckBigTrace1(data2,size,i,KTest1SubCategory));

			test(!(data[BTrace::EFlagsIndex]&BTrace::EContextIdPresent));
			test((data[BTrace::EFlagsIndex]&BTrace::EPcPresent));

			TInt offset = ContextOffset(data);
			test( ((TUint32*)(data+offset))[0] != ((TUint32*)(data2+offset))[0]);

			Trace.DataUsed();
			}
		test_Equal(expectTrace,BigTraceEndTest()); // check we actually got mutilpart traces

		test.Next(_L("Big traces with Context ID"));
		BigTraceBeginTest();
		for(i=minSize; i<=(TInt)sizeof(KTestTrace1)-4; i++)
			{
			TestTrace1(RBTraceTest::EBigTrace|BTrace::EContextIdPresent|extraFlags,i);

			TUint8* data;
			TUint8* data2;
			TInt size;
			size=Trace.GetData(data);
			if(!expectTrace)
				{
				test(!size);
				continue;
				}
			size /= 2;
			data2 = data+size;

			test(CheckBigTrace1(data,size,i,KTest1SubCategory));
			test(CheckBigTrace1(data2,size,i,KTest1SubCategory));

			test((data[BTrace::EFlagsIndex]&BTrace::EContextIdPresent));
			test(!(data[BTrace::EFlagsIndex]&BTrace::EPcPresent));

			TUint offset = ContextOffset(data);
			test_Equal(ThisTraceContextId, ((TUint32*)(data+offset))[0]);
			test_Equal(ThisTraceContextId, ((TUint32*)(data2+offset))[0]);

			Trace.DataUsed();
			}
		test_Equal(expectTrace,BigTraceEndTest()); // check we actually got mutilpart traces

		test.Next(_L("Big traces with Context ID and PC"));
		BigTraceBeginTest();
		for(i=minSize; i<=(TInt)sizeof(KTestTrace1)-4; i++)
			{
			TestTrace1(RBTraceTest::EBigTrace|BTrace::EContextIdPresent|BTrace::EPcPresent|extraFlags,i);

			TUint8* data;
			TUint8* data2;
			TInt size;
			size=Trace.GetData(data);
			if(!expectTrace)
				{
				test(!size);
				continue;
				}
			size /= 2;
			data2 = data+size;

			test(CheckBigTrace1(data,size,i,KTest1SubCategory));
			test(CheckBigTrace1(data2,size,i,KTest1SubCategory));

			test((data[BTrace::EFlagsIndex]&BTrace::EContextIdPresent));
			test((data[BTrace::EFlagsIndex]&BTrace::EPcPresent));

			TUint offset = ContextOffset(data);
			test_Equal(ThisTraceContextId, ((TUint32*)(data+offset))[0] );
			test_Equal(ThisTraceContextId, ((TUint32*)(data2+offset))[0] );
			test_Compare( ((TUint32*)(data+offset))[1], != ,((TUint32*)(data2+offset))[1]);

			Trace.DataUsed();
			}
		test_Equal(expectTrace,BigTraceEndTest()); // check we actually got mutilpart traces
		test.End();
		}

	test.Next(_L("Restore buffer"));
	r = Trace.ResizeBuffer(oldSize);
	test_KErrNone(r);
	Trace.SetFilter2(0);

	test.End();
	}


TUint MainThreadTraceId = 0;

//---------------------------------------------
//! @SYMTestCaseID KBASE-T_BTRACE-0064
//! @SYMTestType UT
//! @SYMPREQ PREQ1030
//! @SYMTestCaseDesc Test BTrace category EThreadIdentification.
//! @SYMTestActions Enable the EThreadIdentification trace category, causing it to be 'primed'.
//!		Rename a thread and a process, then create and destory a thread.
//!		No actions are performed if the kernel doesn't support this trace category.
//! @SYMTestExpectedResults All test actions produced traces and their contents matched
//!		the expected results.
//! @SYMTestPriority High
//! @SYMTestStatus Implemented
//---------------------------------------------
void TestThreadIdentification()
	{
	if(KErrNotSupported==Trace.Filter(BTrace::EThreadIdentification))
		{
		test.Start(_L("Trace category not supported by this build of kernel."));
		test.End();
		return;
		}

	TBuf8<KMaxKernelName> threadName = RThread().Name().Collapse();
	TUint threadId = RThread().Id();
	TBuf8<KMaxKernelName> processName = RProcess().Name().Collapse();

	TUint32 threadTraceId = 0;
	TUint32 processTraceId = 0;
	TUint8* data;
	TInt size;

	test.Start(_L("Reset trace buffer"));
	Trace.SetMode(0);
	TInt oldSize = Trace.BufferSize();
	TInt r = Trace.ResizeBuffer(0x100000);
	test_KErrNone(r);
	Trace.SetFilter(BTrace::EThreadIdentification,0);
	Trace.SetMode(RBTrace::EEnable);

	test.Next(_L("Test category is primed correct when it is enabled"));
	Trace.SetFilter(BTrace::EThreadIdentification,1);
	// search for current thread in trace...
	TUint8* trace;
	size=Trace.GetData(trace);
	test_NotNull(size);
	TUint8* end = trace+size;
	for(data=trace; data<end; data=BTrace::NextRecord(data))
		if(data[BTrace::ECategoryIndex]==BTrace::EThreadIdentification)
			if(data[BTrace::ESubCategoryIndex]==BTrace::EProcessName)
				if(processName==Text(data))
					{
					processTraceId = Body(data)[1];
					break;
					}
	test_Compare(data, < , end);
	for(; data<end; data=BTrace::NextRecord(data))
		if(data[BTrace::ECategoryIndex]==BTrace::EThreadIdentification)
			if(data[BTrace::ESubCategoryIndex]==BTrace::EThreadName)
				if(processTraceId==Body(data)[1])
					if(threadName==Text(data))
						{
						threadTraceId = Body(data)[0];
						break;
						}
	test_Compare(data, < , end);
	for(; data<end; data=BTrace::NextRecord(data))
		if(data[BTrace::ECategoryIndex]==BTrace::EThreadIdentification)
			if(data[BTrace::ESubCategoryIndex]==BTrace::EThreadId)
				if(threadTraceId==Body(data)[0])
					if(processTraceId==Body(data)[1])
						if(threadId==Body(data)[2])
							{
							break;
							}
	test_Compare(data, < ,end);
	Trace.DataUsed();
	MainThreadTraceId = threadTraceId;

	test.Next(_L("Test thread rename traces"));
	test_KErrNone(User::RenameThread(_L("t_btrace-main")));
	threadName = RThread().Name().Collapse();
	size=Trace.GetData(data);
	test_NotNull(size);
	end = data+size;
	test_Equal(BTrace::EThreadIdentification,data[BTrace::ECategoryIndex]);
	test_Equal(BTrace::EThreadName, data[BTrace::ESubCategoryIndex]);
	test_Equal(threadTraceId, Body(data)[0]);
	test_Equal(processTraceId, Body(data)[1]);
	test(threadName==Text(data));
	data=BTrace::NextRecord(data);
	test(data==end);
	Trace.DataUsed();

	test.Next(_L("Test process rename traces"));
	test_KErrNone(User::RenameProcess(_L("T_BTRACE-renamed")));
	processName = RProcess().Name().Collapse();
	size=Trace.GetData(data);
	test_NotNull(size);
	end = data+size;
	test_Equal(BTrace::EThreadIdentification,data[BTrace::ECategoryIndex]);
	test_Equal(BTrace::EProcessName ,data[BTrace::ESubCategoryIndex]);
	test_Equal(processTraceId, Body(data)[1]);
	test(processName==Text(data));
	data=BTrace::NextRecord(data);
	test(data==end);
	Trace.DataUsed();

	test.Next(_L("Test thread creation traces"));
	RThread thread;
	test_KErrNone(thread.Create(KNullDesC,0,0x1000,&User::Allocator(),0));
	threadName = thread.Name().Collapse();
	threadId = thread.Id();
	size=Trace.GetData(data);
	test_NotNull(size);
	end = data+size;

	test_Equal(BTrace::EThreadIdentification,data[BTrace::ECategoryIndex]);
	test_Equal(BTrace::ENanoThreadCreate ,data[BTrace::ESubCategoryIndex]);
	threadTraceId = Body(data)[0];
	data=BTrace::NextRecord(data);
	test_Compare(data, < ,end);

	test_Equal(BTrace::EThreadIdentification,data[BTrace::ECategoryIndex]);
	test_Equal(BTrace::EProcessName ,data[BTrace::ESubCategoryIndex]);
	test_Equal(processTraceId, Body(data)[1]);
	test(processName==Text(data));
	data=BTrace::NextRecord(data);
	test_Compare(data, < ,end);

	test_Equal(BTrace::EThreadIdentification,data[BTrace::ECategoryIndex]);
	test_Equal(BTrace::EThreadCreate ,data[BTrace::ESubCategoryIndex]);
	test_Equal(threadTraceId, Body(data)[0]);
	processTraceId = Body(data)[1];
	test(threadName==Text(data));
	data=BTrace::NextRecord(data);
	test_Compare(data, < ,end);

	test_Equal(BTrace::EThreadIdentification,data[BTrace::ECategoryIndex]);
	test_Equal(BTrace::EThreadId ,data[BTrace::ESubCategoryIndex]);
	test_Equal(threadTraceId, Body(data)[0]);
	test_Equal(processTraceId, Body(data)[1]);
	test(threadId==Body(data)[2]);
	data=BTrace::NextRecord(data);
	test_Equal(data,end);
	Trace.DataUsed();

	test.Next(_L("Test thread destruction traces"));
	thread.Kill(0);
	User::After(100000);
	size=Trace.GetData(data);
	test_NotNull(size);
	end = data+size;

	test_Equal(BTrace::EThreadIdentification,data[BTrace::ECategoryIndex]);
	test_Equal(BTrace::ENanoThreadDestroy ,data[BTrace::ESubCategoryIndex]);
	test_Equal(threadTraceId, Body(data)[0]);
	data=BTrace::NextRecord(data);
	test_Compare(data, < ,end);

	test_Equal(BTrace::EThreadIdentification,data[BTrace::ECategoryIndex]);
	test_Equal(BTrace::EThreadDestroy ,data[BTrace::ESubCategoryIndex]);
	test_Equal(threadTraceId, Body(data)[0]);
	test_Equal(processTraceId, Body(data)[1]);
	test(threadId==Body(data)[2]);
	data=BTrace::NextRecord(data);
	test_Equal(data,end);
	Trace.DataUsed();

	test.Next(_L("Cleanup after tests"));
	Trace.SetFilter(BTrace::EThreadIdentification,0);
	Trace.SetMode(0);
	r = Trace.ResizeBuffer(oldSize);
	test_KErrNone(r);

	test.End();
	}


//---------------------------------------------
//! @SYMTestCaseID KBASE-T_BTRACE-0065
//! @SYMTestType UT
//! @SYMPREQ PREQ1030
//! @SYMTestCaseDesc Test BTrace category ECpuUsage.
//! @SYMTestActions Enable the ECpuUsage trace category for one second, then obtain captured
//!		traces using RBTrace.
//! @SYMTestExpectedResults Traces are generated for the sub-categories EIrqStart, EIDFCStart,
//!		EIDFCEnd and ENewThreadContext. The later must include the context ID of the main test
//!		program thread.
//! @SYMTestPriority High
//! @SYMTestStatus Implemented
//---------------------------------------------
void TestCpuUsage()
	{
	if(KErrNotSupported==Trace.Filter(BTrace::ECpuUsage))
		{
		test.Start(_L("Trace category not supported by this build of kernel."));
		test.End();
		return;
		}

	test.Start(_L("Reset trace buffer"));
	Trace.SetMode(0);
	TInt oldSize = Trace.BufferSize();
	TInt r = Trace.ResizeBuffer(0x100000);
	test_KErrNone(r);
	Trace.SetMode(RBTrace::EEnable);

	test.Next(_L("Generate traces for a short time..."));
	Trace.SetFilter(BTrace::ECpuUsage,1);
	User::After(1000*1000);
	Trace.SetFilter(BTrace::ECpuUsage,0);

	test.Next(_L("Process traces"));
	TUint8 subCategories[256] = {0};
	TUint8* data;
	TInt size;
	while((size=Trace.GetData(data))!=0)
		{
		TUint8* end = data+size;
		for( ; data<end; data=BTrace::NextRecord(data))
			{
			test_Equal(BTrace::ECpuUsage,data[BTrace::ECategoryIndex]);
			TUint subCategory = data[BTrace::ESubCategoryIndex];
			TUint8* context = data+ContextOffset(data);
			TUint8* recordEnd = BTrace::NextRecord(data);
			if(subCategory==BTrace::ENewThreadContext)
				{
				test_Equal(context+4, recordEnd); // trace record should end after context data
				if(*(TUint32*)context != MainThreadTraceId)
					continue; // not a context switch to this thread
				}
			else if (subCategory==BTrace::EIrqStart || subCategory==BTrace::EFiqStart)
				{
				// may or may not contain vector number
				if (recordEnd != context)
					{
					test_Equal(context+4, recordEnd);
					}
				}
			else
				{
				test_Equal(context, recordEnd); // trace record should have no context or any data after
				}
			subCategories[subCategory] = 1; // set flag to say we've seen this kind of trace
			}
		Trace.DataUsed();
		}

	test.Next(_L("Check for expected traces"));
	// timer interrupts should have generated IRQ traces...
	test(subCategories[BTrace::EIrqStart]);
	 // User::After should have caused timer interrupt to queue a DFC...
	test(subCategories[BTrace::EIDFCStart]);
	test(subCategories[BTrace::EIDFCEnd]);
	// Current thread must have got scheduled again...
	test(subCategories[BTrace::ENewThreadContext]);

	test.Next(_L("Cleanup after tests"));
	Trace.SetFilter(BTrace::ECpuUsage,0);
	Trace.SetMode(0);
	r = Trace.ResizeBuffer(oldSize);
	test_KErrNone(r);

	test.End();
	}


volatile TBool SoakDone = EFalse; // always false, but stops compiler warnings in SoakThreadFunction

RThread SoakThread[4];

TInt SoakThreadFunction(TAny* aData)
	{
	TUint32 random = 0;
	BTrace::TCategory category = (BTrace::TCategory)*(TUint8*)aData;
	TUint subCategory = 0;
	while(!SoakDone)
		{
		random = random*69069+1;
		TUint size = (random>>24u);

		if(size<4)
			BTrace0(category,subCategory);
		else if(size<=8)
			BTrace4(category,subCategory,((TUint32*)aData)[1]);
		else if(size<12)
			BTrace8(category,subCategory,((TUint32*)aData)[1],((TUint32*)aData)[2]);
		else
			BTraceN(category,subCategory,((TUint32*)aData)[1],((TUint32*)aData)[2],&((TUint32*)aData)[3],size-12);
		++subCategory;
		}
	return 0;
	}


TInt SoakThreadFunction2(TAny* aData)
	{
	TUint32 random = 0;
	BTrace::TCategory category = (BTrace::TCategory)*(TUint8*)aData;
	TUint subCategory = 0;
	while(!SoakDone)
		{
		random = random*69069+1;
		TUint size = (random>>24u);

		TInt outOk;
		if(size<=8)
			outOk = BTraceFiltered4(category,subCategory,((TUint32*)aData)[1]);
		else if(size<12)
			outOk = BTraceFiltered8(category,subCategory,((TUint32*)aData)[1],((TUint32*)aData)[2]);
		else
			outOk = BTraceFilteredN(category,subCategory,((TUint32*)aData)[1],((TUint32*)aData)[2],&((TUint32*)aData)[3],size-12);
		if(outOk)
			++subCategory;
		}
	return 0;
	}


TInt SoakControlThreadFunction(TAny*)
	{
	// randomly mess with thread priorities of soak test threads so
	// we get lots of preemption going on
	const TThreadPriority priorities[] =
		{
		EPriorityMuchLess,
		EPriorityLess,
		EPriorityNormal,
		EPriorityMore
		};

	TUint32 random = 0;
	while(!SoakDone)
		{
		User::AfterHighRes(1);
		random = random*69069+1;
		SoakThread[(random>>16)%3].SetPriority(priorities[(random>>14)&3]);
		}
	return 0;
	}


void ChangeSecondaryFilter()
	{
	// mess with secondary filter...
	static TUint32 random = 0;
	random = random*69069+1;
	switch(random>>29)
		{
		case 0:
			Trace.SetFilter2(KBTraceFilterTestUid1,0);
			break;
		case 1:
			Trace.SetFilter2(KBTraceFilterTestUid1,1);
			break;
		case 2:
			Trace.SetFilter2(KBTraceFilterTestUid2,0);
			break;
		case 3:
			Trace.SetFilter2(KBTraceFilterTestUid2,1);
			break;
		case 4:
			Trace.SetFilter2(0);
			break;
		case 5:
			Trace.SetFilter2(1);
			break;
		case 6:
			Trace.SetFilter2(&KBTraceFilterTestUid1,1);
			break;
		case 7:
			Trace.SetFilter2(&KBTraceFilterTestUid2,1);
			break;
		}
	}

//---------------------------------------------
//! @SYMTestCaseID KBASE-T_BTRACE-0066
//! @SYMTestType UT
//! @SYMPREQ PREQ1030
//! @SYMTestCaseDesc Soak tests
//! @SYMTestActions Generate ordered traces of random size using two worker threads and
//!		read the generated trace in the main test program thread. All threads are scheduled
//!		in a random manner.
//! @SYMTestExpectedResults Captured traces must contain the correct data and any
//!		missing traces must be indicated by the EMissingRecord flag in the next trace.
//! @SYMTestPriority High
//! @SYMTestStatus Implemented
//---------------------------------------------
void TestSoak(TUint aMode,TUint aTimeInSeconds)
	{
	aMode |= RBTrace::EEnable;

	test.Start(_L("Reset trace buffer"));
	TInt oldSize = Trace.BufferSize();
	TInt r = Trace.ResizeBuffer(0x10000);
	test_KErrNone(r);
	Trace.SetMode(aMode);
	Trace.SetFilter(BTrace::ETest1,1);
	Trace.SetFilter(BTrace::ETest2,1);
	Trace.SetFilter2(KBTraceFilterTestUid2,1);

	TUint32* buffer = (TUint32*)Trace.DataChunk().Base();
	test.Printf(_L("Buffer=%x %x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n"),buffer,
		buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6],buffer[7],buffer[8],buffer[9]);

	test.Next(_L("Random traces..."));
	Trace1Sequence = 0;
	Trace2Sequence = 0;
	RTimer timer;
	test_KErrNone(timer.CreateLocal());
	SoakThread[0].Duplicate(RThread(),EOwnerProcess);
	test_KErrNone(SoakThread[1].Create(KNullDesC,SoakThreadFunction,0x1000,&User::Allocator(),KTestTrace1));
	test_KErrNone(SoakThread[2].Create(KNullDesC,SoakThreadFunction2,0x1000,&User::Allocator(),KTestTrace2));
	test_KErrNone(SoakThread[3].Create(KNullDesC,SoakControlThreadFunction,0x1000,&User::Allocator(),KTestTrace2));
	// The control thread must be resumed first otherwise time slicing perculiarities
	// can cause the soak threads to take all of the CPU time...
	SoakThread[3].SetPriority(EPriorityMuchMore);
	SoakThread[3].Resume();

	TRequestStatus s;
	TTimeIntervalMicroSeconds32 tickPeriod;
	UserHal::TickPeriod(tickPeriod);
	TInt64 ticks = aTimeInSeconds;
	ticks *= 1000000;
	ticks /= tickPeriod.Int();
	timer.AfterTicks(s,(TInt)ticks);

	// resume threads producing trace output...
	SoakThread[1].Resume();
	SoakThread[2].Resume();

	TInt64 totalSize = 0;
	for(;;)
		{
		ChangeSecondaryFilter();
		const TInt KTraceDataBlockSize = 0x1000;
		TUint8* data;
		TInt size;
		while(s==KRequestPending && (size=Trace.GetData(data))!=0)
			{
//			RDebug::Printf("READ: data=%08x size=%08x\n",data,size);
			if(s!=KRequestPending)
				break;
			CheckTraceData(data,size);
			totalSize += size;
			Trace.DataUsed();
			}
		if(s!=KRequestPending)
			break;
		TRequestStatus waitStatus;
		Trace.RequestData(waitStatus,KTraceDataBlockSize);
		User::WaitForRequest(waitStatus);
		test_KErrNone(waitStatus.Int());
		}
	User::WaitForRequest(s);
	test_Equal(EExitPending, SoakThread[1].ExitType() );
	test_Equal(EExitPending, SoakThread[2].ExitType() );
	test_Equal(EExitPending, SoakThread[3].ExitType() );
	SoakThread[1].Kill(0);
	SoakThread[2].Kill(0);
	SoakThread[3].Kill(0);
	SoakThread[1].Close();
	SoakThread[2].Close();
	SoakThread[3].Close();

	test.Printf(_L("total trace data processed = %ld k\n"),totalSize>>10);

	test.Next(_L("Restore buffer"));
	r = Trace.ResizeBuffer(oldSize);
	test_KErrNone(r);

	test.End();
	}


void KernelBenchmark(TUint& aTime1,TUint& aTime2,TUint& aTime3,TBool aTraceEnabled,TBool aFilter2)
	{
	TInt oldSize = Trace.BufferSize();

	TInt r = Trace.ResizeBuffer(0x1000);
	test_KErrNone(r);
	Trace.SetMode(RBTrace::EFreeRunning|RBTrace::EEnable);

	if(aFilter2)
		r = 1+TraceTest.TestBenchmark2(0,1000000);
	else
		r = 1+TraceTest.TestBenchmark(0,1000000);
	TUint8* data;
	TInt size = Trace.GetData(data);
	test(aTraceEnabled ? size!=0 : size==0);
	Trace.DataUsed();
	aTime1 = 1000000000/r;

	r = Trace.ResizeBuffer(0x1000);
	test_KErrNone(r);
	Trace.SetMode(RBTrace::EFreeRunning|RBTrace::EEnable);

	if(aFilter2)
		r = 1+TraceTest.TestBenchmark2(KMaxBTraceDataArray,1000000);
	else
		r = 1+TraceTest.TestBenchmark(KMaxBTraceDataArray,1000000);
	size = Trace.GetData(data);
	test(aTraceEnabled ? size!=0 : size==0);
	Trace.DataUsed();
	aTime2 = 1000000000/r;

	r = 1+TraceTest.TestBenchmarkCheckFilter(aFilter2,1000000);
	aTime3 = 1000000000/r;

	r = Trace.ResizeBuffer(oldSize);
	test_KErrNone(r);
	}


void UserBenchmark(TUint& aTime1,TUint& aTime2,TUint& aTime3,TBool aTraceEnabled,TBool aFilter2)
	{
	TInt oldSize = Trace.BufferSize();

	RTimer timer;
	TRequestStatus status;
	test_KErrNone(timer.CreateLocal());

	TInt r = Trace.ResizeBuffer(0x1000);
	test_KErrNone(r);
	Trace.SetMode(RBTrace::EFreeRunning|RBTrace::EEnable);

	timer.After(status,1);
	User::WaitForRequest(status);
	timer.After(status,1000000);
	r = 0;
	if(aFilter2)
		do
			{
			BTraceFiltered4(BTrace::ETest1,0,KBTraceFilterTestUid1);
			++r;
			}
		while(status==KRequestPending);
	else
		do
			{
			BTrace0(BTrace::ETest1,0);
			++r;
			}
		while(status==KRequestPending);
	User::WaitForRequest(status);
	TUint8* data;
	TInt size = Trace.GetData(data);
	test(aTraceEnabled ? size!=0 : size==0);
	Trace.DataUsed();
	aTime1 = 1000000000/r;

	r = Trace.ResizeBuffer(0x1000);
	test_KErrNone(r);
	Trace.SetMode(RBTrace::EFreeRunning|RBTrace::EEnable);

	timer.After(status,1);
	User::WaitForRequest(status);
	timer.After(status,1000000);
	r = 0;
	if(aFilter2)
		do
			{
			BTraceFilteredContextN(BTrace::ETest1,0,KBTraceFilterTestUid1,0,KTestTrace1,KMaxBTraceDataArray);
			++r;
			}
		while(status==KRequestPending);
	else
		do
			{
			BTraceContextN(BTrace::ETest1,0,0,0,KTestTrace1,KMaxBTraceDataArray);
			++r;
			}
		while(status==KRequestPending);
	User::WaitForRequest(status);
	size = Trace.GetData(data);
	test(aTraceEnabled ? size!=0 : size==0);
	Trace.DataUsed();
	aTime2 = 1000000000/r;

	timer.After(status,1);
	User::WaitForRequest(status);
	timer.After(status,1000000);
	r = 0;
	TBool check = -1;
	if(aFilter2)
		do
			{
			check = BTrace::CheckFilter2(BTrace::ETest1,KBTraceFilterTestUid1);
			++r;
			}
		while(status==KRequestPending);
	else
		do
			{
			check = BTrace::CheckFilter(BTrace::ETest1);
			++r;
			}
		while(status==KRequestPending);
	test(check == aTraceEnabled);
	aTime3 = 1000000000/r;

	r = Trace.ResizeBuffer(oldSize);
	test_KErrNone(r);
	}


//---------------------------------------------
//! @SYMTestCaseID KBASE-T_BTRACE-0066-0067
//! @SYMTestType UT
//! @SYMPREQ PREQ1030
//! @SYMTestCaseDesc Benchmark tracing.
//! @SYMTestActions Time the generation of minimum and maximum sized traces both with
//!		and without the trace filter enabled for the trace category.
//! @SYMTestExpectedResults Trace time with filter enabled should not excede 2000 nano-seconds,
//!		and time with filter disabled should not excede 500 nano-seconds. (These limits are not
//!		asserted). If time significantly excedes this then detailed investigation is required.
//! @SYMTestPriority Medium
//! @SYMTestStatus Implemented
//---------------------------------------------
void TestBenchmark(TBool aUserTrace)
	{
	TUint t1 = 0;
	TUint t2 = 0;
	TUint t3 = 0;

#define BENCH(a1,a2) aUserTrace ? UserBenchmark(t1,t2,t3,a1,a2) : KernelBenchmark(t1,t2,t3,a1,a2)

	test.Printf(_L("                                      Min Trace   Max Trace      Filter\n"));

	Trace.SetFilter(BTrace::ETest1,0);
	BENCH(0,0);
	test.Printf(_L("filter1 off                           %6d ns   %6d ns   %6d ns\n"),t1,t2,t3);

	Trace.SetFilter(BTrace::ETest1,1);
	BENCH(1,0);
	test.Printf(_L("filter1 on                            %6d ns   %6d ns   %6d ns\n"),t1,t2,t3);

	Trace.SetFilter(BTrace::ETest1,0);
	Trace.SetFilter2(0);
	BENCH(0,1);
	test.Printf(_L("filter1 off   filter2 off             %6d ns   %6d ns   %6d ns\n"),t1,t2,t3);

	Trace.SetFilter(BTrace::ETest1,1);
	Trace.SetFilter2(0);
	BENCH(0,1);
	test.Printf(_L("filter1 on    global filter2 off      %6d ns   %6d ns   %6d ns\n"),t1,t2,t3);

	Trace.SetFilter2(1);
	BENCH(1,1);
	test.Printf(_L("filter1 on    global filter2 on       %6d ns   %6d ns   %6d ns\n"),t1,t2,t3);

	Trace.SetFilter2(&KBTraceFilterTestUid2,1);
	BENCH(0,1);
	test.Printf(_L("filter1 on    1 UID filter2 off       %6d ns   %6d ns   %6d ns\n"),t1,t2,t3);

	Trace.SetFilter2(&KBTraceFilterTestUid1,1);
	BENCH(1,1);
	test.Printf(_L("filter1 on    1 UID filter2 on        %6d ns   %6d ns   %6d ns\n"),t1,t2,t3);

	Trace.SetFilter2(BigFilter2,sizeof(BigFilter2)/sizeof(TUint32));
	Trace.SetFilter2(KBTraceFilterTestUid1,0);
	BENCH(0,1);
	test.Printf(_L("filter1 on    100 UID filter2 off     %6d ns   %6d ns   %6d ns\n"),t1,t2,t3);

	Trace.SetFilter2(BigFilter2,sizeof(BigFilter2)/sizeof(TUint32));
	BENCH(1,1);
	test.Printf(_L("filter1 on    100 UID filter2 on      %6d ns   %6d ns   %6d ns\n"),t1,t2,t3);

	Trace.SetFilter(BTrace::ETest1,0);
	Trace.SetFilter2(0);
	}

struct THREADTRACETESTSTRUCT {
	TInt* alloc_addr;
	void* chunk_addr;
};

LOCAL_D TInt threadtraceTestThread(TAny* param)
	{
	THREADTRACETESTSTRUCT* p = (THREADTRACETESTSTRUCT*)param;
	p->alloc_addr = new TInt;
	delete p->alloc_addr;
	return 0;
	}

void TestHeapAndChunkTrace()
	{
	if(KErrNotSupported==Trace.Filter(BTrace::EHeap))
		{
		test.Start(_L("Trace category EHeap not supported by this build of kernel."));
		test.End();
		return;
		}

	test.Start(_L("Reset trace buffer"));
	Trace.SetMode(0);
	TInt oldSize = Trace.BufferSize();
	TInt r = Trace.ResizeBuffer(0x100000);
	test_KErrNone(r);
	Trace.SetFilter(BTrace::EHeap,0);
	Trace.SetFilter(BTrace::EChunks,0);
	Trace.SetMode(RBTrace::EEnable);

	test.Next(_L("Test heap-alloc works as expected"));
	Trace.SetFilter(BTrace::EHeap,1);
	TBool chunkTraceEnabled = Trace.SetFilter(BTrace::EChunks,1)!=KErrNotSupported;

	// Create a test thread
	THREADTRACETESTSTRUCT threadtest;
	RThread thread;
	TRequestStatus stat;
	test.Next(_L("Test thread creation heap trace"));
	r=thread.Create(_L("t_tbrace_2"),threadtraceTestThread,KDefaultStackSize,0x2000,0x2000,&threadtest);
	test_KErrNone(r);
	thread.Logon(stat);
	thread.Resume();
	User::WaitForRequest(stat);


	// search for heap records in trace...
	TUint8* data;
	TUint8* trace;
	TInt size=Trace.GetData(trace);
	test_NotNull(size);
	TUint8* end = trace+size;
	TUint chunk_ptr = 0, heap_chunk_ptr = 0;
	int found_chunk_create = 0;
	int found_heap_chunk_create = 0;
	int found_heap_create=0;
	int found_heap_alloc=0;
	int found_heap_free=0;
	for(data=trace; data<end; data=BTrace::NextRecord(data))
		{
		if(data[BTrace::ECategoryIndex]==BTrace::EChunks)
			{
			if(data[BTrace::ESubCategoryIndex]==BTrace::EChunkCreated)
				{
				found_chunk_create=1;
				chunk_ptr = Body(data)[0];
				}
			}
		if(data[BTrace::ECategoryIndex]==BTrace::EHeap)
			{
			if(data[BTrace::ESubCategoryIndex]==BTrace::EHeapCreate)
				found_heap_create=1;
			if(data[BTrace::ESubCategoryIndex]==BTrace::EHeapChunkCreate)
				{
				found_heap_chunk_create=1;
				heap_chunk_ptr = Body(data)[1];
				}
			if(data[BTrace::ESubCategoryIndex]==BTrace::EHeapAlloc)
				{
				if(Body(data)[1]==(TUint)threadtest.alloc_addr)
					{
					found_heap_alloc=1;
					test_Equal(4, Body(data)[2]);
					test_Compare(Body(data)[3], >= ,4);
					}
				}
			if(data[BTrace::ESubCategoryIndex]==BTrace::EHeapFree)
				{
				if(Body(data)[1]==(TUint)threadtest.alloc_addr)
					found_heap_free=1;
				}
			}
		}
	test(found_heap_create);
	test(found_heap_chunk_create);
	test(found_heap_alloc);
	test(found_heap_free);
	if(!chunkTraceEnabled)
		{
		test.Next(_L("Trace category EChunk not supported by this build of kernel."));
		test.End();
		return;
		}
	test(chunk_ptr && heap_chunk_ptr);
	test(chunk_ptr == heap_chunk_ptr);
	//Trace.DataUsed();

	// Turn on chunk trace and empty btrace buffer
	test.Next(_L("Chunk testing"));
	Trace.SetFilter(BTrace::EChunks,1);
	Trace.Empty();

	// Create a chunk and test the expected traces
	RChunk chunk;
	test_KErrNone(chunk.CreateLocal(4096, 4*1024*1024));
	trace = NULL;
	size=Trace.GetData(trace);
	test_NotNull(size);
	end = trace+size;
	found_chunk_create=0;
	for(data=trace; data<end; data=BTrace::NextRecord(data))
		{
		if(data[BTrace::ECategoryIndex]==BTrace::EChunks)
			{
			if(data[BTrace::ESubCategoryIndex]==BTrace::EChunkCreated)
				{
				test_Equal(4*1024*1024, Body(data)[1]);
				found_chunk_create = 1;
				}
			if(data[BTrace::ESubCategoryIndex]==BTrace::EChunkMemoryAllocated)
				{
				test_Equal(4096, Body(data)[2]);
				found_heap_alloc = 1;
				}
			}
		}
	test(found_heap_alloc && found_chunk_create);
	Trace.DataUsed();

	test.Next(_L("Cleanup after tests"));
	Trace.SetFilter(BTrace::EHeap,0);
	Trace.SetMode(0);
	r = Trace.ResizeBuffer(oldSize);
	test_KErrNone(r);

	test.End();
	}

void SetBTraceFilter(const TUint32* aNew,TUint32* aOld)
	{
	TUint category = 0;
	do
		{
		TUint32 newBits = *aNew++;
		TUint32 oldBits = 0;
		do
			{
			oldBits >>= 1;
			if(Trace.SetFilter(category,newBits&1))
				oldBits |= 0x80000000u;
			newBits >>= 1;
			++category;
			}
		while(category&31);
		if(aOld)
			*aOld++ = oldBits;
		}
	while(category<256);
	}


TUint32 OldTraceFilter[8] = {0};


//thread function to generate BTrace::EHeap::EHeapAllocFail event
LOCAL_D TInt ThreadtraceAllocFailTestThread(TAny* /*param*/)
  	{
  	RPointerArray<TInt32> array(1000);
  	TInt i = 1;
  	for(;;)
  		{
  		TInt32* p = new TInt32[(++i)*2];
  		if(!p)
  			break;
  		else
  			if(array.Append(p) == KErrNoMemory)
  				break;
  		}
  	array.ResetAndDestroy();
  	array.Close();
  	return 0;
  	}

//thread function to generate BTrace::EHeap::EHeapReAllocFail event
LOCAL_D TInt ThreadtraceReAllocFailTestThread(TAny* /*param*/)
	{
	TInt s = 4;
	TUint8 *p = (TUint8*)User::Alloc(s);
	for(;;)
		{
		s *= 2;
		TUint8* np = (TUint8*)User::ReAlloc(p, s);
		if(!np)
			{
			delete [] p;
			break;
			}
		else
			p=np;
		}
	return 0;
	}



//---------------------------------------------------------------------------------------------------------------------
//! @SYMTestCaseID				KBASE-T_BTRACE-0733
//! @SYMTestCaseDesc			Test BTrace - EHeapAllocFail and EHeapReAllocFail subcategories.
//! @SYMTestType				UT
//! @SYMPREQ					PREQ1340
//! @SYMTestPriority			Medium
//! @SYMTestActions
//! 	1.	Configure BTrace to use EHeap and EThreadIdentification as main filter
//!			categories.
//! 	2.	Create and start a thread which will eventually exhaust
//!			all memory resources (this should result with sending a trace
//!			from allocator class - sent trace should have
//!			category - EHeap and subcategory - EHeapAllocFail).
//! 	3.	After thread (from previous point) crashes, get trace data from BTrace
//!			and search for trace with category EHeap and subcategory EHeapAllocFail
//!		4.	Validate trace data payload - it should have exactly 8 bytes (2x4 bytes values).
//!
//! @SYMTestExpectedResults
//! 	1.	Trace data should contain at least one trace with category
//!			EHeap and subcategory EHeapAllocFail.
//! 	2.	Trace data payload (where category is EHeap and subcategory is EHeapAllocFail) should
//!			be 8 bytes long (2 x 4 bytes values).
//---------------------------------------------------------------------------------------------------------------------
void TestHeapAllocFailEvent(TInt aTestCategory)
	{
	//configurnig trace
	if(aTestCategory == BTrace::EHeapAllocFail)
		test.Next(_L("Test to check BTrace::EHeap::EHeapAllocFail trace event"));
	else if(aTestCategory == BTrace::EHeapReAllocFail)
		test.Next(_L("Test to check BTrace::EHeap::EHeapReAllocFail trace event"));
	//configure BTrace
	Trace.Open();
	Trace.SetMode(0);
	TInt r = Trace.ResizeBuffer(0x100000);

	test_KErrNone(r);
	Trace.SetFilter(BTrace::EHeap,0);
	Trace.SetFilter(BTrace::EChunks,0);
	Trace.SetMode(RBTrace::EEnable);
	Trace.SetFilter(BTrace::EHeap,1);
	Trace.SetFilter(BTrace::EThreadIdentification,1);

	//start thread to cause EHeapAllocFail event
	RThread thread;
	TRequestStatus stat;

	//starting test thread
	if(aTestCategory == BTrace::EHeapAllocFail)
		r = thread.Create(_L("t_btrace_allocfail_thread"), ThreadtraceAllocFailTestThread, KDefaultStackSize, 0x2000, 0x2000, NULL);
	else if(aTestCategory == BTrace::EHeapReAllocFail)
		r = thread.Create(_L("t_btrace_reallocfail_thread"), ThreadtraceReAllocFailTestThread, KDefaultStackSize, 0x2000, 0x2000, NULL);

	test_KErrNone(r);
	thread.Logon(stat);
	thread.Resume();
	User::WaitForRequest(stat);
	thread.Close();

	//getting trace data
	TUint8* data;
	TUint8* trace;
	TInt size=Trace.GetData(trace);

	test_NotNull(size);
	TUint8* end = trace+size;
	TInt8 found_heap_allocfail = 0;

	TInt subCat = BTrace::EHeapAllocFail;
	TInt expectedDataSize = 8;
	if(aTestCategory == BTrace::EHeapReAllocFail)
		{
		subCat = BTrace::EHeapReAllocFail;
		expectedDataSize = 12;
		}

	for(data=trace; data<end; data=BTrace::NextRecord(data))
		{
		if(data[BTrace::ECategoryIndex]==BTrace::EHeap)
			if(data[BTrace::ESubCategoryIndex]==subCat)
				{
				found_heap_allocfail = 1;
				TInt allocfail_data_size = ((TInt)data[BTrace::ESizeIndex]) - ExtraSize(data);
				test_Equal(allocfail_data_size,expectedDataSize);
				break; //we're looking only for one record
				}
		}
	test(found_heap_allocfail);

	//closing trace
	Trace.DataUsed();
	Trace.Empty();
	Trace.SetMode(0);
	Trace.Close();
	}


bool FindHeapCorruptionTrace(TUint8* aData, TInt aSize, TInt& aFoundSize)
	{
	TUint8* end = aData+aSize;
	TUint8* data;
	for(data=aData; data<end; data=BTrace::NextRecord(data))
		{
		if(data[BTrace::ECategoryIndex] == BTrace::EHeap)
			if(data[BTrace::ESubCategoryIndex] == BTrace::EHeapCorruption)
				{
				aFoundSize = data[BTrace::ESizeIndex] - ExtraSize(data);
				return true;
				}
		}
	return false;
	}


//---------------------------------------------------------------------------------------------------------------------
//! @SYMTestCaseID				KBASE-T_BTRACE-0734
//! @SYMTestCaseDesc			Test BTrace - EHeapCorruption subcategory.
//! @SYMTestType				UT
//! @SYMPREQ					PREQ1340
//! @SYMTestPriority			Medium
//! @SYMTestActions
//! 	1.	Configure BTrace to use EHeap and EThreadIdentification categories.
//! 	2.	Use test application (t_heapcorruption.exe) with parameters: 1, 2, 3 or 4 to
//!			to corrupt heap memory (for this application)
//! 	3.	Get trace data from BTrace and search for trace with category EHeap and
//!			subcategory EHeapCorruption.
//!		4.	Validate payload size for found traces.
//!
//! @SYMTestExpectedResults
//! 	1.	Test application (when started with either argument) should generate at least
//!			one trace with category EHeap and subcategory EHeapCorruption.
//! 	2.	Trace data payload should be 12 bytes long (3x4 bytes values).
//---------------------------------------------------------------------------------------------------------------------
void TestHeapCorruptionEvents()
	{
	TInt r = KErrNone;
	test.Next(_L("Test to check BTrace::EHeap::EHeapCorruption trace events"));
	//configure BTrace
	Trace.Open();
	Trace.SetMode(0);
	Trace.ResizeBuffer(0x100000);
	test_KErrNone(r);
	Trace.SetFilter(BTrace::EHeap,0);
	Trace.SetFilter(BTrace::EChunks,0);
	Trace.SetMode(RBTrace::EEnable);
	Trace.SetFilter(BTrace::EHeap,1);
	Trace.SetFilter(BTrace::EThreadIdentification,1);

	_LIT(KHeapCorrApp, "t_heapcorruption.exe");
	_LIT(KCorruption0, "0"); //RHeap:: corruption type (when EMonitorMemory flag is set)
	_LIT(KCorruption1, "1"); //RHeap::EBadFreeCellAddress corruption type
	_LIT(KCorruption2, "2"); //RHeap::EBadFreeCellSize corruption type
	_LIT(KCorruption3, "3"); //RHeap::EBadAllocatedCellSize corruption type
	_LIT(KCorruption4, "4"); //RHeap::EBadAllocatedCellAddress corruption type
	_LIT(KCorruptionSpecial1, "1000"); //RHeap::EBadAllocatedCellSize (with EMonitorMemory flag set)
	RProcess p;
	TInt e = KErrNone;
	TRequestStatus status;
	TUint8* trace;
	TInt size, payloadSize;
	bool res;

	//test 0 (for memory monitoring tools - when EMonitorMemory heap flag is set)
	test.Printf(_L("test 0\n"));
	Trace.SetMode(RBTrace::EEnable);
	e = p.Create(KHeapCorrApp, KCorruption0);
	test_KErrNone(e);
	p.Resume();
	p.Logon(status);
	User::WaitForRequest(status);
	p.Close();
	size = Trace.GetData(trace);
	test_NotNull(size);
	res = FindHeapCorruptionTrace(trace, size, payloadSize);
	test(res==true);
	test(payloadSize == 12); //payload in this case must be 12 bytes long (3x4bytes)
	Trace.DataUsed();
	Trace.Empty();
	Trace.SetMode(0);

	//test 1 -
	test.Printf(_L("test 1\n"));
	Trace.SetMode(RBTrace::EEnable);
	e = p.Create(KHeapCorrApp, KCorruption1);
	test_KErrNone(e);
	p.Resume();
	p.Logon(status);
	User::WaitForRequest(status);
	p.Close();
	size = Trace.GetData(trace);
	test_NotNull(size);
	res = FindHeapCorruptionTrace(trace, size, payloadSize);
	test(res==true);
	test(payloadSize == 12); //payload in this case must be 12 bytes long (3x4bytes)
	Trace.DataUsed();
	Trace.Empty();
	Trace.SetMode(0);

	//test 2
	test.Printf(_L("test 2\n"));
	Trace.SetMode(RBTrace::EEnable);
	e = p.Create(KHeapCorrApp, KCorruption2);
	test_KErrNone(e);
	p.Resume();
	p.Logon(status);
	User::WaitForRequest(status);
	p.Close();
	size = Trace.GetData(trace);
	test_NotNull(size);
	res = FindHeapCorruptionTrace(trace, size, payloadSize);
	test(res==true);
	test(payloadSize == 12); //payload in this case must be 12 bytes long (3x4bytes)
	Trace.DataUsed();
	Trace.Empty();
	Trace.SetMode(0);

	//test 3
	test.Printf(_L("test 3\n"));
	Trace.SetMode(RBTrace::EEnable);
	e = p.Create(KHeapCorrApp, KCorruption3);
	test_KErrNone(e);
	p.Resume();
	p.Logon(status);
	User::WaitForRequest(status);
	p.Close();
	size = Trace.GetData(trace);
	test_NotNull(size);
	res = FindHeapCorruptionTrace(trace, size, payloadSize);
	test(res==true);
	test(payloadSize == 12); //payload in this case must be 12 bytes long (3x4bytes)
	Trace.DataUsed();
	Trace.Empty();
	Trace.SetMode(0);

	//test 4
	test.Printf(_L("test 4\n"));
	Trace.SetMode(RBTrace::EEnable);
	e = p.Create(KHeapCorrApp, KCorruption4);
	test_KErrNone(e);
	p.Resume();
	p.Logon(status);
	User::WaitForRequest(status);
	p.Close();
	size = Trace.GetData(trace);
	test_NotNull(size);
	res = FindHeapCorruptionTrace(trace, size, payloadSize);
	test(res==true);
	test(payloadSize == 12); //payload in this case must be 12 bytes long (3x4bytes)
	Trace.DataUsed();
	Trace.Empty();
	Trace.SetMode(0);

	//test 5 (test ____MEMORY_MONITOR_CHECK_CELL macro)
	test.Printf(_L("test 5\n"));
	Trace.SetMode(RBTrace::EEnable);
	e = p.Create(KHeapCorrApp, KCorruptionSpecial1);
	test_KErrNone(e);
	p.Resume();
	p.Logon(status);
	User::WaitForRequest(status);
	p.Close();
	size = Trace.GetData(trace);
	test_NotNull(size);
	res = FindHeapCorruptionTrace(trace, size, payloadSize);
	test(res==true);
	test(payloadSize == 12); //payload in this case must be 12 bytes long (3x4bytes)
	Trace.DataUsed();
	Trace.Empty();
	Trace.SetMode(0);

	//closing trace
	Trace.DataUsed();
	Trace.Empty();
	Trace.SetMode(0);
	Trace.Close();
	}


//Set up utrace
TUint32 KUtracePcValues[3]={0, 0x123456, 0x987654};

#define T_UTRACE_HEADER(aSize,aClassification,aContext,aPc)																\
	((((aSize) + (aContext?4:0) + (aPc?4:0)) << BTrace::ESizeIndex*8)										\
	+(((aContext?BTrace::EContextIdPresent:0) | (aPc?BTrace::EPcPresent:0)) << BTrace::EFlagsIndex*8)			\
	+((aClassification) << BTrace::ECategoryIndex*8)																				\
	+((KTest1SubCategory) << BTrace::ESubCategoryIndex*8))

#define UTRACE_SECONDARY(aClassification,aModuleUid,aThreadIdPresent,aPcPresent,aPc,aFormatId)	\
	BTrace::OutFilteredPcFormatBig(T_UTRACE_HEADER(8,aClassification,aThreadIdPresent,aPcPresent),(TUint32)(aModuleUid),aPc,aFormatId,0,0)

#define UTRACE_SECONDARY_4(aClassification,aModuleUid,aThreadIdPresent,aPcPresent,aPc,aFormatId, aData1) \
	BTrace::OutFilteredPcFormatBig(T_UTRACE_HEADER(8,aClassification,aThreadIdPresent,aPcPresent),(TUint32)(aModuleUid),aPc,aFormatId,&aData1,4)

#define UTRACE_SECONDARY_ANY(aClassification, aModuleUid, aThreadIdPresent, aPcPresent, aPc, aFormatId, aData, aDataSize) \
	BTrace::OutFilteredPcFormatBig(T_UTRACE_HEADER(8,aClassification,aThreadIdPresent,aPcPresent),(TUint32)(aModuleUid),aPc,aFormatId,aData,(TInt)(aDataSize))

void UTraceUserBenchmark(TUint& aTime1,TUint& aTime2,TUint& aTime3,TBool aTraceEnabled)
	{
	TInt oldSize = Trace.BufferSize();

	RTimer timer;
	TRequestStatus status;
	test_KErrNone(timer.CreateLocal());

	TInt r = Trace.ResizeBuffer(0x1000);
	test_KErrNone(r);
	Trace.SetMode(RBTrace::EFreeRunning|RBTrace::EEnable);

	timer.After(status,1);
	User::WaitForRequest(status);
	timer.After(status,1000000);
	r = 0;
	TUint32* frm = (TUint32*)KTestTrace1;
	TUint16 formatId = (TUint16)frm[2];

	do
		{
		UTRACE_SECONDARY(BTrace::ETest1,KBTraceFilterTestUid1,EFalse,EFalse,0,formatId);
		++r;
		}
	while(status==KRequestPending);
	User::WaitForRequest(status);
	TUint8* data;
	TInt size = Trace.GetData(data);
	test(aTraceEnabled ? size!=0 : size==0);
	Trace.DataUsed();
	aTime1 = 1000000000/r;

	r = Trace.ResizeBuffer(0x1000);
	test_KErrNone(r);
	Trace.SetMode(RBTrace::EFreeRunning|RBTrace::EEnable);

	timer.After(status,1);
	User::WaitForRequest(status);
	timer.After(status,1000000);
	r = 0;
	do
		{
		//BTraceFilteredContextN(BTrace::ETest1,0,KBTraceFilterTestUid1,0,KTestTrace1,KMaxBTraceDataArray);
		UTRACE_SECONDARY_ANY(BTrace::ETest1,KBTraceFilterTestUid1,ETrue,EFalse,0,formatId,KTestTrace1,KMaxBTraceDataArray);
		++r;
		}
	while(status==KRequestPending);
	User::WaitForRequest(status);
	size = Trace.GetData(data);
	test(aTraceEnabled ? size!=0 : size==0);
	Trace.DataUsed();
	aTime2 = 1000000000/r;

	timer.After(status,1);
	User::WaitForRequest(status);
	timer.After(status,1000000);
	r = 0;
	TBool check = -1;
	do
		{
		check = BTrace::CheckFilter2(BTrace::ETest1,KBTraceFilterTestUid1);
		++r;
		}
	while(status==KRequestPending);
	test(check == aTraceEnabled);
	aTime3 = 1000000000/r;

	r = Trace.ResizeBuffer(oldSize);
	test_KErrNone(r);
	}

//---------------------------------------------
//! @SYMTestCaseID 		KBASE-T_BTRACE-2442
//! @SYMTestType 		UT
//! @SYMPREQ 			CR1623
//! @SYMTestCaseDesc 	Benchmark utracing.
//! @SYMTestActions 	Time the generation of minimum and maximum sized utraces both with
//!						and without the trace filter enabled for the trace category.
//! @SYMTestExpectedResults Trace time with filter enabled should not excede 2000 nano-seconds,
//!						and time with filter disabled should not excede 500 nano-seconds. (These limits are not
//!						asserted). If time significantly excedes this then detailed investigation is required.
//! @SYMTestPriority 	Medium
//! @SYMTestStatus 		Prototype
//---------------------------------------------
void TestUtraceBenchmark(TBool aUserTrace)
	{
	TUint t1 = 0;
	TUint t2 = 0;
	TUint t3 = 0;
//This uses btrace kernel benching atm, need to change once kernel is implemented
#define UBENCH(a1) aUserTrace ? UTraceUserBenchmark(t1,t2,t3,a1) : KernelBenchmark(t1,t2,t3,a1,1)

	test.Printf(_L("                                      Min Trace   Max Trace      Filter\n"));

	Trace.SetFilter(BTrace::ETest1,0);
	Trace.SetFilter2(0);
	UBENCH(0);
	test.Printf(_L("filter1 off   filter2 off             %6d ns   %6d ns   %6d ns\n"),t1,t2,t3);

	Trace.SetFilter(BTrace::ETest1,1);
	Trace.SetFilter2(0);
	UBENCH(0);
	test.Printf(_L("filter1 on    global filter2 off      %6d ns   %6d ns   %6d ns\n"),t1,t2,t3);

	Trace.SetFilter2(1);
	UBENCH(1);
	test.Printf(_L("filter1 on    global filter2 on       %6d ns   %6d ns   %6d ns\n"),t1,t2,t3);

	Trace.SetFilter2(&KBTraceFilterTestUid2,1);
	UBENCH(0);
	test.Printf(_L("filter1 on    1 UID filter2 off       %6d ns   %6d ns   %6d ns\n"),t1,t2,t3);

	Trace.SetFilter2(&KBTraceFilterTestUid1,1);
	UBENCH(1);
	test.Printf(_L("filter1 on    1 UID filter2 on        %6d ns   %6d ns   %6d ns\n"),t1,t2,t3);

	Trace.SetFilter2(BigFilter2,sizeof(BigFilter2)/sizeof(TUint32));
	Trace.SetFilter2(KBTraceFilterTestUid1,0);
	UBENCH(0);
	test.Printf(_L("filter1 on    100 UID filter2 off     %6d ns   %6d ns   %6d ns\n"),t1,t2,t3);

	Trace.SetFilter2(BigFilter2,sizeof(BigFilter2)/sizeof(TUint32));
	UBENCH(1);
	test.Printf(_L("filter1 on    100 UID filter2 on      %6d ns   %6d ns   %6d ns\n"),t1,t2,t3);

	Trace.SetFilter(BTrace::ETest1,0);
	Trace.SetFilter2(0);
	}


void CallUtrace(TBool aType, TBool aContextPresent, TBool aPcPresent, TInt aSizeOfData)
	{
	if(!(aType&RBTraceTest::EUserTrace))
		{
		// use driver to create a kernel trace...
		TraceTest.Trace(aType,KTestTrace1,aSizeOfData);
		return;
		}

	TUint32* data = (TUint32*)KTestTrace1;
	TUint16 formatId = (TUint16)data[2];
	//multiparted traces (depending on size)
	if(aSizeOfData <= 0)
		{
		UTRACE_SECONDARY(BTrace::ETest1, KBTraceFilterTestUid1, aContextPresent, aPcPresent, KUtracePcValues[1], formatId);
		UTRACE_SECONDARY(BTrace::ETest1, KBTraceFilterTestUid1, aContextPresent, aPcPresent, KUtracePcValues[2], formatId);
		}
	else if(aSizeOfData <= 4)
		{
		UTRACE_SECONDARY_4(BTrace::ETest1, KBTraceFilterTestUid1, aContextPresent, aPcPresent, KUtracePcValues[1], formatId, data[3]);
		UTRACE_SECONDARY_4(BTrace::ETest1, KBTraceFilterTestUid1, aContextPresent, aPcPresent, KUtracePcValues[2], formatId, data[3]);
		}
	else //aSizeOfData > 8
		{
		UTRACE_SECONDARY_ANY(BTrace::ETest1, KBTraceFilterTestUid1, aContextPresent, aPcPresent, KUtracePcValues[1], formatId, data+3, aSizeOfData);
		UTRACE_SECONDARY_ANY(BTrace::ETest1, KBTraceFilterTestUid1, aContextPresent, aPcPresent, KUtracePcValues[2], formatId, data+3, aSizeOfData);
		//BTraceFilteredContextPcBig(BTrace::ETest1,KTest1SubCategory,KBTraceFilterTestUid1,data+2,aSizeOfData-4);
		//BTraceFilteredContextPcBig(BTrace::ETest1,KTest1SubCategory,KBTraceFilterTestUid1,data+2,aSizeOfData-4);
		}
	}


void CheckUtraceFlags(TUint8* aData, TUint8* aData2, TBool aContextPresent, TBool aPcPresent)
	{
	TUint offset = ContextOffset(aData);
	if(aContextPresent)
		{
		aContextPresent = BTrace::EContextIdPresent;
		test((aContextPresent == (aData[BTrace::EFlagsIndex]&BTrace::EContextIdPresent)));
		test_Equal(ThisTraceContextId, ((TUint32*)(aData+offset))[0] );
		test_Equal(ThisTraceContextId, ((TUint32*)(aData2+offset))[0] );
		}
	if(aPcPresent)
		{
		aPcPresent = BTrace::EPcPresent;
		test((aPcPresent == (aData[BTrace::EFlagsIndex]&BTrace::EPcPresent)));
		if(aContextPresent)
			{
			test_Compare(((TUint32*)(aData+offset))[1], ==, KUtracePcValues[1]); //(offset plus 1 because context id is before pc)
			test_Compare(((TUint32*)(aData2+offset))[1], ==, KUtracePcValues[2]);
			}
		else
			{
			test_Compare(((TUint32*)(aData+offset))[0], ==, KUtracePcValues[1]);
			test_Compare(((TUint32*)(aData2+offset))[0], ==, KUtracePcValues[2]);
			}
		}
	}

void SetupTestDataForUtrace(TBool aChangeData = ETrue)
	{
	if(aChangeData)//change to accomodate iFormatId only being 16 bit
		{
			KTestTrace1[10] = (TUint8) 0;
			KTestTrace1[11] = (TUint8) 0;
		}
	else //restore to original data
		{
		KTestTrace1[10] = (TUint8) 10;
		KTestTrace1[11] = (TUint8) 11;
		}
	}

//---------------------------------------------
//! @SYMTestCaseID 			KBASE-T_BTRACE-2441
//! @SYMTestType 			UT
//! @SYMPREQ 				CR1623
//! @SYMTestCaseDesc 		Test UTraces, including multiparted utraces, only testing user side for now, kernel side will be added later
//! @SYMTestActions			Generate traces from kernel code using the UTrace macros as defined above,
//! @SYMTestExpectedResults Traces where broken down into multiple parts and
//!							all trace contents captured by RBTrace matched those specified
//!							at point of trace generation. Also, where appropriate, PC and/or
//!							Context ID values are present and correct.
//! @SYMTestPriority 		High
//! @SYMTestStatus 			Prototype
//---------------------------------------------
void TestUtrace(TBool aUserTrace, TBool aFilter2)
	{
	test.Next(_L("Testing utrace\n"));
	TInt oldSize = Trace.BufferSize();
	TInt r = Trace.ResizeBuffer(0x100000);
	test_KErrNone(r);
	Trace.SetMode(RBTrace::EEnable);

	//set up the test data for UTrace
	SetupTestDataForUtrace();

	// dummy trace do get current thread context id
	Trace.SetFilter(BTrace::ETest1,0);
	ThisTraceContextId = TraceTest.Trace(BTrace::EContextIdPresent,KTestTrace1,0);

	// create a test filter...
	TInt extraFlags = 0;
	if(aUserTrace)
		extraFlags |= RBTraceTest::EUserTrace;
	TInt minSize = 4;
	if(aFilter2)
		{
		extraFlags |= RBTraceTest::EFilter2Trace;
		minSize += 4;
		}

	//Test that filtering works...
	TInt filterMode;
	for(filterMode=0; filterMode<(aFilter2?6:2); ++filterMode)
		{

		// setup filters...
		Trace.SetFilter(BTrace::ETest1,1);
		Trace.SetFilter2(BigFilter2,KNumBTraceFilterTestUids);
		if(filterMode==0 || filterMode==2)
			Trace.SetFilter(BTrace::ETest1,0); // disable in primary filter
		if(filterMode==0 || filterMode==1)
			Trace.SetFilter2(KBTraceFilterTestUid1,0); // disable in secondary filter
		if(filterMode==4)
			Trace.SetFilter2(0); // disable entire secondary filter
		if(filterMode==5)
			Trace.SetFilter2(1); // enable entire secondary filter

		// expectTrace is true if we expect trace to be output...
		TBool expectTrace = aFilter2 ? (filterMode==3 || filterMode==5) : filterMode&1;

		switch(filterMode)
			{
		case 0: test.Next(_L("Test with primary filter OFF, secondary filter OFF")); break;
		case 1: test.Next(_L("Test with primary filter ON, secondary filter OFF")); break;
		case 2: test.Next(_L("Test with primary filter OFF, secondary filter ON")); break;
		case 3: test.Next(_L("Test with primary filter ON, secondary filter ON")); break;
		case 4: test.Next(_L("Test with primary filter ON, global secondary filter OFF")); break;
		case 5: test.Next(_L("Test with primary filter ON, global secondary filter ON")); break;
			}

		TBool contextPresent = EFalse;
		TBool pcPresent = EFalse;
		for(TInt flags = 0; flags < 4; flags++)
			{
			switch(flags)
				{
				case 0:	test.Printf(_L("ContextId OFF, Pc OFF\n")); break;
				case 1: contextPresent = ETrue; extraFlags = BTrace::EContextIdPresent|BTrace::EPcPresent|extraFlags; test.Printf(_L("ContextId ON, Pc OFF\n"));break;
				case 2: pcPresent = ETrue; extraFlags = BTrace::EContextIdPresent|BTrace::EPcPresent|extraFlags; test.Printf(_L("ContextId OFF, Pc ON\n"));break;
				case 3: contextPresent = ETrue; pcPresent = ETrue; extraFlags = BTrace::EContextIdPresent|BTrace::EPcPresent|extraFlags; test.Printf(_L("ContextId ON, Pc ON\n"));break;
				}

			// multiparted traces...
			BigTraceBeginTest();
			for(TInt i=0; i<=(TInt)sizeof(KTestTrace1)-4; i++)
				{
				//CallUtrace(typeOfCall, contextPresent, pcPresent, i);
				CallUtrace(extraFlags, contextPresent, pcPresent, i);

				TUint8* data;
				TUint8* data2;
				TInt size = Trace.GetData(data);
				if(!expectTrace)
					{
					test(!size);
					continue;
					}
				size /= 2;
				data2 = data+size;

				TInt sizePlusFormatId = i + 8;
				test(CheckBigTrace1(data, size, sizePlusFormatId, KTest1SubCategory, 4));
				test(CheckBigTrace1(data2, size, sizePlusFormatId, KTest1SubCategory, 4));

				CheckUtraceFlags(data, data2, contextPresent, pcPresent);
				Trace.DataUsed();
				}
			test_Equal(expectTrace,BigTraceEndTest()); // check we actually got multipart traces
			}
		}

	//Restore trace data
	SetupTestDataForUtrace(EFalse);

	test.Next(_L("Restore buffer\n"));
	r = Trace.ResizeBuffer(oldSize);
	test_KErrNone(r);
	Trace.SetFilter2(0);
	}



GLDEF_C TInt E32Main()
    {
	// initialise test trace data...
	KTestTrace1[0] = BTrace::ETest1;
	TUint i;
	for(i=8; i<sizeof(KTestTrace1); i++)
		{
		KTestTrace1[i] = (TUint8)i;
		KTestTrace2[i] = (TUint8)~i;
		}
	KTestTrace1[4] = (KBTraceFilterTestUid1>>0)&0xff;
	KTestTrace1[5] = (KBTraceFilterTestUid1>>8)&0xff;
	KTestTrace1[6] = (KBTraceFilterTestUid1>>16)&0xff;
	KTestTrace1[7] = (KBTraceFilterTestUid1>>24)&0xff;

	KTestTrace2[4] = (KBTraceFilterTestUid2>>0)&0xff;
	KTestTrace2[5] = (KBTraceFilterTestUid2>>8)&0xff;
	KTestTrace2[6] = (KBTraceFilterTestUid2>>16)&0xff;
	KTestTrace2[7] = (KBTraceFilterTestUid2>>24)&0xff;

	for(i=0; i<KNumBTraceFilterTestUids; i++)
		BigFilter2[i] = KBTraceFilterTestUid+i;

	test.Title();
	TInt r;

	test.Start(_L("Open LDD"));
	r = Trace.Open();
	test_KErrNone(r);

	test.Next(_L("Open test LDD"));
	r = User::LoadLogicalDevice(RBTraceTest::Name());
	test(r==KErrNone || r==KErrAlreadyExists);
	r = TraceTest.Open();
	test_KErrNone(r);

	// save trace settings...
	TUint savedMode = Trace.Mode();
	SetBTraceFilter(OldTraceFilter,OldTraceFilter);

	TBuf<256> commandLine;
	User::CommandLine(commandLine);
	if(commandLine==_L("dump"))
		{
		test.Next(_L("Dumping trace buffer..."));
		DumpTrace();
		goto done;
		}
	else if(commandLine==_L("soak"))
		{
		test.Next(_L("Running endless soak test..."));
		for(;;)
			{
			test.Next(_L("Soak test in free-running mode"));
			TestSoak(RBTrace::EFreeRunning,60);
			test.Next(_L("Soak test in sample mode"));
			TestSoak(0,60);
			}
		}

	test.Next(_L("Basic tests in sample mode"));
	TestBasics(0);
	test.Next(_L("Basic tests in free-running mode"));
	TestBasics(RBTrace::EFreeRunning);
	test.Next(_L("User BTrace test in sample mode"));
	TestUserTrace(0);
	test.Next(_L("Check secondary filter"));
	TestFilter2();

	test.Next(_L("Test user traces"));
	TestTrace(ETrue,EFalse);
	test.Next(_L("Test kernel traces"));
	TestTrace(EFalse,EFalse);
	test.Next(_L("Test user traces using secondary filter"));
	TestTrace(ETrue,ETrue);
	test.Next(_L("Test kernel traces using secondary filter"));
	TestTrace(EFalse,ETrue);

	test.Next(_L("Big user traces"));
	TestBig(ETrue,EFalse);
	test.Next(_L("Big kernel traces"));
	TestBig(EFalse,EFalse);
	test.Next(_L("Big user traces using secondary filter"));
	TestBig(ETrue,ETrue);
	test.Next(_L("Big kernel traces using secondary filter"));
	TestBig(EFalse,ETrue);

	test.Next(_L("Test category EThreadIdentification"));
	TestThreadIdentification();
	test.Next(_L("Test category ECpuUsage"));
	TestCpuUsage();

	test.Next(_L("Soak test in sample mode"));
	TestSoak(0,10);
	test.Next(_L("Soak test in free-running mode"));
	TestSoak(RBTrace::EFreeRunning,10);

	test.Next(_L("Benchmark kernel tracing"));
	TestBenchmark(0);
	test.Next(_L("Benchmark user tracing"));
	TestBenchmark(1);

	test.Next(_L("Test category EHeap"));
	TestHeapAndChunkTrace();

	test.Next(_L("Test user side utraces"));
	TestUtrace(ETrue, ETrue);
	//Kernel side is currently not implemented
	//test.Next(_L("Test kernel side utraces"));
	//TestUtrace(EFalse, ETrue);
	test.Next(_L("Benchmark user side UTraces"));
	TestUtraceBenchmark(ETrue);

done:
	// restore trace settin	gs...
	Trace.SetMode(0);
	SetBTraceFilter(OldTraceFilter,OldTraceFilter);
	Trace.SetMode(savedMode);

	test.Next(_L("Close LDD"));
	Trace.Close();
	TraceTest.Close();
	User::FreeLogicalDevice(RBTraceTest::Name());

	//test RHeap instrumentation:
	//with BTrace:EHeap:EHeapAllocFail trace points
	TestHeapAllocFailEvent(BTrace::EHeapAllocFail);
	//with BTrace:EHeap:EHeapReAllocFail trace points
	TestHeapAllocFailEvent(BTrace::EHeapReAllocFail);
	//with BTrace:EHeap:EHeapCorruption trace points
	TestHeapCorruptionEvents();

	test.End();
	return(0);
    }

