// Copyright (c) 2002-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:
//
#include <e32test.h>
#include <e32svr.h>
#include "bm_suite.h"
class Thread : public BMProgram
{
public :
Thread() : BMProgram(_L("Threads"))
{}
virtual TBMResult* Run(TBMUInt64 aIter, TInt* aCount);
typedef void (*MeasurementFunc)(TBMResult*, TBMUInt64 aIter);
struct Measurement
{
MeasurementFunc iFunc;
TPtrC iName;
Measurement(MeasurementFunc aFunc, const TDesC& aName) :
iFunc(aFunc), iName(aName) {}
};
static TBMResult iResults[];
static Measurement iMeasurements[];
static TBMTicks iChildTime;
static void Creation(TBMResult*, TBMUInt64 aIter);
static TInt CreationChild(TAny*);
static void CreationSuicide(TBMResult*, TBMUInt64 aIter);
static TInt CreationSuicideChild(TAny*);
static void Suicide(TBMResult*, TBMUInt64 aIter);
static TInt SuicideChild(TAny*);
static void Killing(TBMResult*, TBMUInt64 aIter);
static TInt KillingChild(TAny*);
static void SetTls(TBMResult*, TBMUInt64 aIter);
static void GetTls(TBMResult*, TBMUInt64 aIter);
void EnableCleanup()
{
TInt prio = BMProgram::SetAbsPriority(RThread(), iOrigAbsPriority);
BMProgram::SetAbsPriority(RThread(), prio);
}
};
Thread::Measurement Thread::iMeasurements[] =
{
Measurement(&Thread::Creation, _L("Thread Creation Latency")),
Measurement(&Thread::CreationSuicide, _L("Thread Creation Suicide")),
Measurement(&Thread::Suicide, _L("Thread Suicide")),
Measurement(&Thread::Killing, _L("Thread Killing")),
Measurement(&Thread::SetTls, _L("Setting per-thread data")),
Measurement(&Thread::GetTls, _L("Getting per-thread data"))
};
TBMResult Thread::iResults[sizeof(Thread::iMeasurements)/sizeof(Thread::iMeasurements[0])];
TBMTicks Thread::iChildTime;
static Thread prog;
void Thread::Creation(TBMResult* aResult, TBMUInt64 aIter)
{
for (TBMUInt64 i = 0; i < aIter; ++i)
{
RThread child;
TRequestStatus st;
TBMTicks t1;
::bmTimer.Stamp(&t1);
TInt r = child.Create(KNullDesC, Thread::CreationChild, 0x2000, NULL, NULL);
BM_ERROR(r, r == KErrNone);
child.Logon(st);
BMProgram::SetAbsPriority(RThread(), KBMPriorityHigh);
child.Resume();
User::WaitForRequest(st);
BM_ERROR(st.Int(), st == KErrNone);
aResult->Cumulate(TBMTicksDelta(t1, iChildTime));
CLOSE_AND_WAIT(child);
prog.EnableCleanup();
}
}
TInt Thread::CreationChild(TAny*)
{
::bmTimer.Stamp(&iChildTime);
return KErrNone;
}
void Thread::CreationSuicide(TBMResult* aResult, TBMUInt64 aIter)
{
for (TBMUInt64 i = 0; i < aIter; ++i)
{
RThread child;
TRequestStatus st;
TBMTicks t1;
::bmTimer.Stamp(&t1);
TInt r = child.Create(KNullDesC, Thread::CreationSuicideChild, 0x2000, NULL, NULL);
BM_ERROR(r, r == KErrNone);
child.Logon(st);
BMProgram::SetAbsPriority(RThread(), KBMPriorityLow);
child.Resume();
User::WaitForRequest(st);
BM_ERROR(st.Int(), st == KErrNone);
TBMTicks t2;
::bmTimer.Stamp(&t2);
aResult->Cumulate(TBMTicksDelta(t1, t2));
CLOSE_AND_WAIT(child);
prog.EnableCleanup();
}
}
TInt Thread::CreationSuicideChild(TAny*)
{
return KErrNone;
}
void Thread::Suicide(TBMResult* aResult, TBMUInt64 aIter)
{
for (TBMUInt64 i = 0; i < aIter; ++i)
{
RThread child;
TRequestStatus st;
TInt r = child.Create(KNullDesC, Thread::SuicideChild, 0x2000, NULL, NULL);
BM_ERROR(r, r == KErrNone);
child.Logon(st);
BMProgram::SetAbsPriority(RThread(), KBMPriorityLow);
child.Resume();
User::WaitForRequest(st);
BM_ERROR(st.Int(), st == KErrNone);
TBMTicks t2;
::bmTimer.Stamp(&t2);
aResult->Cumulate(TBMTicksDelta(iChildTime, t2));
CLOSE_AND_WAIT(child);
prog.EnableCleanup();
}
}
TInt Thread::SuicideChild(TAny*)
{
::bmTimer.Stamp(&iChildTime);
return KErrNone;
}
void Thread::Killing(TBMResult* aResult, TBMUInt64 aIter)
{
for (TBMUInt64 i = 0; i < aIter; ++i)
{
RThread child;
TRequestStatus st;
TInt r = child.Create(KNullDesC, Thread::KillingChild, 0x2000, NULL, NULL);
BM_ERROR(r, r == KErrNone);
child.Logon(st);
BMProgram::SetAbsPriority(RThread(), KBMPriorityHigh);
child.Resume();
TBMTicks t1;
::bmTimer.Stamp(&t1);
child.Kill(KErrCancel);
User::WaitForRequest(st);
BM_ERROR(st.Int(), st == KErrCancel);
TBMTicks t2;
::bmTimer.Stamp(&t2);
aResult->Cumulate(TBMTicksDelta(t1, t2));
CLOSE_AND_WAIT(child);
prog.EnableCleanup();
}
}
TInt Thread::KillingChild(TAny*)
{
User::WaitForAnyRequest();
return KErrNone;
}
#define TLS_KEY ((TInt32) &Thread::SetTls)
void Thread::SetTls(TBMResult* aResult, TBMUInt64 aIter)
{
aIter <<= 4;
TBMTimeInterval ti;
ti.Begin();
for (TBMUInt64 i = 0; i < aIter; ++i)
{
TInt r = UserSvr::DllSetTls(TLS_KEY, 0);
BM_ERROR(r, r == KErrNone);
}
TBMTicks t = ti.End();
aResult->Cumulate(t, aIter);
UserSvr::DllFreeTls(TLS_KEY);
}
void Thread::GetTls(TBMResult* aResult, TBMUInt64 aIter)
{
aIter <<= 4;
TInt r = UserSvr::DllSetTls(TLS_KEY, 0);
BM_ERROR(r, r == KErrNone);
TBMTimeInterval ti;
ti.Begin();
for (TBMUInt64 i = 0; i < aIter; ++i)
{
UserSvr::DllTls(TLS_KEY);
}
TBMTicks t = ti.End();
aResult->Cumulate(t, aIter);
UserSvr::DllFreeTls(TLS_KEY);
}
TBMResult* Thread::Run(TBMUInt64 aIter, TInt* aCount)
{
TInt count = sizeof(iResults)/sizeof(iResults[0]);
for (TInt i = 0; i < count; ++i)
{
iResults[i].Reset(iMeasurements[i].iName);
iMeasurements[i].iFunc(&iResults[i], aIter);
iResults[i].Update();
}
*aCount = count;
return iResults;
}
void AddThread()
{
BMProgram* next = bmSuite;
bmSuite=(BMProgram*)&prog;
bmSuite->Next()=next;
}