kerneltest/e32test/misc/t_cputime.cpp
changeset 293 0659d0e1a03c
parent 176 af6ec97d9189
--- a/kerneltest/e32test/misc/t_cputime.cpp	Mon Oct 18 15:31:10 2010 +0100
+++ b/kerneltest/e32test/misc/t_cputime.cpp	Wed Oct 20 13:58:28 2010 +0100
@@ -1,4 +1,4 @@
-// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 2005-2010 Nokia Corporation and/or its subsidiary(-ies).
 // All rights reserved.
 // This component and the accompanying materials are made available
 // under the terms of the License "Eclipse Public License v1.0"
@@ -33,9 +33,10 @@
 _LIT(KUp, "up");
 _LIT(KDown, "down");
 
-const TInt KLongWait  = 3000000;  // 3 seconds
-const TInt KShortWait =  100000;  // 0.1 seconds
-const TInt KTolerance =    1000;  // 1 ms
+const TInt KLongWait			= 3000000;  // 3 seconds
+const TInt KShortWait			=  100000;  // 0.1 seconds
+const TInt64 KMaxStartupTime	=    1000;  // 1 ms
+const TInt64 KMaxOverheadPerMil	=      25;	// 2.5%
 const TInt numCpus = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0);
 
 #define FailIfError(EXPR) \
@@ -67,7 +68,7 @@
 TInt SetCpuAffinity(TInt aCore)
     {
     TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny *)aCore, 0);
-    test(r==KErrNone);  
+    test(r == KErrNone);  
     return r;
     }
 
@@ -184,7 +185,7 @@
 		TRequestStatus status;
 		thread.Logon(status);
 		User::WaitForRequest(status);
-		test(status == KErrNone);
+		test(status.Int() == KErrNone);
 		CLOSE_AND_WAIT(thread);
 		
 		(threadParam.iSem).Close();
@@ -219,12 +220,12 @@
 
 	RThread thread;
 	RUndertaker u;
+	TRequestStatus s;
 	TInt h;
-	TRequestStatus s;
 	FailIfError(thread.Create(_L("Thread"), ThreadFunction, 1024, NULL, &threadParam));
 	thread.SetPriority(EPriorityLess);
 	FailIfError(u.Create());
-	FailIfError(u.Logon(s,h));
+	FailIfError(u.Logon(s, h));
 	test(s==KRequestPending);
 
 	TTimeIntervalMicroSeconds time, time2;
@@ -232,59 +233,81 @@
 
 	// Test cpu time is initially zero
 	FailIfError(thread.GetCpuTime(time));
-	test(time == 0);
+	us = time.Int64();
+	test(us == 0);
+
+	// Resume the thread, and sleep long enough for it to wait-on-semaphore
+	thread.Resume();
+	User::After(KLongWait);
+	FailIfError(thread.GetCpuTime(time));
+	us = time.Int64();
+	test.Printf(_L("Time %Ldus\n"), us);
+	test(us < KMaxStartupTime);							// wait should happen in less than 1ms
 
 	// Test cpu time is not increased while thread is waiting on semaphore
-	thread.Resume();
-	User::After(KShortWait);
+	User::After(KLongWait);
 	FailIfError(thread.GetCpuTime(time2));
 	us = time2.Int64();
-	test.Printf(_L("Time %dus\n"), us);
-	test(us < KTolerance); // wait should happen in less than 1ms
+	test.Printf(_L("Time %Ldus\n"), us);
+	test(time2 == time);
 
-	// Test cpu time increases when thread allowed to run
-	// We want to allow 2% tolerance for the thread's CPU time, as there could be
-	// something else running on the system during that time which would result lower CPU time than the
-	// actual KShortPeriod or KLongPeriod wait time.
-	// Also User::After(t) might return within the range of <t, t + 1000000/64 + 2*NanoKarnelTickPeriod>.
-	// Given all that - we expect that the the cpu time should be within the range of:
-	// <t - 0.02*t, t + 15625 + 2*NanoKernelTickPeriod>
-	// or <0.98*t, t + 15625 + 2*NanoKernelTickPeriod>
-	TInt user_after_tolerance = 0;
-	HAL::Get(HAL::ENanoTickPeriod, user_after_tolerance);
-	user_after_tolerance += user_after_tolerance + 15625;
+	// Test cpu time increases when thread allowed to run.
+	//
+	// We want to allow some tolerance for the thread's CPU time, as there could
+	// be other processes running on the system, which would result in lower CPU
+	// time than the actual KShortPeriod or KLongPeriod wait time. We try to
+	// minimise this by making this process as a whole High priority, but it
+	// will still be lower than the WindowServer or the FileServer (but we hope
+	// they won't be active during this test).
+	//
+	// Also interrupts and other overheads may take some of the thread's time.
+	//
+	// Also User::After(t) might return late, by up to one Symbian OS tick (64Hz)
+	// plus twice the NanoKernelTickPeriod
+	// 
+	// Given all that, we expect that the the CPU time should be in the range:
+	//
+	// ( WaitTime*(100-MaxOverhead)% ) <= CPUTime <= ( WaitTime+(1/Hz)+2*NanoKernelTickPeriod )
 
-	(threadParam.iSem).Signal();
-	User::After(KShortWait);
-	FailIfError(thread.GetCpuTime(time));
-	us = time.Int64() - time2.Int64();
-	test.Printf(_L("Time %dus\n"), us);
-	test(100*us >= 98*KShortWait); // left limit
-	test(us - KShortWait <= user_after_tolerance); // right limit
+	TInt nanoTick = 0;
+	HAL::Get(HAL::ENanoTickPeriod, nanoTick);
+	TInt64 maxSleepOverrun = 2*nanoTick + (1000000/64);					// microseconds
+	TInt64 minCpuTime;
+
+	(threadParam.iSem).Signal();										// make thread runnable
+
+	User::After(KShortWait);											// yield CPU for a while
+	FailIfError(thread.GetCpuTime(time2));
+	us = time2.Int64() - time.Int64();
+	test.Printf(_L("Time %Ldus\n"), us);
+	minCpuTime = KShortWait*(1000-KMaxOverheadPerMil)/1000;
+	test(us >= minCpuTime);
+	test(us <= KShortWait+maxSleepOverrun);
 
 	FailIfError(thread.GetCpuTime(time));
-	User::After(KLongWait);
+	User::After(KLongWait);												// yield CPU for a while
 	FailIfError(thread.GetCpuTime(time2));
 	us = time2.Int64() - time.Int64();
 	test.Printf(_L("Time %dus\n"), us);
-	test(100*us >= 98*KLongWait); // left limit
-	test(us - KLongWait <= user_after_tolerance); // right limit
+	minCpuTime = KLongWait*(1000-KMaxOverheadPerMil)/1000;
+	test(us >= minCpuTime);
+	test(us <= KLongWait+maxSleepOverrun);
 
 	// Test not increased while suspended
 	thread.Suspend();
 	FailIfError(thread.GetCpuTime(time));
-	User::After(KShortWait);
+	User::After(KLongWait);
 	FailIfError(thread.GetCpuTime(time2));
-	test(time == time2);
+	test(time2 == time);
 	thread.Resume();
 
 	// Test not increased while dead
 	thread.Kill(KErrNone);
 	User::WaitForRequest(s);	// wait on undertaker since that completes in supervisor thread
 	FailIfError(thread.GetCpuTime(time));
-	User::After(KShortWait);
+	User::After(KLongWait);
 	FailIfError(thread.GetCpuTime(time2));
-	test(time == time2);
+	test(time2 == time);
 
 	RThread t;
 	t.SetHandle(h);
@@ -312,6 +335,7 @@
 	if (numCpus > 1)
 		{
 		test.Printf(_L("** SMP system detected - not testing time shared between threads until load balancing optimized **\n"));
+		test.End();
 		return ETrue;
 		}
 
@@ -371,7 +395,7 @@
 				TRequestStatus status;
 				threads[k].Logon(status);
 				User::WaitForRequest(status);
-				test(status == KErrNone);
+				test(status.Int() == KErrNone);
 				CLOSE_AND_WAIT(threads[k]);
 				}
 			}
@@ -452,6 +476,15 @@
 	TestFastCounter();
 	if (GetCpuTimeIsSupported())
 		{
+		// This process (and this thread) should have priority
+		// over pretty much everything else in the system; test
+		// threads will have slightly lower relative priorities,
+		// but still higher than any other nonsystem tasks ...
+		RProcess thisProcess;
+		RThread thisThread;
+		thisProcess.SetPriority(EPriorityHigh);
+		thisThread.SetPriority(EPriorityMore);
+
 		EnsureSystemIdle();
 		TestThreadCpuTime();
 		TestThreadCpuTime2();
@@ -462,3 +495,4 @@
 	test.End();
 	return 0;
 	}
+