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