kerneltest/e32test/misc/t_loadsim.cpp
branchRCL_3
changeset 256 c1f20ce4abcf
equal deleted inserted replaced
249:a179b74831c9 256:c1f20ce4abcf
       
     1 // Copyright (c) 2009-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32test\misc\t_loadsim.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 
       
    19 //-------------------------------------------------------------------------------------------
       
    20 //! @SYMTestCaseID				KBASE-t_loadsim-2705
       
    21 //! @SYMTestCaseDesc			verifying the behaviour of the load balancer
       
    22 //! @SYMPREQ					417-52765/417-58889
       
    23 //! @SYMTestPriority			Critical
       
    24 //! @SYMTestActions				
       
    25 //! 1. This test runs a variety of loads on an SMP system. Loads types are:
       
    26 //!    1.1 Cpu intensive loads
       
    27 //!    1.2 memory intensive loads (high locality)
       
    28 //!    1.3 memory intensive loads (low locality)
       
    29 //!    1.4 memory intensive loads with atomic operations
       
    30 //!    1.5 cpu intensive loads with some serialization
       
    31 //! 2. For each test, the load is first run on a single cpu locked thread as a baseline
       
    32 //!    benchmark. Then the tests are run in the following configurations:
       
    33 //!    2.1 For n = 1 to 2*Number of cpus do a run with i threads.
       
    34 //!    2.2 For h = 1 to NumCpus ; For n = h to 2*NumCpus; run with h high priorty threads and 
       
    35 //!         n standard priority threads, with high priority threads cpu locked.
       
    36 //!    2.3 For h = 1 to NumCpus ; For n = h to 2*NumCpus; run with h high priorty threads and 
       
    37 //!         n standard priority threads.
       
    38 //! @SYMTestExpectedResults 
       
    39 //!     test passed. TTest is manual:
       
    40 //! 1. For each test we expect to see that the amount of CPU time obtained by each CPU is 
       
    41 //!     balanced. That is, all standard priority threads get roughly same amount of CPU time
       
    42 //!     and all high priority threads get roughly same amount of CPU time and a higher value
       
    43 //!     than lower priority threads.
       
    44 //! 2. We also expect the relative efficiency reported by the test between the benchmark
       
    45 //!    and each test run to be >=95% on average. Values well below this are acceptable in 
       
    46 //!    test runs involving atomic operations (1.4)
       
    47 
       
    48 //-------------------------------------------------------------------------------------------
       
    49 
       
    50 #define __E32TEST_EXTENSION__
       
    51 #include <e32test.h>
       
    52 #include <e32base.h>
       
    53 #include <hal.h>
       
    54 #include <e32atomics.h>
       
    55 #include <u32hal.h>
       
    56 #include <e32svr.h>
       
    57 
       
    58 //#define	TRACE(x)	x
       
    59 #define	TRACE(x)
       
    60 
       
    61 void Panic(TInt aLine)
       
    62 	{
       
    63 	User::Panic(_L("T_LOADSIM"),aLine);
       
    64 	}
       
    65 
       
    66 #define	assert(x)		((void)((x)||(Panic(__LINE__),0)))
       
    67 
       
    68 RTest test(_L("T_LOADSIM"));
       
    69 
       
    70 const TInt KErrCouldNotStart = -99;
       
    71 
       
    72 volatile TInt STFU = 1;
       
    73 
       
    74 /******************************************************************************
       
    75  * Random Number Generation
       
    76  ******************************************************************************/
       
    77 void LFSR(TUint64& a)
       
    78 	{
       
    79 	TInt i;
       
    80 	for (i=64; i>0; --i)
       
    81 		{
       
    82 		TUint64 x = a<<1;
       
    83 		TUint64 y = x<<1;
       
    84 		x^=y;
       
    85 		a = (y>>1) | (x>>63);
       
    86 		}
       
    87 	}
       
    88 
       
    89 // Returns 256*log2(a/2^64)
       
    90 TInt Log2(TUint64 a)
       
    91 	{
       
    92 	const TUint64 KBit63 = UI64LIT(0x8000000000000000);
       
    93 	TInt n = __e32_find_ms1_64(a);
       
    94 	a <<= (63-n);
       
    95 	n -= 64;
       
    96 	TInt i;
       
    97 	for (i=0; i<8; ++i)
       
    98 		{
       
    99 		a >>= 32;
       
   100 		a *= a;
       
   101 		n <<= 1;
       
   102 		if (a & KBit63)
       
   103 			{
       
   104 			++n;
       
   105 			}
       
   106 		else
       
   107 			{
       
   108 			a <<= 1;
       
   109 			}
       
   110 		}
       
   111 	return n;
       
   112 	}
       
   113 
       
   114 TUint32 ExpRV(TUint64 aU, TUint32 aMean, TUint32 aTick)
       
   115 	{
       
   116 	TInt n = -Log2(aU);
       
   117 	TUint64 x = TUint64(n) * TUint64(aMean);
       
   118 	x *= TUint64(22713);	// 2^15 * ln2
       
   119 	TUint64 p(aTick);
       
   120 	p <<= 22;
       
   121 	x += p;
       
   122 	p += p;
       
   123 	x /= p;
       
   124 	return I64LOW(x);
       
   125 	}
       
   126 
       
   127 
       
   128 
       
   129 /******************************************************************************
       
   130  * Generic High-Resolution Timing
       
   131  ******************************************************************************/
       
   132 class TTimestamp
       
   133 	{
       
   134 public:
       
   135 	typedef void (*TSampleFunc)(TAny*);
       
   136 public:
       
   137 	void Sample();
       
   138 	void Sample(TSampleFunc aFunc, TAny* aPtr);
       
   139 	TInt64 operator-(const TTimestamp&) const;
       
   140 	static void Init();
       
   141 private:
       
   142 	TUint32		iF;		// User::FastCounter() value
       
   143 	TUint32		iN;		// User::NTickCount() value
       
   144 private:
       
   145 	static TUint32 FF;	// User::FastCounter() frequency
       
   146 	static TUint32 NP;	// User::NTickCount() period
       
   147 	static TBool FU;	// User::FastCounter() counts up
       
   148 	static TUint32 FWrapM;	// Number of nanokernel ticks for FastCounter() to wrap / 2 * 2^FWrapS
       
   149 	static TInt FWrapS;	// Shift so that 2^31<=FWrapM<2^32
       
   150 	};
       
   151 
       
   152 TUint32	TTimestamp::FF;
       
   153 TUint32	TTimestamp::NP;
       
   154 TBool	TTimestamp::FU;
       
   155 TUint32	TTimestamp::FWrapM;
       
   156 TInt	TTimestamp::FWrapS;
       
   157 
       
   158 
       
   159 void TTimestamp::Sample()
       
   160 	{
       
   161 	TUint32 n = User::NTickCount();
       
   162 	do	{
       
   163 		iN = n;
       
   164 		iF = User::FastCounter();
       
   165 		n = User::NTickCount();
       
   166 		} while (n!=iN);
       
   167 	}
       
   168 
       
   169 void TTimestamp::Sample(TSampleFunc aFunc, TAny* aPtr)
       
   170 	{
       
   171 	TUint32 n = User::NTickCount();
       
   172 	do	{
       
   173 		iN = n;
       
   174 		(*aFunc)(aPtr);
       
   175 		iF = User::FastCounter();
       
   176 		n = User::NTickCount();
       
   177 		} while (n!=iN);
       
   178 	}
       
   179 
       
   180 // return (x*a)/b
       
   181 TUint64 scale(TUint64 x, TUint32 a, TUint32 b)
       
   182 	{
       
   183 	TUint64 mask = KMaxTUint32;
       
   184 	TUint64 x0 = x & mask;
       
   185 	TUint64 x1 = x >> 32;
       
   186 	x0 *= TUint64(a);
       
   187 	x1 *= TUint64(a);
       
   188 	x1 += (x0 >> 32);
       
   189 	x0 &= mask;
       
   190 	TUint64	q1 = x1 / TUint64(b);
       
   191 	TUint64 q0 = x1 - q1*TUint64(b);
       
   192 	q0 <<= 32;
       
   193 	q0 |= x0;
       
   194 	q0 /= TUint64(b);
       
   195 	return (q1<<32)|q0;
       
   196 	}
       
   197 
       
   198 
       
   199 // Return difference between a and this in microseconds
       
   200 TInt64 TTimestamp::operator-(const TTimestamp& a) const
       
   201 	{
       
   202 	TInt sign = 1;
       
   203 	TTimestamp start;
       
   204 	TTimestamp end;
       
   205 	if (iN-a.iN >= 0x80000000u)
       
   206 		{
       
   207 		sign = -1;
       
   208 		start = *this;
       
   209 		end = a;
       
   210 		}
       
   211 	else
       
   212 		{
       
   213 		start = a;
       
   214 		end = *this;
       
   215 		}
       
   216 	TUint32 fd32 = end.iF - start.iF;
       
   217 	if (!FU)
       
   218 		fd32 = ~fd32 + 1u;
       
   219 	TUint64 nd = TUint64(end.iN) - TUint64(start.iN);
       
   220 	nd <<= 31;	// 2^31 * difference in NTickCount
       
   221 	TUint64 x = TUint64(fd32) * TUint64(FWrapM);
       
   222 	x >>= FWrapS;	// ftick difference * (FWrapM/2^FWrapS) = 2^31 * ntick difference
       
   223 	nd -= x;	// Should now be a multiple of 2^31N where N=2^32*ftickp/ntickp
       
   224 				// i.e. should be a multiple of 2^63*ftickp/ntickp
       
   225 
       
   226 	// FWrapM = 2^(31+FWrapS)*ftickp/ntickp
       
   227 	// FWrapM << (32-FWrapS) = 2^63*ftickp/ntickp
       
   228 	TUint64 m = TUint64(FWrapM) << (32-FWrapS);
       
   229 
       
   230 	nd += (m>>1);
       
   231 	nd /= m;
       
   232 
       
   233 	nd = (nd<<32) + TUint64(fd32);	// final result in fast counter ticks
       
   234 	TInt64 r = scale(nd, 1000000, FF);	// convert to microseconds
       
   235 	if (sign<0)
       
   236 		r = -r;
       
   237 	return r;
       
   238 	}
       
   239 
       
   240 void TTimestamp::Init()
       
   241 	{
       
   242 	TInt r;
       
   243 	r = HAL::Get(HAL::ENanoTickPeriod, (TInt&)NP);
       
   244 	assert(r==KErrNone);
       
   245 	r = HAL::Get(HAL::EFastCounterFrequency, (TInt&)FF);
       
   246 	assert(r==KErrNone);
       
   247 	r = HAL::Get(HAL::EFastCounterCountsUp, (TInt&)FU);
       
   248 	assert(r==KErrNone);
       
   249 	TReal fpn = TReal(FF) * TReal(NP) / 1000000.0;	// fast counter ticks per NTick
       
   250 	TReal fwrap = 2147483648.0 / fpn;	// NTicks between fast counter wraparounds / 2
       
   251 	TInt exp = 0;
       
   252 	while (fwrap < 2147483648.0)
       
   253 		{
       
   254 		fwrap *= 2.0;
       
   255 		++exp;
       
   256 		}
       
   257 	fwrap += 0.5;
       
   258 	if (fwrap >= 4294967296.0)
       
   259 		{
       
   260 		fwrap *= 0.5;
       
   261 		--exp;
       
   262 		}
       
   263 	FWrapM = (TUint32)fwrap;
       
   264 	FWrapS = exp;	// NTicks for 2^31 fast ticks = FWrapM/2^FWrapS
       
   265 
       
   266 	test.Printf(_L("FastCounter frequency  %uHz\n"), FF);
       
   267 	if (FU)
       
   268 		test.Printf(_L("FastCounter counts     UP\n"));
       
   269 	else
       
   270 		test.Printf(_L("FastCounter counts     DOWN\n"));
       
   271 	test.Printf(_L("Nanokernel tick period %uus\n"), NP);
       
   272 	test.Printf(_L("FWrapM                 %08x\n"), FWrapM);
       
   273 	test.Printf(_L("FWrapS                 %d\n"), FWrapS);
       
   274 	}
       
   275 
       
   276 /******************************************************************************
       
   277  * CPU Usage Measurement
       
   278  ******************************************************************************/
       
   279 class TThreadCpuUsageSample
       
   280 	{
       
   281 public:
       
   282 	void Sample(RThread aThread);
       
   283 	TInt64 ElapsedTimeDelta(const TThreadCpuUsageSample& aStart) const;
       
   284 	TInt64 CpuTimeDelta(const TThreadCpuUsageSample& aStart) const;
       
   285 private:
       
   286 	static void SampleThreadCpuTime(TAny* aPtr);
       
   287 private:
       
   288 	TTimestamp	iElapsedTime;
       
   289 	TInt64		iCpuTime;
       
   290 	RThread		iThread;
       
   291 	};
       
   292 
       
   293 void TThreadCpuUsageSample::Sample(RThread aThread)
       
   294 	{
       
   295 	iThread = aThread;
       
   296 	iElapsedTime.Sample(&SampleThreadCpuTime, this);
       
   297 	}
       
   298 
       
   299 void TThreadCpuUsageSample::SampleThreadCpuTime(TAny* aPtr)
       
   300 	{
       
   301 	TThreadCpuUsageSample& me = *(TThreadCpuUsageSample*)aPtr;
       
   302 	TTimeIntervalMicroSeconds& rt = *(TTimeIntervalMicroSeconds*)&me.iCpuTime;
       
   303 	assert(me.iThread.GetCpuTime(rt) == KErrNone);
       
   304 	}
       
   305 
       
   306 TInt64 TThreadCpuUsageSample::ElapsedTimeDelta(const TThreadCpuUsageSample& aStart) const
       
   307 	{
       
   308 	return iElapsedTime - aStart.iElapsedTime;
       
   309 	}
       
   310 
       
   311 TInt64 TThreadCpuUsageSample::CpuTimeDelta(const TThreadCpuUsageSample& aStart) const
       
   312 	{
       
   313 	return iCpuTime - aStart.iCpuTime;
       
   314 	}
       
   315 
       
   316 class TCpuUsage
       
   317 	{
       
   318 public:
       
   319 	enum {EMaxCpus=8};
       
   320 public:
       
   321 	void Sample();
       
   322 	TInt64 ElapsedTimeDelta(const TCpuUsage& aStart) const;
       
   323 	TInt64 CpuTimeDelta(const TCpuUsage& aStart, TInt aCpu) const;
       
   324 	static TInt N() { return NumberOfCpus; }
       
   325 public:
       
   326 	static void Init();
       
   327 private:
       
   328 	static void SampleIdleTimes(TAny* aPtr);
       
   329 private:
       
   330 	TTimestamp	iElapsedTime;
       
   331 	TInt64		iIdleTime[EMaxCpus];
       
   332 private:
       
   333 	static TInt NumberOfCpus;
       
   334 	static RThread IdleThread[EMaxCpus];
       
   335 	};
       
   336 
       
   337 TInt TCpuUsage::NumberOfCpus = -1;
       
   338 RThread TCpuUsage::IdleThread[TCpuUsage::EMaxCpus];
       
   339 
       
   340 void TCpuUsage::Init()
       
   341 	{
       
   342 	TTimestamp::Init();
       
   343 
       
   344 	NumberOfCpus = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0);
       
   345 	test.Printf(_L("NumberOfCpus = %d\n"), NumberOfCpus);
       
   346 	assert(NumberOfCpus > 0);
       
   347 	assert(NumberOfCpus <= EMaxCpus);
       
   348 
       
   349 	TTimeIntervalMicroSeconds ms;
       
   350 	TInt r;
       
   351 	r = RThread().GetCpuTime(ms);
       
   352 	if (r != KErrNone)
       
   353 		{
       
   354 		test.Printf(_L("RThread::GetCpuTime() returned %d\n"), r);
       
   355 		test.Printf(_L("This test requires a working RThread::GetCpuTime() to run\n"));
       
   356 		test(0);
       
   357 		}
       
   358 
       
   359 	TFullName kname;
       
   360 	_LIT(KLitKernelName, "ekern.exe*");
       
   361 	_LIT(KLitNull, "::Null");
       
   362 	TFindProcess fp(KLitKernelName);
       
   363 	test_KErrNone(fp.Next(kname));
       
   364 	test.Printf(_L("Found kernel process: %S\n"), &kname);
       
   365 	kname.Append(KLitNull);
       
   366 	TInt i;
       
   367 	for (i=0; i<NumberOfCpus; ++i)
       
   368 		{
       
   369 		TFullName tname(kname);
       
   370 		TFullName tname2;
       
   371 		if (i>0)
       
   372 			tname.AppendNum(i);
       
   373 		TFindThread ft(tname);
       
   374 		test_KErrNone(ft.Next(tname2));
       
   375 		TInt r = IdleThread[i].Open(ft);
       
   376 		test_KErrNone(r);
       
   377 		IdleThread[i].FullName(tname2);
       
   378 		test.Printf(_L("Found and opened %S\n"), &tname2);
       
   379 		}
       
   380 	}
       
   381 
       
   382 void TCpuUsage::Sample()
       
   383 	{
       
   384 	iElapsedTime.Sample(&SampleIdleTimes, this);
       
   385 	}
       
   386 
       
   387 void TCpuUsage::SampleIdleTimes(TAny* aPtr)
       
   388 	{
       
   389 	TCpuUsage& me = *(TCpuUsage*)aPtr;
       
   390 	assert(NumberOfCpus > 0);
       
   391 	TInt i;
       
   392 	for (i=0; i<NumberOfCpus; ++i)
       
   393 		assert(IdleThread[i].GetCpuTime((TTimeIntervalMicroSeconds&)me.iIdleTime[i]) == KErrNone);
       
   394 	}
       
   395 
       
   396 TInt64 TCpuUsage::ElapsedTimeDelta(const TCpuUsage& aStart) const
       
   397 	{
       
   398 	return iElapsedTime - aStart.iElapsedTime;
       
   399 	}
       
   400 
       
   401 TInt64 TCpuUsage::CpuTimeDelta(const TCpuUsage& aStart, TInt aCpu) const
       
   402 	{
       
   403 	assert(TUint(aCpu) < TUint(EMaxCpus));
       
   404 	if (aCpu >= NumberOfCpus)
       
   405 		return 0;
       
   406 	TInt64 idle_time = iIdleTime[aCpu] - aStart.iIdleTime[aCpu];
       
   407 	TInt64 elapsed_time = iElapsedTime - aStart.iElapsedTime;
       
   408 	return elapsed_time - idle_time;
       
   409 	}
       
   410 
       
   411  
       
   412  
       
   413 /******************************************************************************
       
   414  * Generic CPU Consumer
       
   415  ******************************************************************************/
       
   416 enum TCpuEaterType
       
   417 	{
       
   418 	EEaterStd				=0,		// do CPU-intensive work with few memory references
       
   419 	EEaterMemoryLocalS		=1,		// do loads of memory references with reasonable locality, shared
       
   420 	EEaterMemoryNonLocalS	=2,		// do loads of memory references with poor locality, shared
       
   421 	EEaterMemoryLocalU		=3,		// do loads of memory references with reasonable locality, unshared
       
   422 	EEaterMemoryNonLocalU	=4,		// do loads of memory references with poor locality, unshared
       
   423 	EEaterMemoryAtomic		=5,		// do loads of atomic memory references
       
   424 	EEaterMemoryAtomic2		=6,		// do loads of atomic memory references
       
   425 	EEaterAmdahl			=7,		// do CPU-intensive work interspersed with serialized sections
       
   426 	};
       
   427 
       
   428 class CDefaultCpuEater;
       
   429 
       
   430 class REaterArray;
       
   431 class MCpuEater
       
   432 	{
       
   433 public:
       
   434 	MCpuEater();
       
   435 	virtual ~MCpuEater();
       
   436 	virtual void Eat(TInt aTime, TUint32* aWorkDone)=0;
       
   437 	virtual void Calibrate();
       
   438 	inline TBool IsCalibrated() { return iCalibration!=0; }
       
   439 protected:
       
   440 	TUint32 WorkValue(TInt aTime);
       
   441 	TUint32	iCalibration;	// work value for 2^16 microseconds
       
   442 	TUint16	iInstance;
       
   443 	TUint16	iType;
       
   444 
       
   445 	friend class REaterArray;
       
   446 	};
       
   447 
       
   448 MCpuEater::MCpuEater()
       
   449 	{
       
   450 	iCalibration = 0;			// uncalibrated
       
   451 	iInstance = KMaxTUint16;	// dummy value
       
   452 	iType = KMaxTUint16;		// dummy value
       
   453 	}
       
   454 
       
   455 MCpuEater::~MCpuEater()
       
   456 	{
       
   457 	}
       
   458 
       
   459 // Calibration is for 2^KLog2CalibrateTime microseconds
       
   460 const TInt KLog2CalibrateTime = 13;
       
   461 
       
   462 TUint32 MCpuEater::WorkValue(TInt aTime)
       
   463 	{
       
   464 	if (iCalibration == 0)
       
   465 		return aTime;
       
   466 	TUint64 x = TUint64(aTime) * TUint64(iCalibration);
       
   467 	x >>= (KLog2CalibrateTime + 2);	// Factor of 4 margin for slowdowns
       
   468 	TUint32 r = I64LOW(x);
       
   469 	if (I64HIGH(x))
       
   470 		r = KMaxTUint32;
       
   471 	if (r == 0)
       
   472 		return 1;
       
   473 	if (r > iCalibration)
       
   474 		return iCalibration;
       
   475 	return r;
       
   476 	}
       
   477 
       
   478 void MCpuEater::Calibrate()
       
   479 	{
       
   480 	iCalibration = 0;
       
   481 	TUint32 work = 1;
       
   482 	TUint64 used = 1;
       
   483 	TUint64 threshold = 1;
       
   484 	threshold <<= KLog2CalibrateTime;
       
   485 	while (work)
       
   486 		{
       
   487 		TThreadCpuUsageSample initial;
       
   488 		TThreadCpuUsageSample final;
       
   489 		initial.Sample(RThread());
       
   490 		Eat(work, 0);
       
   491 		final.Sample(RThread());
       
   492 		used = final.CpuTimeDelta(initial);
       
   493 		if (used >= threshold)
       
   494 			break;
       
   495 		work <<= 1;
       
   496 		}
       
   497 	assert(work > 0);
       
   498 	TUint64 c(work);
       
   499 	c <<= KLog2CalibrateTime;
       
   500 	c /= used;
       
   501 	if (I64HIGH(c))
       
   502 		iCalibration = KMaxTUint32;
       
   503 	else if (I64LOW(c))
       
   504 		iCalibration = I64LOW(c);
       
   505 	else
       
   506 		iCalibration = 1;
       
   507 	test.Printf(_L("MCpuEater::Calibrate() %u\n"), iCalibration);
       
   508 	}
       
   509 
       
   510 
       
   511 class REaterArray : public RPointerArray<MCpuEater>
       
   512 	{
       
   513 public:
       
   514 	REaterArray();
       
   515 	void Close();
       
   516 	MCpuEater* Find(TInt aType, TInt aInstance);
       
   517 	MCpuEater* FindOrCreateL(TInt aType, TInt aInstance);
       
   518 private:
       
   519 	MCpuEater* CreateLC(TInt aType);
       
   520 private:
       
   521 	class MDummy : public MCpuEater
       
   522 		{
       
   523 	public:
       
   524 		MDummy(TInt aType, TInt aInstance)
       
   525 			{ iType=TUint16(aType); iInstance=TUint16(aInstance); }
       
   526 		virtual ~MDummy()
       
   527 			{}
       
   528 		virtual void Eat(TInt, TUint32*)
       
   529 			{}
       
   530 		};
       
   531 private:
       
   532 	static TBool Identity(const MCpuEater& aL, const MCpuEater& aR);
       
   533 	static TInt Ordering(const MCpuEater& aL, const MCpuEater& aR);
       
   534 	};
       
   535 
       
   536 REaterArray::REaterArray()
       
   537 	:	RPointerArray<MCpuEater>(8, 2*256)
       
   538 	{
       
   539 	}
       
   540 
       
   541 void REaterArray::Close()
       
   542 	{
       
   543 	ResetAndDestroy();
       
   544 	}
       
   545 
       
   546 TBool REaterArray::Identity(const MCpuEater& aL, const MCpuEater& aR)
       
   547 	{
       
   548 	return (aL.iType==aR.iType && aL.iInstance==aR.iInstance);
       
   549 	}
       
   550 
       
   551 TInt REaterArray::Ordering(const MCpuEater& aL, const MCpuEater& aR)
       
   552 	{
       
   553 	if (aL.iType > aR.iType)
       
   554 		return 1;
       
   555 	if (aL.iType < aR.iType)
       
   556 		return -1;
       
   557 	if (aL.iInstance > aR.iInstance)
       
   558 		return 1;
       
   559 	if (aL.iInstance < aR.iInstance)
       
   560 		return -1;
       
   561 	return 0;
       
   562 	}
       
   563 
       
   564 MCpuEater* REaterArray::Find(TInt aType, TInt aInstance)
       
   565 	{
       
   566 	MDummy search(aType, aInstance);
       
   567 	TInt ix = FindInOrder(&search, &Ordering);
       
   568 	if (ix < 0)
       
   569 		return 0;
       
   570 	return (*this)[ix];
       
   571 	}
       
   572 
       
   573 MCpuEater* REaterArray::FindOrCreateL(TInt aType, TInt aInstance)
       
   574 	{
       
   575 	MCpuEater* p = Find(aType, aInstance);
       
   576 	if (p)
       
   577 		return p;
       
   578 	p = CreateLC(aType);
       
   579 	p->iType = TUint16(aType);
       
   580 	p->iInstance = TUint16(aInstance);
       
   581 	InsertInOrderL(p, &Ordering);
       
   582 	CleanupStack::Pop();
       
   583 	return p;
       
   584 	}
       
   585 
       
   586 /******************************************************************************
       
   587  * Generic zero-drift timed events
       
   588  ******************************************************************************/
       
   589 class CLoadSim;
       
   590 class MEvent
       
   591 	{
       
   592 public:
       
   593 	MEvent(CLoadSim*, TInt);
       
   594 	virtual void Start()=0;
       
   595 	virtual ~MEvent();
       
   596 	inline TBool Queued() const
       
   597 		{ return iQueued; }
       
   598 protected:
       
   599 	void QueueAt(TUint32 aTime);
       
   600 	void QueueAfter(TUint32 aInterval);
       
   601 	void Dequeue();
       
   602 	virtual TInt Event();
       
   603 	inline TUint64 Random();
       
   604 protected:
       
   605 	TUint8		iId;
       
   606 	TUint8		iQueued;
       
   607 	TUint8		iE1;
       
   608 	TUint8		iE2;
       
   609 	MEvent*		iChain;
       
   610 	CLoadSim*	iT;
       
   611 	TUint32		iNextEventTime;
       
   612 	friend class CLoadSim;
       
   613 	};
       
   614 
       
   615 class CLoadSim : public CActive
       
   616 	{
       
   617 public:
       
   618 	static CLoadSim* NewL();
       
   619 	~CLoadSim();
       
   620 	inline TInt TimerPeriod() const
       
   621 		{ return iTimerPeriod; }
       
   622 	TUint64 Random();
       
   623 private:
       
   624 	CLoadSim();
       
   625 	virtual void RunL();
       
   626 	virtual void DoCancel();
       
   627 	void StartTimer();
       
   628 private:
       
   629 	RTimer		iTimer;
       
   630 	TUint64		iSeed;
       
   631 	MEvent*		iNextEvent;
       
   632 	TUint32		iIterations;
       
   633 	TUint32		iLastTrigger;		// Last trigger time in ticks
       
   634 	TInt		iCarry;
       
   635 	TInt		iTimerPeriod;		// Timer tick period in microseconds
       
   636 	TInt		iMaxDelta;
       
   637 	TUint8		iInRunL;
       
   638 	TUint8		iTimerRunning;
       
   639 	TUint8		iTimerInit;
       
   640 	TUint8		iOffsetInit;
       
   641 	TUint32		iOffset;
       
   642 private:
       
   643 	friend class MEvent;
       
   644 	};
       
   645 
       
   646 inline TUint64 MEvent::Random()
       
   647 	{ return iT->Random(); }
       
   648 
       
   649 CLoadSim::CLoadSim()
       
   650 	: CActive(EPriorityStandard)
       
   651 	{
       
   652 	iSeed = 0xadf85458;
       
   653 	assert(HAL::Get(HAL::ENanoTickPeriod, iTimerPeriod)==KErrNone);
       
   654 	iMaxDelta = KMaxTInt / (2*iTimerPeriod);
       
   655 	}
       
   656 
       
   657 CLoadSim::~CLoadSim()
       
   658 	{
       
   659 	Cancel();
       
   660 	iTimer.Close();
       
   661 	}
       
   662 
       
   663 CLoadSim* CLoadSim::NewL()
       
   664 	{
       
   665 	CLoadSim* p = new (ELeave) CLoadSim();
       
   666 	CleanupStack::PushL(p);
       
   667 	User::LeaveIfError(p->iTimer.CreateLocal());
       
   668 	CleanupStack::Pop();
       
   669 	return p;
       
   670 	}
       
   671 
       
   672 void CLoadSim::DoCancel()
       
   673 	{
       
   674 	iTimer.Cancel();
       
   675 	iTimerRunning = 0;
       
   676 	}
       
   677 
       
   678 void CLoadSim::RunL()
       
   679 	{
       
   680 	TRACE(RDebug::Printf("!%d\n", iStatus.Int()));
       
   681 	iTimerRunning = 0;
       
   682 	iInRunL = 1;
       
   683 	TUint32 now = iLastTrigger;
       
   684 	if (iStatus == KErrNone)
       
   685 		{
       
   686 		now += iCarry;
       
   687 		iLastTrigger = now;
       
   688 		}
       
   689 	else if (iStatus == KErrArgument)
       
   690 		{
       
   691 		now += iCarry;
       
   692 		}
       
   693 	else if (iStatus == KErrCancel)
       
   694 		{
       
   695 		iLastTrigger += iCarry;	// trigger time was still updated
       
   696 		}
       
   697 	iCarry = 0;
       
   698 	MEvent* e = 0;
       
   699 	FOREVER
       
   700 		{
       
   701 		++iIterations;
       
   702 		e = iNextEvent;
       
   703 		if (!e || e->iNextEventTime>now)
       
   704 			break;
       
   705 		iNextEvent = e->iChain;
       
   706 		e->iChain = 0;
       
   707 		e->iQueued = 0;
       
   708 		e->Event();
       
   709 		}
       
   710 	if (e)
       
   711 		{
       
   712 		TInt delta = TInt(e->iNextEventTime - iLastTrigger);
       
   713 		if (delta > iMaxDelta)
       
   714 			delta = iMaxDelta;
       
   715 		if (delta < -iMaxDelta)
       
   716 			delta = -iMaxDelta;
       
   717 		iCarry = delta;
       
   718 		TInt us = delta * iTimerPeriod;
       
   719 		TRACE(RDebug::Printf("T+%d\n", us));
       
   720 		iTimer.AgainHighRes(iStatus, us);
       
   721 		SetActive();
       
   722 		iTimerRunning = 1;
       
   723 		}
       
   724 	iInRunL = 0;
       
   725 	}
       
   726 
       
   727 void CLoadSim::StartTimer()
       
   728 	{
       
   729 	if (iInRunL)
       
   730 		return;
       
   731 	if (iTimerRunning)
       
   732 		{
       
   733 		TRACE(RDebug::Printf("TC\n"));
       
   734 		iTimer.Cancel();	// will cause RunL with KErrCancel which will restart timer
       
   735 		return;
       
   736 		}
       
   737 	TInt delta = TInt(iNextEvent->iNextEventTime - iLastTrigger);
       
   738 	if (delta > iMaxDelta)
       
   739 		delta = iMaxDelta;
       
   740 	if (delta < -iMaxDelta)
       
   741 		delta = -iMaxDelta;
       
   742 	iCarry = delta;
       
   743 	TInt us = delta * iTimerPeriod;
       
   744 	if (iTimerInit)
       
   745 		{
       
   746 		TRACE(RDebug::Printf("sT+%d\n", us));
       
   747 		iTimer.AgainHighRes(iStatus, us);
       
   748 		}
       
   749 	else
       
   750 		{
       
   751 		if (!iOffsetInit)
       
   752 			iOffsetInit=1, iOffset=User::NTickCount();
       
   753 		TRACE(RDebug::Printf("sT++%d\n", us));
       
   754 		iTimer.HighRes(iStatus, us);
       
   755 		iTimerInit = 1;
       
   756 		}
       
   757 	SetActive();
       
   758 	iTimerRunning = 1;
       
   759 	}
       
   760 
       
   761 TUint64 CLoadSim::Random()
       
   762 	{
       
   763 	LFSR(iSeed);
       
   764 	TUint32 h = I64HIGH(iSeed);
       
   765 	TUint32 l = I64LOW(iSeed);
       
   766 	h *= 0x9e3779b9u;
       
   767 	l *= 0x9e3779b9u;
       
   768 	return MAKE_TUINT64(l,h);
       
   769 	}
       
   770 
       
   771 MEvent::MEvent(CLoadSim* aT, TInt aId)
       
   772 	{
       
   773 	iId = (TUint8)aId;
       
   774 	iQueued = 0;
       
   775 	iE1 = 0;
       
   776 	iE2 = 0;
       
   777 	iChain = 0;
       
   778 	iT = aT;
       
   779 	iNextEventTime = 0;
       
   780 	}
       
   781 
       
   782 MEvent::~MEvent()
       
   783 	{
       
   784 	if (iT)
       
   785 		Dequeue();
       
   786 	}
       
   787 
       
   788 void MEvent::QueueAt(TUint32 aTime)
       
   789 	{
       
   790 	TRACE(RDebug::Printf("Q%d@%u\n", iId, aTime));
       
   791 	if (iQueued)
       
   792 		Dequeue();
       
   793 	MEvent** p = &iT->iNextEvent;
       
   794 	MEvent* e = iT->iNextEvent;
       
   795 	for (; e && e->iNextEventTime <= aTime; p=&e->iChain, e=e->iChain)
       
   796 		{}
       
   797 	iChain = e;
       
   798 	*p = this;
       
   799 	iNextEventTime = aTime;
       
   800 	iQueued = 1;
       
   801 	if (iT->iNextEvent==this && !iT->iInRunL)
       
   802 		iT->StartTimer();
       
   803 	}
       
   804 
       
   805 void MEvent::QueueAfter(TUint32 aInterval)
       
   806 	{
       
   807 	TRACE(RDebug::Printf("Q%d+%u\n", iId, aInterval));
       
   808 	TUint32 now = User::NTickCount();
       
   809 	if (!iT->iTimerInit)
       
   810 		iT->iOffset=now, iT->iOffsetInit=1;
       
   811 	QueueAt(now-iT->iOffset+aInterval);
       
   812 	}
       
   813 
       
   814 void MEvent::Dequeue()
       
   815 	{
       
   816 	TRACE(RDebug::Printf("DQ%d\n", iId));
       
   817 	if (!iQueued)
       
   818 		return;
       
   819 	MEvent* e = iT->iNextEvent;
       
   820 	for (; e && e->iChain!=this; e=e->iChain)
       
   821 		{}
       
   822 	if (e)
       
   823 		{
       
   824 		e->iChain = iChain;
       
   825 		}
       
   826 	iChain = 0;
       
   827 	iQueued = 0;
       
   828 	}
       
   829 
       
   830 TInt MEvent::Event()
       
   831 	{
       
   832 	TRACE(RDebug::Printf("*%d\n", iId));
       
   833 	return iId;
       
   834 	}
       
   835 
       
   836 
       
   837 
       
   838 /******************************************************************************
       
   839  * Poisson process simulation
       
   840  ******************************************************************************/
       
   841 class MDiscretePoisson : public MEvent
       
   842 	{
       
   843 public:
       
   844 	MDiscretePoisson(CLoadSim* aT, TInt aId, TUint32 aMicroseconds);
       
   845 	~MDiscretePoisson();
       
   846 	virtual void Start();
       
   847 	virtual TInt Event();
       
   848 	virtual void PoissonEvent();
       
   849 public:
       
   850 	TUint32		iUs;
       
   851 	TBool		iContinue;
       
   852 	};
       
   853 
       
   854 MDiscretePoisson::MDiscretePoisson(CLoadSim* aT, TInt aId, TUint32 aMicroseconds)
       
   855 	:	MEvent(aT, aId)
       
   856 	{
       
   857 	iUs = aMicroseconds;
       
   858 	iContinue = EFalse;
       
   859 	}
       
   860 
       
   861 MDiscretePoisson::~MDiscretePoisson()
       
   862 	{
       
   863 	}
       
   864 
       
   865 void MDiscretePoisson::Start()
       
   866 	{
       
   867 	iContinue = ETrue;
       
   868 	TUint32 gap = ExpRV(Random(), iUs, iT->TimerPeriod());
       
   869 	TRACE(RDebug::Printf("GG%u\n", gap));
       
   870 	QueueAt(iNextEventTime + gap);
       
   871 	}
       
   872 
       
   873 TInt MDiscretePoisson::Event()
       
   874 	{
       
   875 	PoissonEvent();
       
   876 	if (iContinue)
       
   877 		Start();
       
   878 	return MEvent::Event();
       
   879 	}
       
   880 
       
   881 void MDiscretePoisson::PoissonEvent()
       
   882 	{
       
   883 	}
       
   884 
       
   885 
       
   886 
       
   887 /******************************************************************************
       
   888  * Consume a specified amount of CPU time in either a continuous
       
   889  * or 'staccato' fashion (i.e. in irregular intervals punctuated by gaps)
       
   890  ******************************************************************************/
       
   891 class CStaccatoCpuEater : public CActive, public MEvent
       
   892 	{
       
   893 public:
       
   894 	CStaccatoCpuEater(CLoadSim* aT, MCpuEater* aE, TUint32 aGranularity, TUint32 aMeanGap);
       
   895 	~CStaccatoCpuEater();
       
   896 	void EatMore(TInt64 aMicroseconds);
       
   897 	TUint32 WorkDone() const { return iWorkDone; }
       
   898 	TUint32 Invocations() const { return iInvocations; }
       
   899 private:
       
   900 	virtual void RunL();
       
   901 	virtual void DoCancel();
       
   902 	virtual void Start();
       
   903 	virtual TInt Event();
       
   904 	void StartEating();
       
   905 private:
       
   906 	MCpuEater* iE;
       
   907 	TUint32 iWorkDone;
       
   908 	TUint32 iInvocations;
       
   909 	TUint32 iGranularity;
       
   910 	TUint32 iMeanGap;
       
   911 	TBool iEating;
       
   912 	TInt64 iRemainingCpuTime;
       
   913 	TTimeIntervalMicroSeconds iInitialCpuTime;
       
   914 	TTimeIntervalMicroSeconds iFinalCpuTime;
       
   915 	TInt64 iTotalCpuTime;
       
   916 	};
       
   917 
       
   918 CStaccatoCpuEater::CStaccatoCpuEater(CLoadSim* aT, MCpuEater* aE, TUint32 aGranularity, TUint32 aMeanGap)
       
   919 	:	CActive(EPriorityIdle),
       
   920 		MEvent(aT, 0x53)
       
   921 	{
       
   922 	iE = aE;
       
   923 	iWorkDone = 0;
       
   924 	iInvocations = 0;
       
   925 	iGranularity = aGranularity;
       
   926 	iMeanGap = aMeanGap;
       
   927 	iEating = EFalse;
       
   928 	iRemainingCpuTime = 0;
       
   929 	}
       
   930 
       
   931 CStaccatoCpuEater::~CStaccatoCpuEater()
       
   932 	{
       
   933 	Cancel();
       
   934 	}
       
   935 
       
   936 void CStaccatoCpuEater::EatMore(TInt64 aMicroseconds)
       
   937 	{
       
   938 	TRACE(RDebug::Printf("E+%08x %08x\n", I64HIGH(aMicroseconds), I64LOW(aMicroseconds)));
       
   939 	iRemainingCpuTime += aMicroseconds;
       
   940 	if (!Queued() && !iEating && iRemainingCpuTime>0)
       
   941 		StartEating();
       
   942 	}
       
   943 
       
   944 void CStaccatoCpuEater::RunL()
       
   945 	{
       
   946 	TInt time = KMaxTInt;
       
   947 	if (iRemainingCpuTime < TInt64(KMaxTInt))
       
   948 		time = I64LOW(iRemainingCpuTime);
       
   949 	++iInvocations;
       
   950 	iE->Eat(time, &iWorkDone);
       
   951 	TTimeIntervalMicroSeconds ms;
       
   952 	TInt r = RThread().GetCpuTime(ms);
       
   953 	assert(r==KErrNone);
       
   954 	if (ms < iFinalCpuTime)
       
   955 		{
       
   956 		SetActive();
       
   957 		TRequestStatus* pS = &iStatus;
       
   958 		User::RequestComplete(pS, 0);
       
   959 		return;
       
   960 		}
       
   961 	iEating = EFalse;
       
   962 	TInt64 delta = ms.Int64() - iInitialCpuTime.Int64();
       
   963 	iRemainingCpuTime -= delta;
       
   964 	iTotalCpuTime += delta;
       
   965 	TRACE(RDebug::Printf("D=%8u T=%10u\n",I64LOW(delta),I64LOW(iTotalCpuTime)));
       
   966 	if (iRemainingCpuTime > 0)
       
   967 		{
       
   968 		TUint32 gap = ExpRV(Random(), iMeanGap, iT->TimerPeriod());
       
   969 		TRACE(RDebug::Printf("G%u\n", gap));
       
   970 		QueueAfter(gap);
       
   971 		}
       
   972 	}
       
   973 
       
   974 void CStaccatoCpuEater::DoCancel()
       
   975 	{
       
   976 	MEvent::Dequeue();
       
   977 	iEating = EFalse;
       
   978 	}
       
   979 
       
   980 void CStaccatoCpuEater::Start()
       
   981 	{
       
   982 	}
       
   983 
       
   984 TInt CStaccatoCpuEater::Event()
       
   985 	{
       
   986 	if (!iEating && iRemainingCpuTime>0)
       
   987 		{
       
   988 		StartEating();
       
   989 		}
       
   990 	return MEvent::Event();
       
   991 	}
       
   992 
       
   993 void CStaccatoCpuEater::StartEating()
       
   994 	{
       
   995 	iEating = ETrue;
       
   996 	TInt r = RThread().GetCpuTime(iInitialCpuTime);
       
   997 	assert(r==KErrNone);
       
   998 	if (iGranularity)
       
   999 		{
       
  1000 		TInt howmuch = ExpRV(iT->Random(), iGranularity, 1);
       
  1001 		TRACE(RDebug::Printf("SE+%08x\n", howmuch));
       
  1002 		iFinalCpuTime = iInitialCpuTime.Int64() + TInt64(howmuch);
       
  1003 		}
       
  1004 	else
       
  1005 		iFinalCpuTime = iInitialCpuTime.Int64() + iRemainingCpuTime;	// continuous CPU use
       
  1006 	SetActive();
       
  1007 	TRequestStatus* pS = &iStatus;
       
  1008 	User::RequestComplete(pS, 0);
       
  1009 	}
       
  1010 
       
  1011 
       
  1012 
       
  1013 /******************************************************************************
       
  1014  * Consume CPU time in a bursty fashion
       
  1015  ******************************************************************************/
       
  1016 class CBurstyCpuEater : public CStaccatoCpuEater, public MDiscretePoisson
       
  1017 	{
       
  1018 public:
       
  1019 	struct SParams
       
  1020 		{
       
  1021 		MCpuEater*	iE;
       
  1022 		TUint32		iGranularity;
       
  1023 		TUint32		iMeanIntraBurstGap;
       
  1024 		TUint32		iMeanBurstLength;
       
  1025 		TUint32		iMeanInterBurstGap;
       
  1026 		};
       
  1027 public:
       
  1028 	CBurstyCpuEater(CLoadSim* aT, const SParams& aParams);
       
  1029 	~CBurstyCpuEater();
       
  1030 	virtual void Start();
       
  1031 	virtual void PoissonEvent();
       
  1032 public:
       
  1033 	TUint32		iMeanBurstLength;
       
  1034 	TUint32		iMeanInterBurstGap;
       
  1035 	};
       
  1036 
       
  1037 CBurstyCpuEater::CBurstyCpuEater(CLoadSim* aT, const SParams& aParams)
       
  1038 	:	CStaccatoCpuEater(aT, aParams.iE, aParams.iGranularity, aParams.iMeanIntraBurstGap),
       
  1039 		MDiscretePoisson(aT, 0x42, aParams.iMeanInterBurstGap)
       
  1040 	{
       
  1041 	iMeanBurstLength = aParams.iMeanBurstLength;
       
  1042 	iMeanInterBurstGap = aParams.iMeanInterBurstGap;
       
  1043 	}
       
  1044 
       
  1045 CBurstyCpuEater::~CBurstyCpuEater()
       
  1046 	{
       
  1047 	}
       
  1048 
       
  1049 void CBurstyCpuEater::Start()
       
  1050 	{
       
  1051 	if (iMeanInterBurstGap > 0)
       
  1052 		{
       
  1053 		PoissonEvent();
       
  1054 		MDiscretePoisson::Start();
       
  1055 		}
       
  1056 	else
       
  1057 		{
       
  1058 		EatMore(iMeanBurstLength);	// one single burst
       
  1059 		}
       
  1060 	}
       
  1061 
       
  1062 void CBurstyCpuEater::PoissonEvent()
       
  1063 	{
       
  1064 	TInt burstLen = ExpRV(CStaccatoCpuEater::Random(), iMeanBurstLength, 1);
       
  1065 	EatMore(burstLen);
       
  1066 	}
       
  1067 
       
  1068 
       
  1069 
       
  1070 /******************************************************************************
       
  1071  * Stop the active scheduler after a certain time
       
  1072  ******************************************************************************/
       
  1073 class CTimedStopper : public CActive
       
  1074 	{
       
  1075 public:
       
  1076 	static CTimedStopper* NewL();
       
  1077 	~CTimedStopper();
       
  1078 	void Start(TInt64 aMicroseconds);
       
  1079 private:
       
  1080 	CTimedStopper();
       
  1081 	virtual void RunL();
       
  1082 	virtual void DoCancel();
       
  1083 private:
       
  1084 	RTimer	iTimer;
       
  1085 	};
       
  1086 
       
  1087 CTimedStopper::CTimedStopper()
       
  1088 	:	CActive(EPriorityHigh)
       
  1089 	{
       
  1090 	}
       
  1091 
       
  1092 CTimedStopper::~CTimedStopper()
       
  1093 	{
       
  1094 	Cancel();
       
  1095 	iTimer.Close();
       
  1096 	}
       
  1097 
       
  1098 CTimedStopper* CTimedStopper::NewL()
       
  1099 	{
       
  1100 	CTimedStopper* p = new (ELeave) CTimedStopper();
       
  1101 	CleanupStack::PushL(p);
       
  1102 	User::LeaveIfError(p->iTimer.CreateLocal());
       
  1103 	CleanupStack::Pop();
       
  1104 	return p;
       
  1105 	}
       
  1106 
       
  1107 void CTimedStopper::DoCancel()
       
  1108 	{
       
  1109 	iTimer.Cancel();
       
  1110 	}
       
  1111 
       
  1112 void CTimedStopper::RunL()
       
  1113 	{
       
  1114 	CActiveScheduler::Stop();
       
  1115 	}
       
  1116 
       
  1117 void CTimedStopper::Start(TInt64 aMicroseconds)
       
  1118 	{
       
  1119 	TInt p = (TInt)aMicroseconds;
       
  1120 	iTimer.HighRes(iStatus, p);
       
  1121 	SetActive();
       
  1122 	}
       
  1123 
       
  1124 
       
  1125 
       
  1126 
       
  1127 
       
  1128 /******************************************************************************
       
  1129  * Do something CPU intensive to consume CPU time
       
  1130  ******************************************************************************/
       
  1131 class CDefaultCpuEater : public CBase, public MCpuEater
       
  1132 	{
       
  1133 public:
       
  1134 	CDefaultCpuEater();
       
  1135 	~CDefaultCpuEater();
       
  1136 	virtual void Eat(TInt aTime, TUint32* aWorkDone);
       
  1137 protected:
       
  1138 	TUint64 iX;
       
  1139 	};
       
  1140 
       
  1141 CDefaultCpuEater::CDefaultCpuEater()
       
  1142 	{
       
  1143 	iX = 1;
       
  1144 	}
       
  1145 
       
  1146 CDefaultCpuEater::~CDefaultCpuEater()
       
  1147 	{
       
  1148 	}
       
  1149 
       
  1150 void CDefaultCpuEater::Eat(TInt aTime, TUint32* aWorkDone)
       
  1151 	{
       
  1152 	const TUint64 KMagic = UI64LIT(0x9e3779b97f4a7c15);
       
  1153 	TUint32 work = WorkValue(aTime);
       
  1154 	if (aWorkDone)
       
  1155 		*aWorkDone += work;
       
  1156 	while (work--)
       
  1157 		iX *= KMagic;
       
  1158 	}
       
  1159 
       
  1160 
       
  1161 
       
  1162 /******************************************************************************
       
  1163  * Do something CPU intensive to consume CPU time, partially serialized
       
  1164  ******************************************************************************/
       
  1165 class CAmdahlCpuEater : public CDefaultCpuEater
       
  1166 	{
       
  1167 public:
       
  1168 	static CAmdahlCpuEater* NewLC();
       
  1169 	~CAmdahlCpuEater();
       
  1170 	virtual void Eat(TInt aTime, TUint32* aWorkDone);
       
  1171 protected:
       
  1172 	CAmdahlCpuEater();
       
  1173 	void ConstructL();
       
  1174 protected:
       
  1175 	RMutex iMutex;
       
  1176 	TUint32 iFactor;
       
  1177 	};
       
  1178 
       
  1179 CAmdahlCpuEater::CAmdahlCpuEater()
       
  1180 	{
       
  1181 	}
       
  1182 
       
  1183 CAmdahlCpuEater::~CAmdahlCpuEater()
       
  1184 	{
       
  1185 	iMutex.Close();
       
  1186 	}
       
  1187 
       
  1188 CAmdahlCpuEater* CAmdahlCpuEater::NewLC()
       
  1189 	{
       
  1190 	CAmdahlCpuEater* p = new (ELeave) CAmdahlCpuEater();
       
  1191 	CleanupStack::PushL(p);
       
  1192 	p->ConstructL();
       
  1193 	return p;
       
  1194 	}
       
  1195 
       
  1196 void CAmdahlCpuEater::ConstructL()
       
  1197 	{
       
  1198 	User::LeaveIfError(iMutex.CreateLocal());
       
  1199 	iFactor = KMaxTUint32 / (4*TCpuUsage::N());
       
  1200 	}
       
  1201 
       
  1202 void CAmdahlCpuEater::Eat(TInt aTime, TUint32* aWorkDone)
       
  1203 	{
       
  1204 	TUint64 t(aTime);
       
  1205 	t *= TUint64(iFactor);
       
  1206 	t += TUint64(0x80000000u);
       
  1207 	t >>= 32;
       
  1208 	TInt stime = I64LOW(t);
       
  1209 	if (IsCalibrated())
       
  1210 		{
       
  1211 		iMutex.Wait();
       
  1212 		CDefaultCpuEater::Eat(stime, aWorkDone);
       
  1213 		aTime -= stime;
       
  1214 		iMutex.Signal();
       
  1215 		}
       
  1216 	CDefaultCpuEater::Eat(aTime, aWorkDone);
       
  1217 	}
       
  1218 
       
  1219 
       
  1220 
       
  1221 /******************************************************************************
       
  1222  * Do something memory intensive to consume CPU time
       
  1223  ******************************************************************************/
       
  1224 class CMemoryBandwidthEater : public CBase, public MCpuEater
       
  1225 	{
       
  1226 public:
       
  1227 	static CMemoryBandwidthEater* NewLC(TUint32 aSize, TUint32 aRegionSize, TUint32 aRegionOffset);
       
  1228 	~CMemoryBandwidthEater();
       
  1229 	virtual void Calibrate();
       
  1230 protected:
       
  1231 	CMemoryBandwidthEater(TUint32 aSize, TUint32 aRegionSize, TUint32 aRegionOffset);
       
  1232 	void ConstructL();
       
  1233 	virtual void Eat(TInt aTime, TUint32* aWorkDone);
       
  1234 	TAny* At(TUint32 aRegion, TUint32 aIndex);
       
  1235 	TAny* StepWithinRegion(TAny* aInitial, TUint32 aStep);
       
  1236 protected:
       
  1237 	volatile TUint32 iRegionAlloc;
       
  1238 	TUint32 iPageSize;
       
  1239 	TUint32 iSize;				// multiple of page size
       
  1240 	TAny* iData;				// page aligned
       
  1241 	RChunk iChunk;
       
  1242 	TUint8 iLog2RegionSize;		// log2(bytes per region)
       
  1243 	TUint8 iLog2RO;				// log2(offset from region n to n+1 in bytes)
       
  1244 	TUint8 iLog2PageSize;
       
  1245 	TUint8 iRegionBits;			// number of bits to specify region
       
  1246 	TUint32 iNRgn;
       
  1247 	TUint32 iRegionMask;
       
  1248 	TUint32 iLowerIndexMask;
       
  1249 	TUint32 iUpperIndexMask;
       
  1250 	};
       
  1251 
       
  1252 TUint32 AtomicClearLS1(volatile TUint32* aMask)
       
  1253 	{
       
  1254 	TUint32 initial = *aMask;
       
  1255 	TUint32 final;
       
  1256 	do	{
       
  1257 		final = initial & (initial-1);
       
  1258 		} while(!__e32_atomic_cas_ord32(aMask, &initial, final));
       
  1259 	return initial;
       
  1260 	}
       
  1261 
       
  1262 TInt AtomicAllocBit(volatile TUint32* aMask)
       
  1263 	{
       
  1264 	return __e32_find_ls1_32(AtomicClearLS1(aMask));
       
  1265 	}
       
  1266 
       
  1267 TUint32 AtomicFreeBit(volatile TUint32* aMask, TInt aBit)
       
  1268 	{
       
  1269 	return __e32_atomic_ior_ord32(aMask, 1u<<aBit);
       
  1270 	}
       
  1271 
       
  1272 
       
  1273 
       
  1274 CMemoryBandwidthEater* CMemoryBandwidthEater::NewLC(TUint32 aSize, TUint32 aRegionSize, TUint32 aRegionOffset)
       
  1275 	{
       
  1276 	CMemoryBandwidthEater* p = new (ELeave) CMemoryBandwidthEater(aSize, aRegionSize, aRegionOffset);
       
  1277 	CleanupStack::PushL(p);
       
  1278 	p->ConstructL();
       
  1279 	return p;
       
  1280 	}
       
  1281 
       
  1282 CMemoryBandwidthEater::CMemoryBandwidthEater(TUint32 aSize, TUint32 aRegionSize, TUint32 aRegionOffset)
       
  1283 	{
       
  1284 	TInt r = HAL::Get(HAL::EMemoryPageSize, (TInt&)iPageSize);
       
  1285 	assert(r==KErrNone);
       
  1286 	iLog2PageSize = (TUint8)__e32_find_ms1_32(iPageSize);
       
  1287 	assert( !(aRegionSize & (aRegionSize-1)) );
       
  1288 	assert( !(aRegionOffset & (aRegionOffset-1)) );
       
  1289 	iLog2RegionSize = (TUint8)__e32_find_ms1_32(aRegionSize);
       
  1290 	iLog2RO = (TUint8)__e32_find_ms1_32(aRegionOffset);
       
  1291 	TUint32 round = (aRegionSize>iPageSize) ? aRegionSize : iPageSize;
       
  1292 	iSize = (aSize + round - 1) &~ (round - 1);
       
  1293 	--iSize;
       
  1294 	iSize |= (iSize>>1);
       
  1295 	iSize |= (iSize>>2);
       
  1296 	iSize |= (iSize>>4);
       
  1297 	iSize |= (iSize>>8);
       
  1298 	iSize |= (iSize>>16);
       
  1299 	++iSize;
       
  1300 	iNRgn = iSize >> iLog2RegionSize;
       
  1301 	if (iNRgn>=32)
       
  1302 		iRegionAlloc = ~0u;
       
  1303 	else
       
  1304 		iRegionAlloc = ~((~0u)<<iNRgn);
       
  1305 	iRegionBits = TUint8(1 + __e32_find_ms1_32(iNRgn-1));
       
  1306 	iLowerIndexMask = ~((~0u)<<iLog2RO);
       
  1307 	iRegionMask = (~((~0u)<<iRegionBits))<<iLog2RO;
       
  1308 	iUpperIndexMask = ((iSize-1)>>(iRegionBits+iLog2RO))<<(iRegionBits+iLog2RO);
       
  1309 	}
       
  1310 
       
  1311 CMemoryBandwidthEater::~CMemoryBandwidthEater()
       
  1312 	{
       
  1313 	iChunk.Close();
       
  1314 	}
       
  1315 
       
  1316 void CMemoryBandwidthEater::ConstructL()
       
  1317 	{
       
  1318 	TInt mask = (1<<20)-1;
       
  1319 	TInt maxSize = (TInt(iSize)+mask)&~mask;
       
  1320 	User::LeaveIfError(iChunk.CreateLocal(iSize, maxSize, EOwnerThread));
       
  1321 	iData = iChunk.Base();
       
  1322 	}
       
  1323 
       
  1324 void CMemoryBandwidthEater::Calibrate()
       
  1325 	{
       
  1326 	MCpuEater::Calibrate();
       
  1327 	MCpuEater::Calibrate();
       
  1328 	}
       
  1329 
       
  1330 TAny* CMemoryBandwidthEater::At(TUint32 aRegion, TUint32 aIndex)
       
  1331 	{
       
  1332 	TUint32 offset = aIndex & iLowerIndexMask;
       
  1333 	offset |= (aRegion<<iLog2RO);
       
  1334 	offset |= ((aIndex<<iRegionBits) & iUpperIndexMask);
       
  1335 	return ((TUint8*)iData) + offset;
       
  1336 	}
       
  1337 
       
  1338 TAny* CMemoryBandwidthEater::StepWithinRegion(TAny* aInitial, TUint32 aStep)
       
  1339 	{
       
  1340 	TUintPtr offset = TUintPtr(aInitial) - TUintPtr(iData);
       
  1341 	TUintPtr offset2 = offset + (aStep & iLowerIndexMask);
       
  1342 	if ((offset^offset2)&iRegionMask)
       
  1343 		{
       
  1344 		offset2 -= (iLowerIndexMask+1);
       
  1345 		aStep += (iLowerIndexMask+1);
       
  1346 		}
       
  1347 	offset2 += ((aStep<<iRegionBits)&iUpperIndexMask);
       
  1348 	offset2 &= (iSize-1);
       
  1349 	return ((TUint8*)iData) + offset2;
       
  1350 	}
       
  1351 
       
  1352 void CMemoryBandwidthEater::Eat(TInt aTime, TUint32* aWorkDone)
       
  1353 	{
       
  1354 	TUint32 work = WorkValue(aTime);
       
  1355 	if (aWorkDone)
       
  1356 		*aWorkDone += work;
       
  1357 	TInt region = AtomicAllocBit(&iRegionAlloc);
       
  1358 	assert(region>=0);
       
  1359 	TUint32 done = 0;
       
  1360 	TUint32 rgnsz = 1u << iLog2RegionSize;
       
  1361 	for (; work; work-=done)
       
  1362 		{
       
  1363 		done = (work>rgnsz) ? rgnsz : work;
       
  1364 		TUint8* p = (TUint8*)At(region,0);
       
  1365 		TUint8 prev = *p;
       
  1366 		TUint32 n = done;
       
  1367 		do	{
       
  1368 			TUint8* q = p;
       
  1369 			p = (TUint8*)StepWithinRegion(p, 31);
       
  1370 			*q = *p;
       
  1371 			} while(--n);
       
  1372 		*p = prev;
       
  1373 		}
       
  1374 	AtomicFreeBit(&iRegionAlloc, region);
       
  1375 	}
       
  1376 
       
  1377 
       
  1378 /******************************************************************************
       
  1379  * Do lots of atomic operations to consume CPU time
       
  1380  ******************************************************************************/
       
  1381 class CAtomicMemoryBandwidthEater : public CMemoryBandwidthEater
       
  1382 	{
       
  1383 public:
       
  1384 	static CAtomicMemoryBandwidthEater* NewLC(TUint32 aSize);
       
  1385 	~CAtomicMemoryBandwidthEater();
       
  1386 protected:
       
  1387 	CAtomicMemoryBandwidthEater(TUint32 aSize);
       
  1388 	void ConstructL();
       
  1389 	virtual void Eat(TInt aTime, TUint32* aWorkDone);
       
  1390 protected:
       
  1391 	volatile TUint32 iX;
       
  1392 	};
       
  1393 
       
  1394 CAtomicMemoryBandwidthEater* CAtomicMemoryBandwidthEater::NewLC(TUint32 aSize)
       
  1395 	{
       
  1396 	CAtomicMemoryBandwidthEater* p = new (ELeave) CAtomicMemoryBandwidthEater(aSize);
       
  1397 	CleanupStack::PushL(p);
       
  1398 	p->ConstructL();
       
  1399 	return p;
       
  1400 	}
       
  1401 
       
  1402 CAtomicMemoryBandwidthEater::CAtomicMemoryBandwidthEater(TUint32 aSize)
       
  1403 	:	CMemoryBandwidthEater(aSize, aSize, aSize)
       
  1404 	{
       
  1405 	iX = TUint32(this) ^ RThread().Id().operator TUint();
       
  1406 	iX *= 0x9e3779b9u;
       
  1407 	}
       
  1408 
       
  1409 CAtomicMemoryBandwidthEater::~CAtomicMemoryBandwidthEater()
       
  1410 	{
       
  1411 	}
       
  1412 
       
  1413 void CAtomicMemoryBandwidthEater::ConstructL()
       
  1414 	{
       
  1415 	CMemoryBandwidthEater::ConstructL();
       
  1416 	}
       
  1417 
       
  1418 TUint32 AtomicRandom(volatile TUint32* a)
       
  1419 	{
       
  1420 	TUint32 initial = *a;
       
  1421 	TUint32 final;
       
  1422 	do	{
       
  1423 		final = 69069*initial + 41;
       
  1424 		} while(!__e32_atomic_cas_ord32(a, &initial, final));
       
  1425 	return final;
       
  1426 	}
       
  1427 
       
  1428 void CAtomicMemoryBandwidthEater::Eat(TInt aTime, TUint32* aWorkDone)
       
  1429 	{
       
  1430 	TUint32 work = WorkValue(aTime);
       
  1431 	if (aWorkDone)
       
  1432 		*aWorkDone += work;
       
  1433 	volatile TUint32* pW = (volatile TUint32*)iData;
       
  1434 	const TUint32 mask = iSize/sizeof(TUint32)-1;
       
  1435 	TUint32 x = AtomicRandom(&iX);
       
  1436 	TUint32 n = work;
       
  1437 	do	{
       
  1438 		TUint32 offset = (x>>2) & mask;
       
  1439 		x = 69069*x+41;
       
  1440 		__e32_atomic_add_rlx32(pW+offset, 1);
       
  1441 		} while(--n);
       
  1442 	}
       
  1443 
       
  1444 
       
  1445 /******************************************************************************
       
  1446  *
       
  1447  ******************************************************************************/
       
  1448 struct SThreadResult
       
  1449 	{
       
  1450 	TUint64		iElapsedTime;
       
  1451 	TUint64		iCpuTime;
       
  1452 	TUint32		iWorkDone;
       
  1453 	TUint32		iInvocations;
       
  1454 	};
       
  1455 
       
  1456 struct SThreadParams
       
  1457 	{
       
  1458 	TInt64		iTestTime;
       
  1459 
       
  1460 	TInt		iId;
       
  1461 	TUint32		iCpuAffinity;
       
  1462 
       
  1463 	TInt		iPriority;
       
  1464 	RSemaphore	iTurnstile;
       
  1465 
       
  1466 	SThreadResult* iResult;
       
  1467 	TInt		iGroupId;
       
  1468 
       
  1469 	MCpuEater*	iE;
       
  1470 	TUint32		iGranularity;
       
  1471 	TUint32		iMeanIntraBurstGap;
       
  1472 	TUint32		iMeanBurstLength;
       
  1473 	TUint32		iMeanInterBurstGap;
       
  1474 	};
       
  1475 
       
  1476 class MThreadCompletion
       
  1477 	{
       
  1478 public:
       
  1479 	virtual void Complete(TBool aOk, SThreadParams* aParams)=0;
       
  1480 	};
       
  1481 
       
  1482 class CThreadI : public CBase
       
  1483 	{
       
  1484 public:
       
  1485 	CThreadI();
       
  1486 	~CThreadI();
       
  1487 	static TInt ThreadFunc(TAny* aPtr);
       
  1488 	TInt Run();
       
  1489 	void InitL();
       
  1490 public:
       
  1491 	CTrapCleanup*		iCleanup;
       
  1492 	CActiveScheduler*	iAS;
       
  1493 	CLoadSim*			iL;
       
  1494 	CBurstyCpuEater*	iB;
       
  1495 	CTimedStopper*		iStopper;
       
  1496 	RSemaphore			iTurnstile;
       
  1497 	SThreadParams*		iParams;
       
  1498 	};
       
  1499 
       
  1500 CThreadI::CThreadI()
       
  1501 	{
       
  1502 	}
       
  1503 
       
  1504 CThreadI::~CThreadI()
       
  1505 	{
       
  1506 	iTurnstile.Close();
       
  1507 	delete iStopper;
       
  1508 	delete iB;
       
  1509 	delete iL;
       
  1510 	delete iAS;
       
  1511 	delete iCleanup;
       
  1512 	}
       
  1513 
       
  1514 TInt CThreadI::ThreadFunc(TAny* aPtr)
       
  1515 	{
       
  1516 	CThreadI* p = new CThreadI;
       
  1517 	if (!p)
       
  1518 		return KErrNoMemory;
       
  1519 	p->iParams = (SThreadParams*)aPtr;
       
  1520 	return p->Run();
       
  1521 	}
       
  1522 
       
  1523 void CThreadI::InitL()
       
  1524 	{
       
  1525 	iTurnstile = iParams->iTurnstile;
       
  1526 	User::LeaveIfError(iTurnstile.Duplicate(RThread(), EOwnerThread));
       
  1527 	iAS = new (ELeave) CActiveScheduler;
       
  1528 	CActiveScheduler::Install(iAS);
       
  1529 	iL = CLoadSim::NewL();
       
  1530 	CActiveScheduler::Add(iL);
       
  1531 	const CBurstyCpuEater::SParams* params = (const CBurstyCpuEater::SParams*)&iParams->iE;
       
  1532 	iB = new (ELeave) CBurstyCpuEater(iL, *params);
       
  1533 	CActiveScheduler::Add(iB);
       
  1534 	iStopper = CTimedStopper::NewL();
       
  1535 	CActiveScheduler::Add(iStopper);
       
  1536 	memclr(iParams->iResult, sizeof(*iParams->iResult));
       
  1537 	RThread().SetPriority(TThreadPriority(iParams->iPriority));
       
  1538 	UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*)iParams->iCpuAffinity, 0);
       
  1539 	}
       
  1540 
       
  1541 TInt CThreadI::Run()
       
  1542 	{
       
  1543 	iCleanup = CTrapCleanup::New();
       
  1544 	if (!iCleanup)
       
  1545 		return KErrNoMemory;
       
  1546 	TRAPD(r,InitL());
       
  1547 	if (r == KErrNone)
       
  1548 		{
       
  1549 		TThreadCpuUsageSample initial;
       
  1550 		TThreadCpuUsageSample final;
       
  1551 		RThread::Rendezvous(KErrNone);
       
  1552 		iTurnstile.Wait();
       
  1553 		iB->Start();
       
  1554 		initial.Sample(RThread());
       
  1555 		iStopper->Start(iParams->iTestTime);
       
  1556 		CActiveScheduler::Start();
       
  1557 		final.Sample(RThread());
       
  1558 		iParams->iResult->iWorkDone = iB->WorkDone();
       
  1559 		iParams->iResult->iInvocations = iB->Invocations();
       
  1560 		iParams->iResult->iElapsedTime = final.ElapsedTimeDelta(initial);
       
  1561 		iParams->iResult->iCpuTime = final.CpuTimeDelta(initial);
       
  1562 		}
       
  1563 	delete this;
       
  1564 	return r;
       
  1565 	}
       
  1566 
       
  1567 
       
  1568 /******************************************************************************
       
  1569  *
       
  1570  ******************************************************************************/
       
  1571 class CThreadX : public CActive
       
  1572 	{
       
  1573 public:
       
  1574 	static CThreadX* NewL(SThreadParams* aParams, MThreadCompletion* aComplete);
       
  1575 	static CThreadX* NewLC(SThreadParams* aParams, MThreadCompletion* aComplete);
       
  1576 	CThreadX();
       
  1577 	~CThreadX();
       
  1578 	void ConstructL();
       
  1579 	virtual void RunL();
       
  1580 	virtual void DoCancel();
       
  1581 public:
       
  1582 	RThread				iThread;
       
  1583 	RTimer				iTimer;
       
  1584 	SThreadParams*		iParams;
       
  1585 	MThreadCompletion*	iComplete;
       
  1586 	};
       
  1587 
       
  1588 CThreadX::CThreadX()
       
  1589 	:	CActive(EPriorityStandard)
       
  1590 	{
       
  1591 	}
       
  1592 
       
  1593 CThreadX::~CThreadX()
       
  1594 	{
       
  1595 	Cancel();
       
  1596 	iTimer.Close();
       
  1597 	iThread.Close();
       
  1598 	}
       
  1599 
       
  1600 CThreadX* CThreadX::NewL(SThreadParams* aParams, MThreadCompletion* aComplete)
       
  1601 	{
       
  1602 	CThreadX* p = NewLC(aParams, aComplete);
       
  1603 	CleanupStack::Pop();
       
  1604 	return p;
       
  1605 	}
       
  1606 
       
  1607 CThreadX* CThreadX::NewLC(SThreadParams* aParams, MThreadCompletion* aComplete)
       
  1608 	{
       
  1609 	CThreadX* p = new (ELeave) CThreadX();
       
  1610 	p->iParams = aParams;
       
  1611 	p->iComplete = aComplete;
       
  1612 	CleanupStack::PushL(p);
       
  1613 	p->ConstructL();
       
  1614 	return p;
       
  1615 	}
       
  1616 
       
  1617 const TInt KThreadHeapMin = 0x1000;
       
  1618 const TInt KThreadHeapMax = 0x200000;
       
  1619 void CThreadX::ConstructL()
       
  1620 	{
       
  1621 	CActiveScheduler::Add(this);
       
  1622 	TRequestStatus s0, s1;
       
  1623 	User::LeaveIfError(iTimer.CreateLocal());
       
  1624 	User::LeaveIfError(iThread.Create(KNullDesC, &CThreadI::ThreadFunc, 0x1000, KThreadHeapMin, KThreadHeapMax, iParams));
       
  1625 	iThread.Rendezvous(s1);
       
  1626 	if (s1!=KRequestPending)
       
  1627 		{
       
  1628 		User::WaitForRequest(s1);
       
  1629 		User::Leave(s1.Int());
       
  1630 		}
       
  1631 	iTimer.After(s0, 5*1000*1000);
       
  1632 	iThread.Resume();
       
  1633 	User::WaitForRequest(s0, s1);
       
  1634 	if (s1==KRequestPending)
       
  1635 		{
       
  1636 		iThread.Terminate(KErrCouldNotStart);
       
  1637 		User::WaitForRequest(s1);
       
  1638 		User::Leave(KErrTimedOut);
       
  1639 		}
       
  1640 	iTimer.Cancel();
       
  1641 	User::WaitForRequest(s0);
       
  1642 	if (iThread.ExitType() != EExitPending)
       
  1643 		{
       
  1644 		User::Leave(KErrDied);
       
  1645 		}
       
  1646 	iThread.Logon(iStatus);
       
  1647 	if (iStatus!=KRequestPending)
       
  1648 		{
       
  1649 		User::WaitForRequest(iStatus);
       
  1650 		User::Leave(iStatus.Int());
       
  1651 		}
       
  1652 	SetActive();
       
  1653 	User::LeaveIfError(s1.Int());
       
  1654 	}
       
  1655 
       
  1656 void CThreadX::DoCancel()
       
  1657 	{
       
  1658 	iThread.Terminate(KErrCouldNotStart);
       
  1659 	}
       
  1660 
       
  1661 void CThreadX::RunL()
       
  1662 	{
       
  1663 	TBool ok = ETrue;
       
  1664 	if (iThread.ExitType() != EExitKill)
       
  1665 		ok = EFalse;
       
  1666 	if (iThread.ExitReason() != KErrNone)
       
  1667 		ok = EFalse;
       
  1668 	if (iComplete)
       
  1669 		iComplete->Complete(ok, iParams);
       
  1670 	}
       
  1671 
       
  1672 
       
  1673 /******************************************************************************
       
  1674  *
       
  1675  ******************************************************************************/
       
  1676 struct STestThreadDesc
       
  1677 	{
       
  1678 	TUint32		iCpuAffinity;
       
  1679 	TInt		iPriority;
       
  1680 	TInt		iGroupId;
       
  1681 	TUint16		iEaterType;
       
  1682 	TUint16		iEaterInstance;
       
  1683 	TUint32		iGranularity;
       
  1684 	TUint32		iMeanIntraBurstGap;
       
  1685 	TUint32		iMeanBurstLength;
       
  1686 	TUint32		iMeanInterBurstGap;
       
  1687 
       
  1688 	static STestThreadDesc* ContinuousL(TInt aPri = EPriorityNormal);
       
  1689 	static STestThreadDesc* ContinuousLC(TInt aPri = EPriorityNormal);
       
  1690 	static STestThreadDesc* StaccatoL(TUint32 aGranularity, TUint32 aMeanGap, TInt aPri = EPriorityNormal);
       
  1691 	static STestThreadDesc* StaccatoLC(TUint32 aGranularity, TUint32 aMeanGap, TInt aPri = EPriorityNormal);
       
  1692 	};
       
  1693 
       
  1694 STestThreadDesc* STestThreadDesc::ContinuousLC(TInt aPri)
       
  1695 	{
       
  1696 	STestThreadDesc* p = (STestThreadDesc*)User::AllocLC(sizeof(STestThreadDesc));
       
  1697 	p->iCpuAffinity = 0xffffffff;
       
  1698 	p->iPriority = aPri;
       
  1699 	p->iGroupId = 0;
       
  1700 	p->iEaterType = EEaterStd;
       
  1701 	p->iEaterInstance = 0;
       
  1702 	p->iGranularity = 0;
       
  1703 	p->iMeanIntraBurstGap = 0;
       
  1704 	p->iMeanBurstLength = KMaxTInt32;
       
  1705 	p->iMeanInterBurstGap = 0;
       
  1706 	return p;
       
  1707 	}
       
  1708 
       
  1709 STestThreadDesc* STestThreadDesc::ContinuousL(TInt aPri)
       
  1710 	{
       
  1711 	STestThreadDesc* p = ContinuousLC(aPri);
       
  1712 	CleanupStack::Pop();
       
  1713 	return p;
       
  1714 	}
       
  1715 
       
  1716 STestThreadDesc* STestThreadDesc::StaccatoLC(TUint32 aGranularity, TUint32 aMeanGap, TInt aPri)
       
  1717 	{
       
  1718 	STestThreadDesc* p = (STestThreadDesc*)User::AllocLC(sizeof(STestThreadDesc));
       
  1719 	p->iCpuAffinity = 0xffffffff;
       
  1720 	p->iPriority = aPri;
       
  1721 	p->iGroupId = 0;
       
  1722 	p->iEaterType = EEaterStd;
       
  1723 	p->iEaterInstance = 0;
       
  1724 	p->iGranularity = aGranularity;
       
  1725 	p->iMeanIntraBurstGap = aMeanGap;
       
  1726 	p->iMeanBurstLength = KMaxTInt32;
       
  1727 	p->iMeanInterBurstGap = 0;
       
  1728 	return p;
       
  1729 	}
       
  1730 
       
  1731 STestThreadDesc* STestThreadDesc::StaccatoL(TUint32 aGranularity, TUint32 aMeanGap, TInt aPri)
       
  1732 	{
       
  1733 	STestThreadDesc* p = StaccatoLC(aGranularity, aMeanGap, aPri);
       
  1734 	CleanupStack::Pop();
       
  1735 	return p;
       
  1736 	}
       
  1737 
       
  1738 
       
  1739 class CTest : public CBase, public MThreadCompletion
       
  1740 	{
       
  1741 public:
       
  1742 	struct SStats
       
  1743 		{
       
  1744 		TInt64	iTotalCpu;
       
  1745 		TInt64	iMinCpu;
       
  1746 		TInt64	iMaxCpu;
       
  1747 		TInt64	iTotalWork;
       
  1748 		TInt64	iMinWork;
       
  1749 		TInt64	iMaxWork;
       
  1750 		};
       
  1751 public:
       
  1752 	static CTest* NewL(TInt64 aTestTime, TInt aNumTypes, ...);
       
  1753 	~CTest();
       
  1754 	RPointerArray<SThreadParams>& Threads()
       
  1755 		{ return iP; }
       
  1756 	TInt Execute();
       
  1757 	void PrintResults() const;
       
  1758 	void GetStats(SStats& aStats, TInt aFirstThread=0, TInt aCount=KMaxTInt) const;
       
  1759 	TInt64 TotalCpuAll() const;
       
  1760 private:
       
  1761 	CTest();
       
  1762 	void ConstructL(TInt64 aTestTime, TInt aNumTypes, VA_LIST aList);
       
  1763 	SThreadParams* AddThreadParamsL();
       
  1764 	CThreadX* AddThreadXL(SThreadParams* aParams);
       
  1765 
       
  1766 	virtual void Complete(TBool aOk, SThreadParams* aParams);
       
  1767 private:
       
  1768 	RPointerArray<SThreadParams> iP;
       
  1769 	RPointerArray<CThreadX> iTX;
       
  1770 	REaterArray iEaters;
       
  1771 	RSemaphore iTurnstile;
       
  1772 	TInt iCompleteCount;
       
  1773 	TCpuUsage iInitialCpuUsage;
       
  1774 	TCpuUsage iFinalCpuUsage;
       
  1775 	};
       
  1776 
       
  1777 CTest::CTest()
       
  1778 	:	iP(32),
       
  1779 		iTX(32)
       
  1780 	{
       
  1781 	}
       
  1782 
       
  1783 CTest::~CTest()
       
  1784 	{
       
  1785 	iTX.ResetAndDestroy();
       
  1786 
       
  1787 	TInt i;
       
  1788 	TInt c = iP.Count();
       
  1789 	for (i=0; i<c; ++i)
       
  1790 		{
       
  1791 		SThreadParams* p = iP[i];
       
  1792 		iP[i] = 0;
       
  1793 		if (p)
       
  1794 			{
       
  1795 			User::Free(p->iResult);
       
  1796 			User::Free(p);
       
  1797 			}
       
  1798 		}
       
  1799 	iP.Close();
       
  1800 	iEaters.Close();
       
  1801 	iTurnstile.Close();
       
  1802 	}
       
  1803 
       
  1804 CTest* CTest::NewL(TInt64 aTestTime, TInt aNumTypes, ...)
       
  1805 	{
       
  1806 	VA_LIST list;
       
  1807 	VA_START(list, aNumTypes);
       
  1808 	CTest* p = new (ELeave) CTest;
       
  1809 	CleanupStack::PushL(p);
       
  1810 	p->ConstructL(aTestTime, aNumTypes, list);
       
  1811 	CleanupStack::Pop();
       
  1812 	return p;
       
  1813 	}
       
  1814 
       
  1815 SThreadParams* CTest::AddThreadParamsL()
       
  1816 	{
       
  1817 	SThreadResult* tr = (SThreadResult*)User::AllocLC(sizeof(SThreadResult));
       
  1818 	SThreadParams* tp = (SThreadParams*)User::AllocLC(sizeof(SThreadParams));
       
  1819 	memclr(tr, sizeof(SThreadResult));
       
  1820 	tp->iResult = tr;
       
  1821 	iP.AppendL(tp);
       
  1822 	CleanupStack::Pop(2);
       
  1823 	tp->iTurnstile = iTurnstile;
       
  1824 	return tp;
       
  1825 	}
       
  1826 
       
  1827 CThreadX* CTest::AddThreadXL(SThreadParams* aP)
       
  1828 	{
       
  1829 	if (aP->iGranularity==0 && aP->iMeanInterBurstGap==0)
       
  1830 		{
       
  1831 		// continuous use thread
       
  1832 		if (TInt64(aP->iMeanBurstLength) >= aP->iTestTime)
       
  1833 			aP->iMeanBurstLength = I64LOW(aP->iTestTime) + (I64LOW(aP->iTestTime)>>1);
       
  1834 		}
       
  1835 	CThreadX* tx = CThreadX::NewLC(aP, this);
       
  1836 	iTX.AppendL(tx);
       
  1837 	CleanupStack::Pop();
       
  1838 	return tx;
       
  1839 	}
       
  1840 
       
  1841 void CTest::Complete(TBool aOk, SThreadParams*)
       
  1842 	{
       
  1843 	if (!aOk || --iCompleteCount==0)
       
  1844 		CActiveScheduler::Stop();
       
  1845 	}
       
  1846 
       
  1847 
       
  1848 void CTest::ConstructL(TInt64 aTestTime, TInt aNumTypes, VA_LIST aList)
       
  1849 	{
       
  1850 	typedef const STestThreadDesc* TTestThreadDescPtrC;
       
  1851 
       
  1852 	User::LeaveIfError(iTurnstile.CreateLocal(0));
       
  1853 	TInt tt;
       
  1854 	TInt tid = 0;
       
  1855 	for (tt=0; tt<aNumTypes; ++tt)
       
  1856 		{
       
  1857 		TInt nThreads = VA_ARG(aList, TInt);
       
  1858 		TInt inc = 0;
       
  1859 		const TTestThreadDescPtrC* ppttd = 0;
       
  1860 		TTestThreadDescPtrC pttd = 0;
       
  1861 		if (nThreads < 0)
       
  1862 			{
       
  1863 			ppttd = VA_ARG(aList, const TTestThreadDescPtrC*);
       
  1864 			nThreads = -nThreads;
       
  1865 			inc = 1;
       
  1866 			}
       
  1867 		else
       
  1868 			{
       
  1869 			pttd = VA_ARG(aList, TTestThreadDescPtrC);
       
  1870 			ppttd = &pttd;
       
  1871 			}
       
  1872 		TInt k;
       
  1873 		for (k=0; k<nThreads; ++k, ++tid)
       
  1874 			{
       
  1875 			const STestThreadDesc& ttd = **ppttd;
       
  1876 			ppttd += inc;
       
  1877 			SThreadParams* tp = AddThreadParamsL();
       
  1878 			tp->iId = tid;
       
  1879 			tp->iTestTime = aTestTime;
       
  1880 			tp->iCpuAffinity = ttd.iCpuAffinity;
       
  1881 			tp->iPriority = ttd.iPriority;
       
  1882 			tp->iGroupId = ttd.iGroupId;
       
  1883 			tp->iE = iEaters.FindOrCreateL(ttd.iEaterType, ttd.iEaterInstance);
       
  1884 			tp->iGranularity = ttd.iGranularity;
       
  1885 			tp->iMeanIntraBurstGap = ttd.iMeanIntraBurstGap;
       
  1886 			tp->iMeanBurstLength = ttd.iMeanBurstLength;
       
  1887 			tp->iMeanInterBurstGap = ttd.iMeanInterBurstGap;
       
  1888 			AddThreadXL(tp);
       
  1889 			}
       
  1890 		}
       
  1891 	}
       
  1892 
       
  1893 TInt CTest::Execute()
       
  1894 	{
       
  1895 	iCompleteCount = iP.Count();
       
  1896 	iInitialCpuUsage.Sample();
       
  1897 	iTurnstile.Signal(iCompleteCount);
       
  1898 	CActiveScheduler::Start();
       
  1899 	iFinalCpuUsage.Sample();
       
  1900 	return iCompleteCount ? KErrGeneral : KErrNone;
       
  1901 	}
       
  1902 
       
  1903 void CTest::GetStats(SStats& a, TInt aFirstThread, TInt aCount) const
       
  1904 	{
       
  1905 	a.iTotalCpu = 0;
       
  1906 	a.iMinCpu = KMaxTInt64;
       
  1907 	a.iMaxCpu = KMinTInt64;
       
  1908 	a.iTotalWork = 0;
       
  1909 	a.iMinWork = KMaxTInt64;
       
  1910 	a.iMaxWork = KMinTInt64;
       
  1911 	TInt nt = iP.Count();
       
  1912 	if (aFirstThread > nt)
       
  1913 		aFirstThread = nt;
       
  1914 	if (aCount > nt - aFirstThread)
       
  1915 		aCount = nt - aFirstThread;
       
  1916 	TInt i = aFirstThread;
       
  1917 	for (; i<aFirstThread+aCount; ++i)
       
  1918 		{
       
  1919 		SThreadResult* tr = iP[i]->iResult;
       
  1920 		TInt64 cpu = tr->iCpuTime;
       
  1921 		TInt64 work = tr->iWorkDone;
       
  1922 		a.iTotalCpu += cpu;
       
  1923 		a.iTotalWork += work;
       
  1924 		if (cpu < a.iMinCpu)
       
  1925 			a.iMinCpu = cpu;
       
  1926 		if (cpu > a.iMaxCpu)
       
  1927 			a.iMaxCpu = cpu;
       
  1928 		if (work < a.iMinWork)
       
  1929 			a.iMinWork = work;
       
  1930 		if (work > a.iMaxWork)
       
  1931 			a.iMaxWork = work;
       
  1932 		}
       
  1933 	}
       
  1934 
       
  1935 TInt64 CTest::TotalCpuAll() const
       
  1936 	{
       
  1937 	TInt i;
       
  1938 	TInt nc = TCpuUsage::N();
       
  1939 	TInt64 totalCpuAll = 0;
       
  1940 	for (i=0; i<nc; ++i)
       
  1941 		{
       
  1942 		TInt64 u = iFinalCpuUsage.CpuTimeDelta(iInitialCpuUsage, i);
       
  1943 		totalCpuAll += u;
       
  1944 		}
       
  1945 	return totalCpuAll;
       
  1946 	}
       
  1947 
       
  1948 void CTest::PrintResults() const
       
  1949 	{
       
  1950 	TInt i;
       
  1951 	TInt nt = iP.Count();
       
  1952 	TInt nc = TCpuUsage::N();
       
  1953 	TInt64 totalCpuAll = 0;
       
  1954 	TInt64 totalCpu = 0;
       
  1955 	TInt64 totalWork = 0;
       
  1956 	for (i=0; i<nt; ++i)
       
  1957 		{
       
  1958 		SThreadResult* tr = iP[i]->iResult;
       
  1959 		test.Printf(_L("%2u: E=%10u     C=%10u     I=%10u     W=%10u\n"),
       
  1960 			i, I64LOW(tr->iElapsedTime), I64LOW(tr->iCpuTime), tr->iInvocations, tr->iWorkDone );
       
  1961 		totalCpu += tr->iCpuTime;
       
  1962 		totalWork += TInt64(tr->iWorkDone);
       
  1963 		}
       
  1964 	test.Printf(_L("Total              C=%12Lu                    W=%12Lu\n"), totalCpu, totalWork);
       
  1965 	for (i=0; i<nc; ++i)
       
  1966 		{
       
  1967 		TInt64 u = iFinalCpuUsage.CpuTimeDelta(iInitialCpuUsage, i);
       
  1968 		totalCpuAll += u;
       
  1969 		test.Printf(_L("Cpu%1u: %10u "), i, I64LOW(u));
       
  1970 		}
       
  1971 	test.Printf(_L("\n"));
       
  1972 	test.Printf(_L("Total %12Lu\n"), totalCpuAll);
       
  1973 	}
       
  1974 
       
  1975 
       
  1976 
       
  1977 MCpuEater* REaterArray::CreateLC(TInt aType)
       
  1978 	{
       
  1979 	switch (aType)
       
  1980 		{
       
  1981 		case EEaterStd:
       
  1982 			{
       
  1983 			CDefaultCpuEater* p = new (ELeave) CDefaultCpuEater();
       
  1984 			CleanupStack::PushL(p);
       
  1985 			p->Calibrate();
       
  1986 			return p;
       
  1987 			}
       
  1988 		case EEaterMemoryLocalS:
       
  1989 			{
       
  1990 			CMemoryBandwidthEater* p = CMemoryBandwidthEater::NewLC(0x8000, 0x0800, 0x0800);
       
  1991 			p->Calibrate();
       
  1992 			return p;
       
  1993 			}
       
  1994 		case EEaterMemoryNonLocalS:
       
  1995 			{
       
  1996 			CMemoryBandwidthEater* p = CMemoryBandwidthEater::NewLC(0x100000, 0x10000, 0x4);
       
  1997 			p->Calibrate();
       
  1998 			return p;
       
  1999 			}
       
  2000 		case EEaterMemoryLocalU:
       
  2001 			{
       
  2002 			CMemoryBandwidthEater* p = CMemoryBandwidthEater::NewLC(0x4000, 0x4000, 0x4000);
       
  2003 			p->Calibrate();
       
  2004 			return p;
       
  2005 			}
       
  2006 		case EEaterMemoryNonLocalU:
       
  2007 			{
       
  2008 			CMemoryBandwidthEater* p = CMemoryBandwidthEater::NewLC(0x80000, 0x80000, 0x80000);
       
  2009 			p->Calibrate();
       
  2010 			return p;
       
  2011 			}
       
  2012 		case EEaterMemoryAtomic:
       
  2013 			{
       
  2014 			CAtomicMemoryBandwidthEater* p = CAtomicMemoryBandwidthEater::NewLC(0x1000);
       
  2015 			p->Calibrate();
       
  2016 			return p;
       
  2017 			}
       
  2018 		case EEaterMemoryAtomic2:
       
  2019 			{
       
  2020 			CAtomicMemoryBandwidthEater* p = CAtomicMemoryBandwidthEater::NewLC(0x8000);
       
  2021 			p->Calibrate();
       
  2022 			return p;
       
  2023 			}
       
  2024 		case EEaterAmdahl:
       
  2025 			{
       
  2026 			CAmdahlCpuEater* p = CAmdahlCpuEater::NewLC();
       
  2027 			p->Calibrate();
       
  2028 			return p;
       
  2029 			}
       
  2030 		default:
       
  2031 			User::Leave(KErrNotSupported);
       
  2032 		}
       
  2033 	return 0;
       
  2034 	}
       
  2035 
       
  2036 
       
  2037 
       
  2038 /******************************************************************************
       
  2039  *
       
  2040  ******************************************************************************/
       
  2041 
       
  2042 void RunBenchmarkL(CTest::SStats& aB, STestThreadDesc* aT, TInt aLength)
       
  2043 	{
       
  2044 	const TInt NC = TCpuUsage::N();
       
  2045 	CTest* p;
       
  2046 	TUint32 saved_aff = aT->iCpuAffinity;
       
  2047 	aT->iCpuAffinity = NC-1;
       
  2048 	p = CTest::NewL(aLength, 1, 1, aT);
       
  2049 	TInt r = p->Execute();
       
  2050 	test_KErrNone(r);
       
  2051 	p->PrintResults();
       
  2052 	p->GetStats(aB);
       
  2053 	delete p;
       
  2054 	aT->iCpuAffinity = saved_aff;
       
  2055 	}
       
  2056 
       
  2057 void CompareToBenchmark(const CTest::SStats& aS, const CTest::SStats& aB)
       
  2058 	{
       
  2059 	TReal bCpu = (TReal)aB.iTotalCpu;
       
  2060 	TReal bWork = (TReal)aB.iTotalWork;
       
  2061 	TReal bEff = bWork/bCpu*1000000.0;
       
  2062 	TReal tCpu = (TReal)aS.iTotalCpu;
       
  2063 	TReal tWork = (TReal)aS.iTotalWork;
       
  2064 	TReal tEff = tWork/tCpu*1000000.0;
       
  2065 	TReal mCpu = (TReal)aS.iMinCpu;
       
  2066 	TReal MCpu = (TReal)aS.iMaxCpu;
       
  2067 	TReal mWork = (TReal)aS.iMinWork;
       
  2068 	TReal MWork = (TReal)aS.iMaxWork;
       
  2069 	test.Printf(_L("Total CPU usage %6.1f%% of benchmark\n"), 100.0*tCpu/bCpu);
       
  2070 	test.Printf(_L("Total work done %6.1f%% of benchmark\n"), 100.0*tWork/bWork);
       
  2071 	test.Printf(_L("Max/min ratio   %6.1f%% (CPU) %6.1f%% (Work)\n"), 100.0*MCpu/mCpu, 100.0*MWork/mWork);
       
  2072 	test.Printf(_L("Work/sec bench: %10.1f test: %10.1f  Relative Efficiency %6.1f%%\n"), bEff, tEff, tEff/bEff*100.0);
       
  2073 	}
       
  2074 
       
  2075 void ContinuousTestL(TInt aLength, TUint32 aWhich)
       
  2076 	{
       
  2077 	aLength *= 1000;
       
  2078 	const TInt NC = TCpuUsage::N();
       
  2079 	TInt r = 0;
       
  2080 	TInt i = 0;
       
  2081 	CTest::SStats benchmark;
       
  2082 	CTest::SStats st;
       
  2083 	CTest::SStats stm;
       
  2084 	CTest* p = 0;
       
  2085 	TUint et = aWhich >> 28;
       
  2086 	TBool separate = (aWhich & 0x08000000u);
       
  2087 	TInt instance = 0;
       
  2088 	STestThreadDesc* td[2*TCpuUsage::EMaxCpus] = {0};
       
  2089 	STestThreadDesc* tdm[TCpuUsage::EMaxCpus] = {0};
       
  2090 	STestThreadDesc* tdl[TCpuUsage::EMaxCpus] = {0};
       
  2091 	for (i=0; i<2*NC; ++i)
       
  2092 		{
       
  2093 		td[i] = STestThreadDesc::ContinuousLC();
       
  2094 		td[i]->iEaterType = (TUint16)et;
       
  2095 		td[i]->iEaterInstance = (TUint16)(separate ? (instance++) : 0);
       
  2096 		if (i<NC)
       
  2097 			{
       
  2098 			tdm[i] = STestThreadDesc::ContinuousLC(EPriorityMore);
       
  2099 			tdm[i]->iEaterType = (TUint16)et;
       
  2100 			tdm[i]->iEaterInstance = (TUint16)(separate ? (instance++) : 0);
       
  2101 			tdl[i] = STestThreadDesc::ContinuousLC();
       
  2102 			tdl[i]->iCpuAffinity = i;
       
  2103 			tdl[i]->iEaterType = (TUint16)et;
       
  2104 			tdl[i]->iEaterInstance = (TUint16)(separate ? (instance++) : 0);
       
  2105 			}
       
  2106 		}
       
  2107 
       
  2108 	test.Printf(_L("\nTesting a single continuous CPU-locked thread\n"));
       
  2109 	RunBenchmarkL(benchmark, tdl[NC-1], aLength);
       
  2110 
       
  2111 	TInt n;
       
  2112 
       
  2113 	if (aWhich & 1)
       
  2114 		{
       
  2115 		for (n=1; n<=2*NC; ++n)
       
  2116 			{
       
  2117 			test.Printf(_L("\nTesting %d continuous thread(s) ...\n"), n);
       
  2118 			p = CTest::NewL(aLength, 1, -n, td);
       
  2119 			r = p->Execute();
       
  2120 			test_KErrNone(r);
       
  2121 			p->PrintResults();
       
  2122 			p->GetStats(st);
       
  2123 			delete p;
       
  2124 			CompareToBenchmark(st, benchmark);
       
  2125 			}
       
  2126 		}
       
  2127 
       
  2128 	TInt h;
       
  2129 	if (aWhich & 2)
       
  2130 		{
       
  2131 		for (h=1; h<NC; ++h)
       
  2132 			{
       
  2133 			for (n=h; n<=2*NC; ++n)
       
  2134 				{
       
  2135 				TInt l = n - h;
       
  2136 				test.Printf(_L("\nTesting %d continuous thread(s) (%d higher priority) CPU-locked...\n"), n, h);
       
  2137 				p = CTest::NewL(aLength, 2, -h, tdl, l, tdl[h]);
       
  2138 				r = p->Execute();
       
  2139 				test_KErrNone(r);
       
  2140 				p->PrintResults();
       
  2141 				p->GetStats(st, h, l);
       
  2142 				p->GetStats(stm, 0, h);
       
  2143 				delete p;
       
  2144 				CompareToBenchmark(stm, benchmark);
       
  2145 				if (l>0)
       
  2146 					CompareToBenchmark(st, benchmark);
       
  2147 				}
       
  2148 			}
       
  2149 		}
       
  2150 
       
  2151 	if (aWhich & 4)
       
  2152 		{
       
  2153 		for (h=1; h<NC; ++h)
       
  2154 			{
       
  2155 			for (n=h; n<=2*NC; ++n)
       
  2156 				{
       
  2157 				TInt l = n - h;
       
  2158 				test.Printf(_L("\nTesting %d continuous thread(s) (%d higher priority)...\n"), n, h);
       
  2159 				p = CTest::NewL(aLength, 2, -h, tdm, -l, td);
       
  2160 				r = p->Execute();
       
  2161 				test_KErrNone(r);
       
  2162 				p->PrintResults();
       
  2163 				p->GetStats(st, h, l);
       
  2164 				p->GetStats(stm, 0, h);
       
  2165 				delete p;
       
  2166 				CompareToBenchmark(stm, benchmark);
       
  2167 				if (l>0)
       
  2168 					CompareToBenchmark(st, benchmark);
       
  2169 				}
       
  2170 			}
       
  2171 		}
       
  2172 
       
  2173 	CleanupStack::PopAndDestroy(NC*4);
       
  2174 	}
       
  2175 
       
  2176 
       
  2177 void TestWithOneSpecialL(const TDesC& aTitle, TInt aLength, const CTest::SStats& aB1, const CTest::SStats& aB0, STestThreadDesc* aT1, STestThreadDesc* aT0)
       
  2178 	{
       
  2179 	const TInt NC = TCpuUsage::N();
       
  2180 	CTest::SStats st;
       
  2181 	CTest::SStats sti;
       
  2182 	CTest* p = 0;
       
  2183 	TInt n;
       
  2184 	TInt r;
       
  2185 	for (n=1; n<=2*NC-1; ++n)
       
  2186 		{
       
  2187 		test.Printf(_L("\nTesting %d continuous thread(s) plus %S ...\n"), n, &aTitle);
       
  2188 		p = CTest::NewL(aLength, 2, 1, aT1, n, aT0);
       
  2189 		r = p->Execute();
       
  2190 		test_KErrNone(r);
       
  2191 		p->PrintResults();
       
  2192 		p->GetStats(st, 1, n);
       
  2193 		p->GetStats(sti, 0, 1);
       
  2194 		delete p;
       
  2195 		CompareToBenchmark(sti, aB1);
       
  2196 		CompareToBenchmark(st, aB0);
       
  2197 
       
  2198 		test.Printf(_L("\nTesting %d continuous thread(s) plus %Sh ...\n"), n, &aTitle);
       
  2199 		TInt orig_pri = aT1->iPriority;
       
  2200 		aT1->iPriority = EPriorityMore;
       
  2201 		p = CTest::NewL(aLength, 2, 1, aT1, n, aT0);
       
  2202 		r = p->Execute();
       
  2203 		test_KErrNone(r);
       
  2204 		p->PrintResults();
       
  2205 		p->GetStats(st, 1, n);
       
  2206 		p->GetStats(sti, 0, 1);
       
  2207 		delete p;
       
  2208 		CompareToBenchmark(sti, aB1);
       
  2209 		CompareToBenchmark(st, aB0);
       
  2210 		aT1->iPriority = orig_pri;
       
  2211 		}
       
  2212 	}
       
  2213 
       
  2214 void ContinuousPlusIntermittentTestL(TInt aLength, TUint32 aWhich)
       
  2215 	{
       
  2216 	aLength *= 1000;
       
  2217 	const TInt NC = TCpuUsage::N();
       
  2218 	TInt i = 0;
       
  2219 	CTest::SStats bmc, bmilc, bmilf, bmihc, bmihf;
       
  2220 	STestThreadDesc* td = STestThreadDesc::ContinuousLC();
       
  2221 	STestThreadDesc* tdl[TCpuUsage::EMaxCpus] = {0};
       
  2222 	STestThreadDesc* tdilc[TCpuUsage::EMaxCpus] = {0};	// light load, coarse grained
       
  2223 	STestThreadDesc* tdilf[TCpuUsage::EMaxCpus] = {0};	// light load, fine grained
       
  2224 	STestThreadDesc* tdihc[TCpuUsage::EMaxCpus] = {0};	// heavy load, coarse grained
       
  2225 	STestThreadDesc* tdihf[TCpuUsage::EMaxCpus] = {0};	// heavy load, fine grained
       
  2226 	for (i=0; i<NC; ++i)
       
  2227 		{
       
  2228 		tdl[i] = STestThreadDesc::ContinuousLC();
       
  2229 		tdl[i]->iCpuAffinity = i;
       
  2230 		tdilc[i] = STestThreadDesc::StaccatoLC(45000, 500000);
       
  2231 		tdilf[i] = STestThreadDesc::StaccatoLC(1000, 50000);
       
  2232 		tdihc[i] = STestThreadDesc::StaccatoLC(400000, 500000);
       
  2233 		tdihf[i] = STestThreadDesc::StaccatoLC(3000, 5000);
       
  2234 		}
       
  2235 
       
  2236 	test.Printf(_L("\nTesting a single continuous CPU-locked thread\n"));
       
  2237 	RunBenchmarkL(bmc, tdl[NC-1], aLength);
       
  2238 
       
  2239 	if (aWhich & 1)
       
  2240 		{
       
  2241 		test.Printf(_L("\nTesting a single ILC CPU-locked thread\n"));
       
  2242 		RunBenchmarkL(bmilc, tdilc[NC-1], aLength);
       
  2243 		}
       
  2244 
       
  2245 	if (aWhich & 2)
       
  2246 		{
       
  2247 		test.Printf(_L("\nTesting a single ILF CPU-locked thread\n"));
       
  2248 		RunBenchmarkL(bmilf, tdilf[NC-1], aLength);
       
  2249 		}
       
  2250 
       
  2251 	if (aWhich & 4)
       
  2252 		{
       
  2253 		test.Printf(_L("\nTesting a single IHC CPU-locked thread\n"));
       
  2254 		RunBenchmarkL(bmihc, tdihc[NC-1], aLength);
       
  2255 		}
       
  2256 
       
  2257 	if (aWhich & 8)
       
  2258 		{
       
  2259 		test.Printf(_L("\nTesting a single IHF CPU-locked thread\n"));
       
  2260 		RunBenchmarkL(bmihf, tdihf[NC-1], aLength);
       
  2261 		}
       
  2262 
       
  2263 	if (aWhich & 1)
       
  2264 		{
       
  2265 		TestWithOneSpecialL(_L("ILC"), aLength, bmilc, bmc, tdilc[0], td);
       
  2266 		}
       
  2267 	if (aWhich & 2)
       
  2268 		{
       
  2269 		TestWithOneSpecialL(_L("ILF"), aLength, bmilf, bmc, tdilf[0], td);
       
  2270 		}
       
  2271 	if (aWhich & 4)
       
  2272 		{
       
  2273 		TestWithOneSpecialL(_L("IHC"), aLength, bmihc, bmc, tdihc[0], td);
       
  2274 		}
       
  2275 	if (aWhich & 8)
       
  2276 		{
       
  2277 		TestWithOneSpecialL(_L("IHF"), aLength, bmihf, bmc, tdihf[0], td);
       
  2278 		}
       
  2279 	CleanupStack::PopAndDestroy(5*NC+1);
       
  2280 	}
       
  2281 
       
  2282 
       
  2283 TInt E32Main()
       
  2284 	{
       
  2285 	RThread().SetPriority(EPriorityAbsoluteHigh);
       
  2286 	test.Title();
       
  2287 	User::SetCritical(User::ESystemCritical);
       
  2288 	TCpuUsage::Init();
       
  2289 	TInt r = 0;
       
  2290 
       
  2291 	CTrapCleanup* cln = CTrapCleanup::New();
       
  2292 	test_NotNull(cln);
       
  2293 	CActiveScheduler* as = new CActiveScheduler;
       
  2294 	test_NotNull(as);
       
  2295 	CActiveScheduler::Install(as);
       
  2296 
       
  2297 	test.Printf(_L("\n************************************************************************\n"));
       
  2298 	test.Printf(_L("* Testing with CPU intensive loads...\n"));
       
  2299 	test.Printf(_L("************************************************************************\n"));
       
  2300 	TRAP(r, ContinuousTestL(3000, 1+4));
       
  2301 	test_KErrNone(r);
       
  2302 	TRAP(r, ContinuousTestL(10000, 1+4));
       
  2303 	test_KErrNone(r);
       
  2304 	TRAP(r, ContinuousPlusIntermittentTestL(10000, 15));
       
  2305 	test_KErrNone(r);
       
  2306 
       
  2307 	test.Printf(_L("\n************************************************************************\n"));
       
  2308 	test.Printf(_L("* Testing with memory intensive loads, good locality...\n"));
       
  2309 	test.Printf(_L("************************************************************************\n"));
       
  2310 	TRAP(r, ContinuousTestL(3000, 1+4+0x08000000u+(EEaterMemoryLocalU<<28)));
       
  2311 	test_KErrNone(r);
       
  2312 	TRAP(r, ContinuousTestL(10000, 1+4+0x08000000u+(EEaterMemoryLocalU<<28)));
       
  2313 	test_KErrNone(r);
       
  2314 
       
  2315 	test.Printf(_L("\n************************************************************************\n"));
       
  2316 	test.Printf(_L("* Testing with memory intensive loads, poor locality...\n"));
       
  2317 	test.Printf(_L("************************************************************************\n"));
       
  2318 	TRAP(r, ContinuousTestL(3000, 1+4+0x08000000u+(EEaterMemoryNonLocalU<<28)));
       
  2319 	test_KErrNone(r);
       
  2320 	TRAP(r, ContinuousTestL(10000, 1+4+0x08000000u+(EEaterMemoryNonLocalU<<28)));
       
  2321 	test_KErrNone(r);
       
  2322 
       
  2323 	test.Printf(_L("\n************************************************************************\n"));
       
  2324 	test.Printf(_L("* Testing with memory intensive loads, atomic operations...\n"));
       
  2325 	test.Printf(_L("************************************************************************\n"));
       
  2326 	TRAP(r, ContinuousTestL(3000, 1+4+(EEaterMemoryAtomic<<28)));
       
  2327 	test_KErrNone(r);
       
  2328 	TRAP(r, ContinuousTestL(10000, 1+4+(EEaterMemoryAtomic<<28)));
       
  2329 	test_KErrNone(r);
       
  2330 
       
  2331 	test.Printf(_L("\n************************************************************************\n"));
       
  2332 	test.Printf(_L("* Testing with memory intensive loads, atomic operations 2...\n"));
       
  2333 	test.Printf(_L("************************************************************************\n"));
       
  2334 	TRAP(r, ContinuousTestL(3000, 1+4+(EEaterMemoryAtomic2<<28)));
       
  2335 	test_KErrNone(r);
       
  2336 	TRAP(r, ContinuousTestL(10000, 1+4+(EEaterMemoryAtomic2<<28)));
       
  2337 	test_KErrNone(r);
       
  2338 
       
  2339 	test.Printf(_L("\n************************************************************************\n"));
       
  2340 	test.Printf(_L("* Testing with CPU intensive loads with some serialization...\n"));
       
  2341 	test.Printf(_L("************************************************************************\n"));
       
  2342 	TRAP(r, ContinuousTestL(3000, 1+4+(EEaterAmdahl<<28)));
       
  2343 	test_KErrNone(r);
       
  2344 	TRAP(r, ContinuousTestL(10000, 1+4+(EEaterAmdahl<<28)));
       
  2345 	test_KErrNone(r);
       
  2346 
       
  2347 	delete as;
       
  2348 	delete cln;
       
  2349 	return r;
       
  2350 	}
       
  2351