os/kernelhwsrv/kerneltest/e32test/misc/t_cputime.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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 =    1000;  // 1 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 = 0;				// Later tests will exercise other CPUs
   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 - 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 	}