kerneltest/e32test/power/t_frqchg.cpp
changeset 201 43365a9b78a3
equal deleted inserted replaced
200:73ea206103e6 201:43365a9b78a3
       
     1 // Copyright (c) 2010-2010 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\power\t_frqchg.cpp
       
    15 //
       
    16 //
       
    17 
       
    18 #define __E32TEST_EXTENSION__
       
    19 #include <e32test.h>
       
    20 #include <e32math.h>
       
    21 #include <e32atomics.h>
       
    22 #include <hal.h>
       
    23 #include "d_frqchg.h"
       
    24 #include <e32svr.h>
       
    25 #include "u32std.h"
       
    26 
       
    27 RFrqChg Driver;
       
    28 RTest test(_L("T_FRQCHG"));
       
    29 
       
    30 // test will fail if slice is > (expected+KSliceDeltaPercent%of expexted) 
       
    31 // or < (expected-KSliceDeltaPercent%expected)
       
    32 const TInt KSliceDeltaPercent = 5;   
       
    33 // test will fail for global timer based timestamps if interval measured 
       
    34 // is > (expected+KTimeStampDeltaPercent%of expexted) 
       
    35 // or < (expected-KTimeStampDeltaPercent%expected)
       
    36 const TInt KTimeStampDeltaPercent = 5;
       
    37 
       
    38 TInt RealToRatio(SRatio& aRatio, const TRealX& aReal)
       
    39 	{
       
    40 	aRatio.iSpare1 = 0;
       
    41 	aRatio.iSpare2 = 0;
       
    42 	if (aReal.iSign || aReal.IsZero() || aReal.IsNaN())
       
    43 		{
       
    44 		aRatio.iM = 0;
       
    45 		aRatio.iX = 0;
       
    46 		return (aReal.IsZero()) ? KErrNone : KErrNotSupported;
       
    47 		}
       
    48 	TRealX rx(aReal);
       
    49 	TRealX rr(rx);
       
    50 	rr.iExp -= 32;
       
    51 	rr.iMantLo = 0;
       
    52 	rr.iMantHi = 0x80000000u;
       
    53 	rx += rr;	// rounding
       
    54 	TInt exp = rx.iExp - 32767 - 31;
       
    55 	if (exp < -32768)
       
    56 		{
       
    57 		aRatio.iM = 0;
       
    58 		aRatio.iX = 0;
       
    59 		return KErrUnderflow;
       
    60 		}
       
    61 	if (exp > 32767)
       
    62 		{
       
    63 		aRatio.iM = 0xffffffffu;
       
    64 		aRatio.iX = 32767;
       
    65 		return KErrOverflow;
       
    66 		}
       
    67 	aRatio.iM = rx.iMantHi;
       
    68 	aRatio.iX = (TInt16)exp;
       
    69 	return KErrNone;
       
    70 	}
       
    71 
       
    72 TInt RatioToReal(TRealX& a, const SRatio& aRatio)
       
    73 	{
       
    74 	a.iSign = 0;
       
    75 	a.iFlag = 0;
       
    76 	a.iMantLo = 0;
       
    77 	a.iMantHi = aRatio.iM;
       
    78 	if (!aRatio.iM)
       
    79 		{
       
    80 		a.SetZero();
       
    81 		return KErrNone;
       
    82 		}
       
    83 	TInt exp = aRatio.iX + 31 + 32767;
       
    84 	if (exp > 65534)
       
    85 		{
       
    86 		a.SetInfinite(EFalse);
       
    87 		}
       
    88 	else
       
    89 		{
       
    90 		a.iExp = (TUint16)exp;
       
    91 		}
       
    92 	return KErrNone;
       
    93 	}
       
    94 
       
    95 TInt RatioSetValue(TRealX& a, TUint32 aInt, TInt aDivisorExp)
       
    96 	{
       
    97 	a.Set(TUint(aInt));
       
    98 	TInt exp = a.iExp;
       
    99 	exp -= aDivisorExp;
       
   100 	if (exp<1)
       
   101 		{
       
   102 		a.SetZero();
       
   103 		return KErrUnderflow;
       
   104 		}
       
   105 	if (exp>65534)
       
   106 		{
       
   107 		a.SetInfinite(EFalse);
       
   108 		return KErrOverflow;
       
   109 		}
       
   110 	a.iExp = (TInt16)exp;
       
   111 	return KErrNone;
       
   112 	}
       
   113 
       
   114 TInt RatioReciprocal(SRatio& aRatio)
       
   115 	{
       
   116 	TRealX rx;
       
   117 	TInt r = RatioToReal(rx, aRatio);
       
   118 	if (r != KErrNone)
       
   119 		return r;
       
   120 	rx = TRealX(1) / rx;
       
   121 	return RealToRatio(aRatio, rx);
       
   122 	}
       
   123 
       
   124 TInt RatioMult(const SRatio& aRatio, TUint32& aInt32)
       
   125 	{
       
   126 	TRealX rx;
       
   127 	TInt r = RatioToReal(rx, aRatio);
       
   128 	if (r != KErrNone)
       
   129 		return r;
       
   130 	r = rx.MultEq(TRealX((TUint)aInt32));
       
   131 	if (r != KErrNone)
       
   132 		return r;
       
   133 	if (rx.IsZero())
       
   134 		{
       
   135 		aInt32 = 0;
       
   136 		return KErrNone;
       
   137 		}
       
   138 	rx.AddEq(TRealX(0.5));
       
   139 	if (rx<TRealX(1))
       
   140 		{
       
   141 		aInt32 = 0;
       
   142 		return KErrUnderflow;
       
   143 		}
       
   144 	if (rx.iExp > 32767+31)
       
   145 		{
       
   146 		aInt32 = ~0u;
       
   147 		return KErrOverflow;
       
   148 		}
       
   149 	aInt32 = rx.operator TUint();
       
   150 	return KErrNone;
       
   151 	}
       
   152 
       
   153 void RatioPrint(const char* aTitle, const SRatio& aRatio)
       
   154 	{
       
   155 	TPtrC8 t8((const TUint8*)aTitle);
       
   156 	TBuf<256> t16;
       
   157 	t16.Copy(t8);
       
   158 	test.Printf(_L("%S: %08x %04x\n"), &t16, aRatio.iM, TUint16(aRatio.iX));
       
   159 	}
       
   160 
       
   161 void RatioPrint2(const char* aTitle, const SRatio& aR1, const SRatio& aR2)
       
   162 	{
       
   163 	TPtrC8 t8((const TUint8*)aTitle);
       
   164 	TBuf<256> t16;
       
   165 	t16.Copy(t8);
       
   166 	test.Printf(_L("%S: %08x %04x   %08x %04x\n"), &t16, aR1.iM, TUint16(aR1.iX), aR2.iM, TUint16(aR2.iX));
       
   167 	}
       
   168 
       
   169 void TestEqual(const SRatio& aActual, const SRatio& aExpected)
       
   170 	{
       
   171 	if (aActual.iM==aExpected.iM && aActual.iX==aExpected.iX)
       
   172 		return;
       
   173 	RatioPrint("Actual", aActual);
       
   174 	RatioPrint("Expected", aExpected);
       
   175 	test(0);
       
   176 	}
       
   177 
       
   178 const TUint32 MultTestIntegers[] =
       
   179 	{
       
   180 	0u, 1u, 2u, 3u, 5u, 7u, 11u, 13u, 17u, 19u, 23u, 29u, 31u, 37u, 41u, 43u, 47u,
       
   181 	50u, 51u, 53u, 59u, 61u, 63u, 67u, 71u, 72u, 81u, 100u, 127u, 133u, 187u, 200u,
       
   182 	4u, 8u, 16u, 32u, 64u, 128u, 256u, 512u, 1024u, 2048u, 4096u, 8192u, 16384u,
       
   183 	32768u, 65536u, 131072u, 262144u, 524288u, 1048576u, 2097152u, 4194304u, 8388608u,
       
   184 	16777216u, 33554432u, 67108864u, 134217728u, 268435456u, 536870912u, 1073741824u,
       
   185 	2147483648u, 4294967295u,
       
   186 	9u, 27u, 243u, 729u, 2187u, 6561u, 19683u, 59049u, 177147u, 531441u, 1594323u,
       
   187 	4782969u, 14348907u, 43046721u, 129140163u, 387420489u, 1162261467u, 3486784401u,
       
   188 	25u, 125u, 625u, 3125u, 15625u, 78125u, 390625u, 1953125u, 9765625u,
       
   189 	48828125u, 244140625u, 1220703125u,
       
   190 	49u, 343u, 2401u, 16807u, 117649u, 823543u, 5764801u, 40353607u, 282475249u, 1977326743u
       
   191 	};
       
   192 
       
   193 void Test1M(const SRatio& aRatio)
       
   194 	{
       
   195 	SRatio ratio = aRatio;
       
   196 	const TInt N = sizeof(MultTestIntegers)/sizeof(MultTestIntegers[0]);
       
   197 	test.Printf(_L("Testing %d integers\n"), N);
       
   198 	TInt i;
       
   199 	for (i=0; i<N; ++i)
       
   200 		{
       
   201 		TUint32 I = MultTestIntegers[i];
       
   202 		TUint32 I0 = I;
       
   203 		TUint32 I1 = I;
       
   204 		TInt r0 = RatioMult(aRatio, I0);
       
   205 		TInt r1 = Driver.RatioMult(ratio, I1);
       
   206 		if (r0!=KErrNone || r1!=KErrNone)
       
   207 			{
       
   208 			if (r0!=r1)
       
   209 				{
       
   210 				test.Printf(_L("Return code mismatch r0=%d r1=%d (I=%08x I0=%08x I1=%08x)\n"), r0, r1, I, I0, I1);
       
   211 				test(0);
       
   212 				}
       
   213 			}
       
   214 		else if (I0!=I1)
       
   215 			{
       
   216 			test.Printf(_L("Result mismatch I=%08x I0=%08x I1=%08x\n"), I, I0, I1);
       
   217 			}
       
   218 		}
       
   219 	}
       
   220 
       
   221 void Test1(TUint32 aInt, TInt aDivisorExp)
       
   222 	{
       
   223 	TRealX realx;
       
   224 	SRatio r0x;
       
   225 	SRatio r0;
       
   226 	SRatio r1x;
       
   227 	SRatio r1;
       
   228 	TInt r;
       
   229 	test.Printf(_L("Test1 %08x %d\n"), aInt, aDivisorExp);
       
   230 	r = RatioSetValue(realx, aInt, aDivisorExp);
       
   231 	test_KErrNone(r);
       
   232 	r = RealToRatio(r0x, realx);
       
   233 	test_KErrNone(r);
       
   234 	r = Driver.RatioSet(r0, aInt, aDivisorExp);
       
   235 	RatioPrint2("R0X,R0", r0x, r0);
       
   236 	TestEqual(r0, r0x);
       
   237 	Test1M(r0);
       
   238 	r1x = r0x;
       
   239 	r = RatioReciprocal(r1x);
       
   240 	test_KErrNone(r);
       
   241 	r1 = r0;
       
   242 	r = Driver.RatioReciprocal(r1);
       
   243 	test_KErrNone(r);
       
   244 	RatioPrint2("R1X,R1", r1x, r1);
       
   245 	TestEqual(r1, r1x);
       
   246 	Test1M(r1);
       
   247 	}
       
   248 
       
   249 void TestRatios()
       
   250 	{
       
   251 	Test1(1,0);
       
   252 	Test1(3,0);
       
   253 	Test1(0xb504f334u,32);
       
   254 	Test1(0xc90fdaa2u,30);
       
   255 	Test1(10,0);
       
   256 	Test1(0xcccccccd,35);
       
   257 	Test1(100,0);
       
   258 	Test1(0xa3d70a3d,38);
       
   259 	}
       
   260 
       
   261 class CircBuf
       
   262 	{
       
   263 public:
       
   264 	static CircBuf* New(TInt aSlots);
       
   265 	CircBuf();
       
   266 	~CircBuf();
       
   267 	TInt TryPut(TUint32 aIn);
       
   268 	void Reset();
       
   269 public:
       
   270 	volatile TUint32* iBufBase;
       
   271 	TUint32 iSlotCount;
       
   272 	volatile TUint32 iPutIndex;
       
   273 	};
       
   274 
       
   275 CircBuf* CircBuf::New(TInt aSlots)
       
   276 	{
       
   277 	test(TUint32(aSlots-1)<65536);
       
   278 	CircBuf* p = new CircBuf();
       
   279 	p->iSlotCount = aSlots;
       
   280 	p->iPutIndex = 0;
       
   281 	p->iBufBase = (TUint32*)User::Alloc(aSlots*sizeof(TUint32));
       
   282 	if (!p->iBufBase)
       
   283 		{
       
   284 		delete p;
       
   285 		p = 0;
       
   286 		}
       
   287 	__e32_memory_barrier();
       
   288 	return p;
       
   289 	}
       
   290 
       
   291 CircBuf::CircBuf()
       
   292 	{
       
   293 	iBufBase = 0;
       
   294 	}
       
   295 
       
   296 CircBuf::~CircBuf()
       
   297 	{
       
   298 	User::Free((TAny*)iBufBase);
       
   299 	}
       
   300 
       
   301 TInt CircBuf::TryPut(TUint32 aIn)
       
   302 	{
       
   303 	TUint32 orig = __e32_atomic_tau_rlx32(&iPutIndex, iSlotCount, 0, 1);
       
   304 	if (orig == iSlotCount)
       
   305 		return KErrOverflow;
       
   306 	iBufBase[orig] = aIn;
       
   307 	return KErrNone;
       
   308 	}
       
   309 
       
   310 void CircBuf::Reset()
       
   311 	{
       
   312 	__e32_atomic_store_ord32(&iPutIndex, 0);
       
   313 	}
       
   314 
       
   315 
       
   316 
       
   317 class CTimesliceTestThread : public CBase
       
   318 	{
       
   319 public:
       
   320 	CTimesliceTestThread();
       
   321 	~CTimesliceTestThread();
       
   322 	static CTimesliceTestThread* New(TUint32 aId, TInt aCpu, TInt aSlice, CircBuf* aBuf);
       
   323 	void Start();
       
   324 	void Wait();
       
   325 	TBool Finished();
       
   326 	TInt Construct(TUint32 aId, TInt aCpu, TInt aSlice, CircBuf* aBuf);
       
   327 	static TInt ThreadFunc(TAny*);
       
   328 public:
       
   329 	RThread	iThread;
       
   330 	TRequestStatus iExitStatus;
       
   331 	TUint32 iId;
       
   332 	CircBuf* iBuf;
       
   333 	TUint32 iFreq;
       
   334 	TUint32 iThresh;
       
   335 	TUint32 iThresh2;
       
   336 	TInt iCpu;
       
   337 	TInt iSlice;
       
   338 	};
       
   339 
       
   340 CTimesliceTestThread::CTimesliceTestThread()
       
   341 	{
       
   342 	iThread.SetHandle(0);
       
   343 	}
       
   344 
       
   345 CTimesliceTestThread::~CTimesliceTestThread()
       
   346 	{
       
   347 	if (iThread.Handle())
       
   348 		{
       
   349 		if (iThread.ExitType() == EExitPending)
       
   350 			{
       
   351 			iThread.Kill(0);
       
   352 			Wait();
       
   353 			}
       
   354 		CLOSE_AND_WAIT(iThread);
       
   355 		}
       
   356 	}
       
   357 
       
   358 TInt CTimesliceTestThread::Construct(TUint32 aId, TInt aCpu, TInt aSlice, CircBuf* aBuf)
       
   359 	{
       
   360 	iId = aId;
       
   361 	iCpu = aCpu;
       
   362 	iSlice = aSlice;
       
   363 	iBuf = aBuf;
       
   364 
       
   365 	TInt r = HAL::Get(HAL::EFastCounterFrequency, (TInt&)iFreq);
       
   366 	if (r!=KErrNone)
       
   367 		return r;
       
   368 	iThresh = iFreq / 3000;
       
   369 	if (iThresh < 10)
       
   370 		iThresh = 10;
       
   371 	iThresh2 = iFreq;
       
   372 	TBuf<16> name = _L("TSThrd");
       
   373 	name.AppendNum(iId);
       
   374 	r = iThread.Create(name, &ThreadFunc, 0x1000, NULL, this);
       
   375 	if (r!=KErrNone)
       
   376 		return r;
       
   377 	iThread.Logon(iExitStatus);
       
   378 	if (iExitStatus != KRequestPending)
       
   379 		{
       
   380 		iThread.Kill(0);
       
   381 		iThread.Close();
       
   382 		iThread.SetHandle(0);
       
   383 		return iExitStatus.Int();
       
   384 		}
       
   385 	return KErrNone;
       
   386 	}
       
   387 
       
   388 CTimesliceTestThread* CTimesliceTestThread::New(TUint32 aId, TInt aCpu, TInt aSlice, CircBuf* aBuf)
       
   389 	{
       
   390 	CTimesliceTestThread* p = new CTimesliceTestThread;
       
   391 	if (p)
       
   392 		{
       
   393 		TInt r = p->Construct(aId, aCpu, aSlice, aBuf);
       
   394 		if (r != KErrNone)
       
   395 			{
       
   396 			delete p;
       
   397 			p = 0;
       
   398 			}
       
   399 		}
       
   400 	return p;
       
   401 	}
       
   402 
       
   403 void CTimesliceTestThread::Start()
       
   404 	{
       
   405 	iThread.Resume();
       
   406 	}
       
   407 
       
   408 TBool CTimesliceTestThread::Finished()
       
   409 	{
       
   410 	return (KRequestPending!=iExitStatus.Int());
       
   411 	}
       
   412 
       
   413 void CTimesliceTestThread::Wait()
       
   414 	{
       
   415 	User::WaitForRequest(iExitStatus);
       
   416 	}
       
   417 
       
   418 TInt CTimesliceTestThread::ThreadFunc(TAny* aPtr)
       
   419 	{
       
   420 	CTimesliceTestThread& a = *(CTimesliceTestThread*)aPtr;
       
   421 	Driver.SetCurrentThreadCpu(a.iCpu);
       
   422 	Driver.SetCurrentThreadPriority(63);
       
   423 	Driver.SetCurrentThreadTimeslice(a.iSlice);
       
   424 	User::AfterHighRes(100000);
       
   425 	TUint id = a.iId;
       
   426 	TUint32 last_interval_begin = User::FastCounter();
       
   427 	TUint32 last_seen_time = User::FastCounter();
       
   428 	FOREVER
       
   429 		{
       
   430 		TUint32 nfc = User::FastCounter();
       
   431 		TUint32 delta = nfc - last_seen_time;
       
   432 		TUint32 interval_length = last_seen_time - last_interval_begin;
       
   433 		if (delta > a.iThresh || interval_length > a.iThresh2)
       
   434 			{
       
   435 			last_interval_begin = nfc;
       
   436 			TUint32 x = (id<<30) | (interval_length&0x3fffffffu);
       
   437 			TInt r = a.iBuf->TryPut(x);
       
   438 			if (r != KErrNone)
       
   439 				break;
       
   440 			}
       
   441 		last_seen_time = nfc;
       
   442 		}
       
   443 	return KErrNone;
       
   444 	}
       
   445 
       
   446 CircBuf* RunTimesliceTest(TInt aCpu, TInt aSlice, TInt aCount, TInt aInterfere = 0)
       
   447  	{
       
   448 	TUint32 oldaff = 0;
       
   449 	TUint32 interfereAffinity = 0; 
       
   450 	TUint tellKernel = 0x80000000u;
       
   451 	
       
   452 	CircBuf* buf = CircBuf::New(aCount);
       
   453 	test(buf != 0);
       
   454 	CTimesliceTestThread* t0 = CTimesliceTestThread::New(0, aCpu, aSlice, buf);
       
   455 	test(t0 != 0);
       
   456 	CTimesliceTestThread* t1 = CTimesliceTestThread::New(1, aCpu, aSlice, buf);
       
   457 	test(t1 != 0);
       
   458 
       
   459 	if (aInterfere) 
       
   460 		{
       
   461 		if (aInterfere < 0) 
       
   462 			{
       
   463 			tellKernel = 0;
       
   464 			}
       
   465 		TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0);
       
   466 		test(r>0);
       
   467 		interfereAffinity = (0x80000000 | ((0x1<<r)-1)) & ~0x2; // all except core 1
       
   468 		if (0x80000001 == interfereAffinity) 
       
   469 			{
       
   470 			interfereAffinity = 0;   // dual core system (not doing this fails affinity check later)
       
   471 			}
       
   472 		
       
   473 		Driver.SetCurrentThreadCpu(interfereAffinity , &oldaff);   // move away from core 1 (doesn't hurt though not much difference gained)
       
   474 		Driver.SetCurrentThreadPriority(63);                       // changing prescaler requires running on core 1 so priority needs to 
       
   475 		}                                                          // match test threads
       
   476 
       
   477 
       
   478 	t0->Start();
       
   479 	t1->Start();
       
   480 	if (aInterfere) 
       
   481 		{
       
   482 		TInt prescale = 1;
       
   483 		while (!t0->Finished() || !t1->Finished()) 
       
   484 			{
       
   485 			User::AfterHighRes(23000);
       
   486 			Driver.SetLocalTimerPrescaler((1u<<1)|tellKernel, prescale);
       
   487 			prescale++;
       
   488 			if (prescale >  4) 
       
   489 				{
       
   490 				prescale = 0;
       
   491 				}
       
   492 			}
       
   493 		}
       
   494 
       
   495 	t0->Wait();
       
   496 	t1->Wait();
       
   497 	
       
   498 	delete t0;
       
   499 	delete t1;
       
   500 	if (aInterfere) 
       
   501 		{
       
   502 		TUint32 aff;
       
   503 		Driver.SetLocalTimerPrescaler((1u<<1)|0x80000000u, -1);
       
   504 		RThread().SetPriority(EPriorityNormal);
       
   505 		Driver.SetCurrentThreadCpu(oldaff,&aff);
       
   506 		test_Equal(aff,interfereAffinity);
       
   507 		}
       
   508 	return buf;
       
   509 	}
       
   510 
       
   511 TUint32 ticks_to_us(TUint32 aTicks, TUint32 aF)
       
   512 	{
       
   513 	TUint64 x = TUint64(aTicks) * TUint64(1000000);
       
   514 	TUint64 f64 = aF;
       
   515 	x += (f64>>1);
       
   516 	x /= f64;
       
   517 	return I64LOW(x);
       
   518 	}
       
   519 
       
   520 void DisplayBuffer(CircBuf* aBuf, TUint32 aSlice )
       
   521 	{
       
   522 	TUint32 f;
       
   523 	TInt r = HAL::Get(HAL::EFastCounterFrequency, (TInt&)f);
       
   524 	test_KErrNone(r);
       
   525 	TUint32* p = (TUint32*)aBuf->iBufBase;
       
   526 	TInt c = aBuf->iSlotCount;
       
   527 	TInt i;
       
   528 	TInt lid = -1;
       
   529 	TUint32 min = ~0u;
       
   530 	TUint32 max = 0;
       
   531 	TUint32 totivus = 0;
       
   532 	TBool firstchg = ETrue;
       
   533 	for (i=0; i<c; ++i)
       
   534 		{
       
   535 		TUint32 x = p[i];
       
   536 		TUint32 id = x>>30;
       
   537 		TUint32 iv = (x<<2)>>2;
       
   538 		TUint32 ivus = ticks_to_us(iv,f);
       
   539 		if (lid >= 0)
       
   540 			{
       
   541 			if (lid == (TInt)id)
       
   542 				totivus += ivus;
       
   543 			else
       
   544 				{
       
   545 				if (!firstchg)
       
   546 					{
       
   547 					if (totivus < min)
       
   548 						min = totivus;
       
   549 					if (totivus > max)
       
   550 						max = totivus;
       
   551 					}
       
   552 				else
       
   553 					firstchg = EFalse;
       
   554 				totivus = ivus;
       
   555 				}
       
   556 			}
       
   557 		lid = (TInt)id;
       
   558 		test.Printf(_L("ID: %1d IV: %10d (=%10dus) TIV %10dus\n"), id, iv, ivus, totivus);
       
   559 		}
       
   560 
       
   561 	if (aSlice > 0)
       
   562 		{
       
   563 		// check timeslices where within acceptable ranges
       
   564 		TUint32 sliceError = KSliceDeltaPercent*aSlice/100;
       
   565 		test_Compare(max,<,aSlice+sliceError);  
       
   566 		test_Compare(min,>,aSlice-sliceError);  
       
   567 		}
       
   568 	test.Printf(_L("RANGE %d-%dus (%dus)\n"), min, max, max-min);
       
   569 	}
       
   570 
       
   571 void TT()
       
   572 	{
       
   573 	test.Printf(_L("Timeslicing test ...\n"));
       
   574 	CircBuf* b = RunTimesliceTest(1, 50000, 100);
       
   575 	test.Next(_L("Baseline - expecting normal"));
       
   576 	DisplayBuffer(b,50000u);
       
   577 	delete b;
       
   578 
       
   579 	Driver.SetLocalTimerPrescaler(1u<<1, 1);
       
   580 	b = RunTimesliceTest(1, 50000, 100);
       
   581 	test.Next(_L("expecting double"));
       
   582 	DisplayBuffer(b,100000u);
       
   583 	delete b;
       
   584 
       
   585 	Driver.SetLocalTimerPrescaler(1u<<1|0x80000000u, 1);
       
   586 	test.Next(_L("expecting normal again"));
       
   587 	b = RunTimesliceTest(1, 50000, 100);
       
   588 	DisplayBuffer(b,50000u);
       
   589 	delete b;
       
   590 
       
   591 	test.Next(_L("expecting half"));
       
   592 	Driver.SetLocalTimerPrescaler(1u<<1, -1);
       
   593 	b = RunTimesliceTest(1, 50000, 100);
       
   594 	DisplayBuffer(b,25000u);
       
   595 	delete b;
       
   596 
       
   597 	Driver.SetLocalTimerPrescaler(1u<<1|0x80000000u, -1);
       
   598 	test.Next(_L("expecting normal again"));
       
   599 	b = RunTimesliceTest(1, 50000, 100);
       
   600 	DisplayBuffer(b,50000u);
       
   601 	delete b;
       
   602 
       
   603 	b = RunTimesliceTest(1, 50000, 200 ,-1);
       
   604 	test.Next(_L("expecting random"));
       
   605 	DisplayBuffer(b,0u);  // timeslices should be fairly random on this run
       
   606 
       
   607 	b = RunTimesliceTest(1, 50000, 200 ,1);
       
   608 	test.Next(_L("expecting normal again"));
       
   609 	DisplayBuffer(b,50000u);
       
   610 	delete b;
       
   611 	}
       
   612 
       
   613 struct SGTRecord
       
   614 	{
       
   615 	TUint64 iTSInterval;
       
   616 	TUint64 iGTInterval;
       
   617 	};
       
   618 
       
   619 
       
   620 SGTRecord* RunGTTest(TInt aCount, TInt aWait)
       
   621 	{
       
   622 	TUint64 lastgt,lastts,gt,ts;
       
   623 
       
   624 	SGTRecord* res = new SGTRecord[aCount];
       
   625 	test(res!=0);
       
   626 
       
   627 
       
   628 	TInt r = Driver.ReadGlobalTimerAndTimestamp(lastgt,lastts);
       
   629 	test_Equal(r,KErrNone);
       
   630 
       
   631 	for (TInt i = 0; i < aCount; i++) 
       
   632 		{
       
   633 		User::AfterHighRes(aWait);
       
   634 		
       
   635 		TInt r = Driver.ReadGlobalTimerAndTimestamp(gt,ts);
       
   636 		test_Equal(r,KErrNone);
       
   637 		res[i].iGTInterval = gt-lastgt;
       
   638 		lastgt = gt;
       
   639 		res[i].iTSInterval = ts-lastts;
       
   640 		lastts = ts;
       
   641 		}
       
   642 
       
   643 	return res;
       
   644 	}
       
   645 
       
   646 void DisplayGTResults(SGTRecord* aRec, TInt aCount, TUint32 aFreq, TUint64 aExpectedTSInterval, TUint64 aExpectedGTInterval)
       
   647 	{
       
   648 	SGTRecord max = { 0ul , 0ul };
       
   649 	SGTRecord min = { KMaxTUint64 , KMaxTUint64 };
       
   650 	
       
   651 	TUint64 errgt = (aExpectedGTInterval*KTimeStampDeltaPercent)/100;
       
   652 	TUint64 errts = (aExpectedTSInterval*KTimeStampDeltaPercent)/100;
       
   653 
       
   654 	
       
   655 	for (TInt i = 0 ; i < aCount; i++) 
       
   656 		{
       
   657 		test.Printf(_L("gt interval : %Lu (gtticks) %Lu (us)\n"),
       
   658 					aRec[i].iGTInterval,
       
   659 					aRec[i].iTSInterval*1000000u/TUint64(aFreq));
       
   660 		
       
   661 		if (max.iTSInterval < aRec[i].iTSInterval) 
       
   662 			{
       
   663 			max.iTSInterval = aRec[i].iTSInterval;
       
   664 			}
       
   665 		if (max.iGTInterval < aRec[i].iGTInterval) 
       
   666 			{
       
   667 			max.iGTInterval = aRec[i].iGTInterval;
       
   668 			}
       
   669 		
       
   670 		if (min.iTSInterval > aRec[i].iTSInterval) 
       
   671 			{
       
   672 			min.iTSInterval = aRec[i].iTSInterval;
       
   673 			}
       
   674 		if (min.iGTInterval > aRec[i].iGTInterval) 
       
   675 			{
       
   676 			min.iGTInterval = aRec[i].iGTInterval;
       
   677 			}
       
   678 		}
       
   679 	
       
   680 	test.Printf(_L("RANGE Global Timer %Lu-%Lu ticks (%Lu ticks)\n"),
       
   681 				min.iGTInterval, max.iGTInterval, max.iGTInterval-min.iGTInterval);
       
   682 	
       
   683 	test.Printf(_L("RANGE Timestamp %Lu-%Lu us (%Lu us)\n"),
       
   684 				(1000000u*min.iGTInterval)/TUint64(aFreq), (1000000u*max.iGTInterval)/TUint64(aFreq),
       
   685 				(1000000u*max.iGTInterval)/TUint64(aFreq) - (1000000u*min.iGTInterval)/TUint64(aFreq));
       
   686 	
       
   687 	if (errts) 
       
   688 		{
       
   689 		test_Compare(max.iTSInterval,<,aExpectedTSInterval+errts);  
       
   690 		test_Compare(min.iTSInterval,>,aExpectedTSInterval);  
       
   691 		}
       
   692 	
       
   693 	if (errgt) 
       
   694 		{
       
   695 		test_Compare(max.iGTInterval,<,aExpectedGTInterval+errgt);  
       
   696 		test_Compare(min.iGTInterval,>,aExpectedGTInterval);  
       
   697 		}
       
   698 	
       
   699 	}
       
   700 
       
   701 void GTT()
       
   702 	{
       
   703 	test.Printf(_L("Global timer tests ...\n"));
       
   704 	TUint64 gt,ts;
       
   705 
       
   706 	TInt r = Driver.ReadGlobalTimerAndTimestamp(gt,ts);
       
   707 	if (KErrNotSupported == r ) 
       
   708 		{
       
   709 		test.Printf(_L("Global timer not supported in this plaform, skipping GT tests\n"));
       
   710 		return;
       
   711 		}
       
   712 
       
   713 	TUint32 f;
       
   714 	r = HAL::Get(HAL::EFastCounterFrequency, (TInt&)f);
       
   715 	test_KErrNone(r);
       
   716 	TInt wait = 100000; // 100ms
       
   717 	TInt count = 10;
       
   718 	
       
   719 	TUint64 expectedTs = (TUint64(f)*TUint64(wait))/1000000u;
       
   720 	TUint64 expectedGtOrig = expectedTs;
       
   721 	
       
   722 	SGTRecord* rec;
       
   723 	for (TInt i = 0; i < 10; i++)
       
   724 		{
       
   725 		TUint64 expectedGt = expectedGtOrig/(i+1);
       
   726 		r = Driver.SetGlobalTimerPrescaler(i);
       
   727 		test_KErrNone(r);
       
   728 		rec = RunGTTest(count, wait);
       
   729 		test.Printf(_L("expectedTS %Lu expectedGT %Lu\n"),expectedTs,expectedGt);
       
   730 		DisplayGTResults(rec,count, f, expectedTs , expectedGt);
       
   731 		delete rec;
       
   732 		}
       
   733 
       
   734 	r = Driver.SetGlobalTimerPrescaler(-1); // back to default
       
   735 	test_KErrNone(r);
       
   736 	}
       
   737 
       
   738 void RunTests()
       
   739 	{
       
   740 	TestRatios();
       
   741 	if (Driver.FrqChgTestPresent()!=KErrNone)
       
   742 		{
       
   743 		test.Printf(_L("Frequency Change not supported on this platform\n"));
       
   744 		return;
       
   745 		}
       
   746 	TT();
       
   747 	GTT();
       
   748 	}
       
   749 
       
   750 GLDEF_C TInt E32Main()
       
   751 	{
       
   752 	test.Title();
       
   753 	test.Start(_L("Testing"));
       
   754 	TInt r = User::LoadLogicalDevice(KLddName);
       
   755 	if (r==KErrNotFound)
       
   756 		{
       
   757 		test.Printf(_L("Test not supported on this platform\n"));
       
   758 		}
       
   759 	else 
       
   760 		{
       
   761 		if (r!=KErrNone)
       
   762 			{
       
   763 			test_Equal(KErrAlreadyExists, r);
       
   764 			}
       
   765 		r = Driver.Open();
       
   766 		test_KErrNone(r);
       
   767 		RunTests();
       
   768 		Driver.Close();
       
   769 		}
       
   770 
       
   771 	test.End();
       
   772 	r = User::FreeLogicalDevice(KLddName);
       
   773 	test_KErrNone(r);
       
   774 	return KErrNone;
       
   775 	}