Convert Kernelhwsrv package from SFL to EPL
kernel\eka\compsupp is subject to the ARM EABI LICENSE
userlibandfileserver\fatfilenameconversionplugins\unicodeTables is subject to the Unicode license
kernel\eka\kernel\zlib is subject to the zlib license
// 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);
}