kerneltest/e32test/misc/t_cputime.cpp
changeset 0 a41df078684a
child 36 538db54a451d
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2005-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_cputime.cpp
       
    15 // Tests User::FastCounter() and RThread::GetCpuTime()
       
    16 // Note: This test only works on the emulator when run in textshell mode.  The
       
    17 // reason for this is that is assumes that it will be able to use 100% of CPU
       
    18 // time, but when techview is starting up there are many other threads consuming
       
    19 // CPU time.
       
    20 // 
       
    21 //
       
    22 
       
    23 #include <e32test.h>
       
    24 #include <e32svr.h>
       
    25 #include <u32hal.h>
       
    26 #include <hal.h>
       
    27 #ifdef __WINS__
       
    28 #include <e32wins.h>
       
    29 #endif
       
    30 
       
    31 RTest test(_L("T_CPUTIME"));
       
    32 
       
    33 _LIT(KUp, "up");
       
    34 _LIT(KDown, "down");
       
    35 
       
    36 const TInt KLongWait  = 3000000;  // 3 seconds
       
    37 const TInt KShortWait =  100000;  // 0.1 seconds
       
    38 const TInt KTolerance =     500;  // 0.5 ms
       
    39 const TInt numCpus = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0);
       
    40 
       
    41 #define FailIfError(EXPR) \
       
    42 	{ \
       
    43 	TInt aErr = (EXPR); \
       
    44 	if (aErr != KErrNone) \
       
    45 		{ \
       
    46 		test.Printf(_L("Return code == %d\n"), aErr); \
       
    47 		test(EFalse); \
       
    48 		} \
       
    49 	}
       
    50 
       
    51 class TThreadParam
       
    52 	{
       
    53 public:
       
    54 	TInt iCpu;
       
    55 	RSemaphore iSem;
       
    56 	};
       
    57 
       
    58 TBool GetCpuTimeIsSupported()
       
    59 	{
       
    60 	RThread thread;
       
    61 	TTimeIntervalMicroSeconds time;
       
    62 	TInt err = thread.GetCpuTime(time);
       
    63 	test(err == KErrNone || err == KErrNotSupported);
       
    64 	return err == KErrNone;
       
    65 	}
       
    66 
       
    67 TInt SetCpuAffinity(TInt aCore)
       
    68     {
       
    69     TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny *)aCore, 0);
       
    70     test(r==KErrNone);  
       
    71     return r;
       
    72     }
       
    73 
       
    74 
       
    75 //! @SYMTestCaseID t_cputime_0
       
    76 //! @SYMTestType CT
       
    77 //! @SYMTestCaseDesc Fast counter tests
       
    78 //! @SYMREQ CR RFID-66JJKX
       
    79 //! @SYMTestActions Compares the high res timer against the nanokernel microsecond tick
       
    80 //! @SYMTestExpectedResults The differnce measured should be < 1%
       
    81 //! @SYMTestPriority High
       
    82 //! @SYMTestStatus Defined
       
    83 void TestFastCounter()
       
    84 	{
       
    85 	test.Start(_L("Comparing NTickCount with FastCounter"));
       
    86 
       
    87 	TInt tickPeriod = 0;
       
    88 	FailIfError(HAL::Get(HAL::ENanoTickPeriod, tickPeriod));
       
    89 	test.Printf(_L("  tick period == %d\n"), tickPeriod);
       
    90 	
       
    91 	TInt countFreq = 0;
       
    92 	FailIfError(HAL::Get(HAL::EFastCounterFrequency, countFreq));
       
    93 	test.Printf(_L("  count freq == %d\n"), countFreq);
       
    94 
       
    95 	TBool fcCountsUp = 0;
       
    96 	FailIfError(HAL::Get(HAL::EFastCounterCountsUp, fcCountsUp));
       
    97 	test.Printf(_L("  count dir == %S\n"), fcCountsUp ? &KUp : &KDown);
       
    98 
       
    99 	TUint startTick = User::NTickCount();
       
   100 	TUint startCount = User::FastCounter();
       
   101 
       
   102 	User::After(KLongWait);
       
   103 
       
   104 	TUint endTick = User::NTickCount();
       
   105 	TUint endCount = User::FastCounter();
       
   106 
       
   107 	TInt tickDiff = endTick - startTick;
       
   108 	TInt countDiff = fcCountsUp ? (endCount - startCount) : (startCount - endCount);
       
   109 
       
   110 	test.Printf(_L("  tick difference == %d\n"), tickDiff);
       
   111 	test.Printf(_L("  fast count difference == %d\n"), countDiff);
       
   112 
       
   113 	TInt elapsedTickUs = tickDiff * tickPeriod;
       
   114 	TInt elapsedCountUs = (TInt)(((TInt64)1000000 * countDiff) / countFreq);
       
   115 
       
   116 	test.Printf(_L("  tick time == %d\n"), elapsedTickUs);
       
   117 	test.Printf(_L("  count time == %d\n"), elapsedCountUs);
       
   118 
       
   119 	TReal diff = (100.0 * Abs(elapsedCountUs - elapsedTickUs)) / elapsedTickUs;
       
   120 
       
   121 	test.Printf(_L("  %% difference == %f\n"), diff);
       
   122 	test(diff < 1.0);	
       
   123 	test.End();
       
   124 	}
       
   125 
       
   126 TInt ThreadFunction(TAny* aParam)
       
   127 	{
       
   128 	if (numCpus > 1)
       
   129 		{
       
   130 		TInt& core = (static_cast<TThreadParam*>(aParam))->iCpu;
       
   131 		FailIfError(SetCpuAffinity(core));
       
   132 		}
       
   133 
       
   134 	RSemaphore& semaphore = (static_cast<TThreadParam*>(aParam))->iSem;
       
   135 	semaphore.Wait();
       
   136 	for (;;)
       
   137 		{
       
   138 		// Spin
       
   139 		}
       
   140 	}
       
   141 
       
   142 void EnsureSystemIdle()
       
   143 	{
       
   144 	// This test assumes 100% cpu resource is available, so it can fail on
       
   145 	// windows builds if something else is running in the background.  This
       
   146 	// function attempts to wait for the system to become idle.
       
   147 	
       
   148 #ifdef __WINS__
       
   149 
       
   150 	const TInt KMaxWait = 60 * 1000000;
       
   151 	const TInt KSampleTime = 1 * 1000000;
       
   152 	const TInt KWaitTime = 5 * 1000000;
       
   153 	
       
   154 	test.Start(_L("Waiting for system to become idle"));
       
   155 	TInt totalTime = 0;
       
   156 	TBool idle;
       
   157 	do
       
   158 		{
       
   159 		test(totalTime < KMaxWait);
       
   160 		
       
   161 		TThreadParam threadParam;
       
   162 		FailIfError((threadParam.iSem).CreateLocal(0));
       
   163 		threadParam.iCpu = 1;
       
   164 
       
   165 		RThread thread;
       
   166 		FailIfError(thread.Create(_L("Thread"), ThreadFunction, 1024, NULL, &threadParam));		
       
   167 		thread.SetPriority(EPriorityLess);
       
   168 		thread.Resume();
       
   169 
       
   170 		User::After(KShortWait); // Pause to allow thread setup
       
   171 
       
   172 		(threadParam.iSem).Signal();		
       
   173 		User::After(KSampleTime);
       
   174 		thread.Suspend();
       
   175 
       
   176 		TTimeIntervalMicroSeconds time;
       
   177 		FailIfError(thread.GetCpuTime(time));
       
   178 		TReal error = (100.0 * Abs(time.Int64() - KSampleTime)) / KSampleTime;
       
   179 		test.Printf(_L("    time == %ld, error == %f%%\n"), time, error);
       
   180 
       
   181 		idle = error < 2.0;		
       
   182 		
       
   183 		thread.Kill(KErrNone);
       
   184 		TRequestStatus status;
       
   185 		thread.Logon(status);
       
   186 		User::WaitForRequest(status);
       
   187 		test(status == KErrNone);
       
   188 		CLOSE_AND_WAIT(thread);
       
   189 		
       
   190 		(threadParam.iSem).Close();
       
   191 
       
   192 		if (!idle)
       
   193 			User::After(KWaitTime);		// Allow system to finish whatever it's doing
       
   194 
       
   195 		totalTime += KShortWait + KSampleTime + KWaitTime;
       
   196 		}
       
   197 	while(!idle);
       
   198 	
       
   199 	test.End();
       
   200 	
       
   201 #endif
       
   202 	}
       
   203 
       
   204 //! @SYMTestCaseID t_cputime_1
       
   205 //! @SYMTestType CT
       
   206 //! @SYMTestCaseDesc Thread CPU time tests
       
   207 //! @SYMREQ CR RFID-66JJKX
       
   208 //! @SYMTestActions Tests cpu time when a thread is put through the various states
       
   209 //! @SYMTestExpectedResults Reported cpu time increses only when the thread is running
       
   210 //! @SYMTestPriority High
       
   211 //! @SYMTestStatus Defined
       
   212 void TestThreadCpuTime()
       
   213 	{
       
   214 	test.Start(_L("CPU thread time unit tests"));
       
   215 
       
   216 	TThreadParam threadParam;
       
   217 	FailIfError((threadParam.iSem).CreateLocal(0));
       
   218 	threadParam.iCpu = 1;
       
   219 
       
   220 	RThread thread;
       
   221 	RUndertaker u;
       
   222 	TInt h;
       
   223 	TRequestStatus s;
       
   224 	FailIfError(thread.Create(_L("Thread"), ThreadFunction, 1024, NULL, &threadParam));
       
   225 	thread.SetPriority(EPriorityLess);
       
   226 	FailIfError(u.Create());
       
   227 	FailIfError(u.Logon(s,h));
       
   228 	test(s==KRequestPending);
       
   229 
       
   230 	TTimeIntervalMicroSeconds time, time2;
       
   231 	
       
   232 	// Test time is initially zero
       
   233 	FailIfError(thread.GetCpuTime(time));
       
   234 	test(time == 0);
       
   235 
       
   236 	// Test not increased while waiting on semaphore
       
   237 	thread.Resume();
       
   238 	User::After(KShortWait);
       
   239 	FailIfError(thread.GetCpuTime(time));
       
   240 	test(time < KTolerance); // wait happens in less than 0.5ms
       
   241 
       
   242 	// Test increases when thread allowed to run
       
   243 	(threadParam.iSem).Signal();
       
   244 	User::After(KShortWait);
       
   245 	FailIfError(thread.GetCpuTime(time));
       
   246 	test(time > (KShortWait - 2 * KTolerance));
       
   247 
       
   248 	// Test not increased while suspended
       
   249 	thread.Suspend();
       
   250 	FailIfError(thread.GetCpuTime(time));
       
   251 	User::After(KShortWait);
       
   252 	FailIfError(thread.GetCpuTime(time2));
       
   253 	test(time == time2);
       
   254 	thread.Resume();
       
   255 	
       
   256 	// Test not increased while dead
       
   257 	thread.Kill(KErrNone);
       
   258 	User::WaitForRequest(s);	// wait on undertaker since that completes in supervisor thread
       
   259 	FailIfError(thread.GetCpuTime(time));
       
   260 	User::After(KShortWait);
       
   261 	FailIfError(thread.GetCpuTime(time2));
       
   262 	test(time == time2);
       
   263 
       
   264 	RThread t;
       
   265 	t.SetHandle(h);
       
   266 	test(t.Id()==thread.Id());
       
   267 	t.Close();
       
   268 	u.Close();
       
   269 	thread.Close();
       
   270 	(threadParam.iSem).Close();
       
   271 	test.End();
       
   272 	}
       
   273 
       
   274 //! @SYMTestCaseID t_cputime_2
       
   275 //! @SYMTestType CT
       
   276 //! @SYMTestCaseDesc Thread CPU time tests
       
   277 //! @SYMREQ CR RFID-66JJKX
       
   278 //! @SYMTestActions Tests cpu time when multiple threads are running
       
   279 //! @SYMTestExpectedResults Total time is divided evenly among running threads
       
   280 //! @SYMTestPriority High
       
   281 //! @SYMTestStatus Defined
       
   282 
       
   283 TBool DoTestThreadCpuTime2()  // Returns ETrue if test passed
       
   284 	{
       
   285 	test.Start(_L("Testing time shared between threads"));
       
   286 
       
   287 	if (numCpus > 1)
       
   288 		{
       
   289 		test.Printf(_L("** SMP system detected - not testing time shared between threads until load balancing optimized **\n"));
       
   290 		return ETrue;
       
   291 		}
       
   292 
       
   293 	const TInt KMaxThreads = 4;
       
   294 
       
   295 	TThreadParam threadParam;
       
   296 			
       
   297 	RThread* threads = NULL;
       
   298 	threads = new(ELeave) RThread[numCpus*KMaxThreads];
       
   299 	FailIfError((threadParam.iSem).CreateLocal(0));
       
   300 
       
   301 	TBool pass = ETrue;
       
   302 	for (TInt numThreads = 1 ; pass && numThreads <= KMaxThreads ; ++numThreads)
       
   303 		{
       
   304 		test.Printf(_L("  testing with %d threads on each of %d CPUs:\n"), numThreads, numCpus);
       
   305 
       
   306 		TInt i, j, k;
       
   307 		for (i = 0 ; i < numThreads ; ++i)
       
   308 			{
       
   309 			for (j = 0 ; j < numCpus ; ++j)
       
   310 				{
       
   311 				TBuf<16> name;
       
   312 				name.AppendFormat(_L("Thread%d%d"), i, j);
       
   313 				threadParam.iCpu = j;
       
   314 				k = i+j*KMaxThreads;
       
   315 				FailIfError(threads[k].Create(name, ThreadFunction, 1024, NULL, &threadParam));
       
   316 				threads[k].SetPriority(EPriorityLess);
       
   317 				threads[k].Resume();
       
   318 				}
       
   319 			}
       
   320 
       
   321 		User::After(KShortWait); // Pause to allow thread setup
       
   322 
       
   323 		(threadParam.iSem).Signal(numThreads*numCpus);		
       
   324 		User::After(KLongWait);
       
   325 		for (i = 0 ; i < numThreads ; ++i)
       
   326 			for (j = 0 ; j < numCpus ; ++j)
       
   327 				threads[i+j*KMaxThreads].Suspend();
       
   328 
       
   329 		TInt expected = KLongWait / numThreads;
       
   330 		for (i = 0 ; i < numThreads ; ++i)
       
   331 			{
       
   332 			for (j = 0 ; j < numCpus ; ++j)
       
   333 				{
       
   334 				k = i+j*KMaxThreads;
       
   335 				TTimeIntervalMicroSeconds time;
       
   336 				FailIfError(threads[k].GetCpuTime(time));
       
   337 
       
   338 				TReal error = (100.0 * Abs(time.Int64() - expected)) / expected;
       
   339 			
       
   340 				test.Printf(_L("    %d%d: time == %ld, error == %d%%\n"), i, j, time.Int64(), TInt(error));
       
   341 
       
   342 				if (error >= 5.0)
       
   343 					pass = EFalse;
       
   344 
       
   345 				threads[k].Kill(KErrNone);
       
   346 				TRequestStatus status;
       
   347 				threads[k].Logon(status);
       
   348 				User::WaitForRequest(status);
       
   349 				test(status == KErrNone);
       
   350 				CLOSE_AND_WAIT(threads[k]);
       
   351 				}
       
   352 			}
       
   353 		}
       
   354 
       
   355 	(threadParam.iSem).Close();
       
   356 	test.End();
       
   357 
       
   358 	return pass;
       
   359 	}
       
   360 
       
   361 void TestThreadCpuTime2()
       
   362 	{
       
   363 #ifdef __WINS__
       
   364 	TBool pass = EFalse;
       
   365 	for (TInt retry = 0 ; !pass && retry < 5 ; ++retry)
       
   366 		{
       
   367 		if (retry > 0)
       
   368 			{
       
   369 			test.Printf(_L("Test failed, retrying...\n"));
       
   370 			EnsureSystemIdle();
       
   371 			}
       
   372 		pass = DoTestThreadCpuTime2();
       
   373 		}
       
   374 	test(pass);
       
   375 #else
       
   376 	test(DoTestThreadCpuTime2());
       
   377 #endif
       
   378 	}
       
   379 
       
   380 TInt ThreadFunction2(TAny* aParam)
       
   381 	{
       
   382 	TTimeIntervalMicroSeconds& time = *(TTimeIntervalMicroSeconds*)aParam;	
       
   383 	RThread thread;
       
   384 	return thread.GetCpuTime(time);
       
   385 	}
       
   386 
       
   387 #ifdef __MARM__
       
   388 
       
   389 void DoTestThreadCpuTime3(TAny* aParam, TExitType aExpectedExitType, TInt aExpectedExitReason)
       
   390 	{
       
   391 	RThread thread;
       
   392 	FailIfError(thread.Create(_L("TestThread"), ThreadFunction2, 1024, NULL, aParam));
       
   393 	thread.Resume();
       
   394 	TRequestStatus status;
       
   395 	thread.Logon(status);
       
   396 	User::WaitForRequest(status);
       
   397 
       
   398 	TExitCategoryName exitCat = thread.ExitCategory();
       
   399 	test.Printf(_L("Thread exit with type == %d, reason == %d, cat == %S\n"),
       
   400 				thread.ExitType(), thread.ExitReason(), &exitCat);
       
   401 	
       
   402 	test(thread.ExitType() == aExpectedExitType);
       
   403 	test(thread.ExitReason() == aExpectedExitReason);
       
   404 	CLOSE_AND_WAIT(thread);
       
   405 	}
       
   406 
       
   407 void TestThreadCpuTime3()
       
   408 	{
       
   409 	// Test kernel writes the return value back to user-space with the correct permissions
       
   410 	TTimeIntervalMicroSeconds time;
       
   411 	DoTestThreadCpuTime3(&time, 			EExitKill, 0);	// ok
       
   412 	DoTestThreadCpuTime3((TAny*)0, 			EExitPanic, 3);	// null pointer
       
   413 	DoTestThreadCpuTime3((TAny*)0x64000000, EExitPanic, 3);	// start of kernel data on moving memory model
       
   414 	DoTestThreadCpuTime3((TAny*)0xc8000000, EExitPanic, 3);	// start of kernel data on moving multiple model
       
   415 	}
       
   416 
       
   417 #endif
       
   418 
       
   419 GLDEF_C TInt E32Main()
       
   420 	{
       
   421 	test.Title();
       
   422 	test.Start(_L("T_CPUTIME"));
       
   423 	
       
   424 	if (numCpus > 1)
       
   425 		FailIfError(SetCpuAffinity(0));
       
   426 
       
   427 	TestFastCounter();
       
   428 	if (GetCpuTimeIsSupported())
       
   429 		{
       
   430 		EnsureSystemIdle();
       
   431 		TestThreadCpuTime();
       
   432 		TestThreadCpuTime2();
       
   433 #ifdef __MARM__
       
   434 		TestThreadCpuTime3();
       
   435 #endif
       
   436 		}
       
   437 	test.End();
       
   438 	return 0;
       
   439 	}