piprofiler/plugins/GeneralsPlugin/src/GppSamplerImpl.cpp
changeset 22 a009639409f5
child 42 0ff24a8f6ca2
equal deleted inserted replaced
17:67c6ff54ec25 22:a009639409f5
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include <piprofiler/ProfilerVersion.h>
       
    20 #include <piprofiler/ProfilerTraces.h>
       
    21 #include <kern_priv.h>
       
    22 #include <arm.h>
       
    23 
       
    24 #include "GppSamplerImpl.h"
       
    25 
       
    26 extern TUint*		IntStackPtr();
       
    27 #define	TAG(obj)	(*(TUint32*)&(obj.iAsyncDeleteNext))
       
    28 
       
    29 // properties for ISA task parsing
       
    30 const TUid KIsaPropertyCat={0x2001E5AD};
       
    31 enum TIsaPropertyKeys
       
    32 	{
       
    33 	EIsaPropertyIsaTaskParserStatus = 1,
       
    34 	EIsaPropertyIsaTaskAddressStart,
       
    35 	EIsaPropertyIsaTaskAddressEnd,
       
    36 	EIsaPropertyIsaTaskAddress,
       
    37 	EIsaPropertyIsaOsTaskRunningAddress,
       
    38 	EIsaPropertyIsaTaskParsedName
       
    39 	};
       
    40 
       
    41 
       
    42 DGppSamplerImpl::DGppSamplerImpl()
       
    43 	{
       
    44 	LOGTEXT("GppSamplerImpl::GppSamplerImpl");
       
    45 	iInterruptStack = (TUint*)IntStackPtr();
       
    46 
       
    47 	LOGTEXT("GppSamplerImpl::GppSamplerImpl - attaching to properties");
       
    48 
       
    49 	TInt err = iIsaStartAddr.Attach(KIsaPropertyCat, EIsaPropertyIsaTaskAddressStart);
       
    50 	if(err != KErrNone)
       
    51 		LOGTEXT("GppSamplerImpl::GppSamplerImpl() - Property EIsaPropertyIsaTaskAddressStart not available"); 
       
    52 	err = iIsaEndAddr.Attach(KIsaPropertyCat, EIsaPropertyIsaTaskAddressEnd);
       
    53 	if(err != KErrNone)
       
    54 		LOGTEXT("GppSamplerImpl::GppSamplerImpl() - Property EIsaPropertyIsaTaskAddressEnd not available"); 
       
    55 	err = iIsaPluginStatus.Attach(KIsaPropertyCat, EIsaPropertyIsaTaskParserStatus);
       
    56 	if(err != KErrNone)
       
    57 		LOGTEXT("GppSamplerImpl::GppSamplerImpl() - Property EIsaPropertyIsaTaskParserStatus not available"); 
       
    58 	err = iIsaOsTaskRunning.Attach(KIsaPropertyCat, EIsaPropertyIsaOsTaskRunningAddress);
       
    59 	if(err != KErrNone)
       
    60 		LOGTEXT("GppSamplerImpl::GppSamplerImpl() - Property EIsaPropertyIsaOsTaskRunningAddress not available"); 
       
    61 	
       
    62 	PROFILER_ISA_TASK_NAMES
       
    63 	
       
    64 	Reset();
       
    65 	}
       
    66 
       
    67 DGppSamplerImpl::~DGppSamplerImpl() 
       
    68 	{
       
    69 	iIsaStartAddr.Close();
       
    70 	iIsaEndAddr.Close();
       
    71 	iIsaPluginStatus.Close();
       
    72 	iIsaOsTaskRunning.Close();
       
    73 	}
       
    74 
       
    75 void DGppSamplerImpl::Reset()
       
    76 	{
       
    77 	LOGTEXT("GppSamplerImpl::Reset");
       
    78 	iLastPc = 0;
       
    79 	iLastThread = 0;
       
    80 	iRepeat = 0;
       
    81 	iIsaStatus = 0;
       
    82 	iIsaStart = 0;
       
    83 	iIsaEnd = 0;
       
    84 //	isaOsTaskRunningAddr = 0;
       
    85 	
       
    86 	// in SMP start time common with all CPUs, provided by DGeneralsDriver class
       
    87 #ifndef __SMP__
       
    88 	iStartTime = ( NKern::TickCount() & 0xfffffffc );
       
    89 #endif
       
    90 	
       
    91 	TPropertyStatus status;
       
    92 	TInt osAddr = 0;
       
    93 	
       
    94 	LOGTEXT("GppSamplerImpl::Reset - getting status");
       
    95 	
       
    96 	// get status of ISA plug-in
       
    97 	if(iIsaPluginStatus.GetStatus(status))
       
    98 		{
       
    99 		iIsaPluginStatus.Get(iIsaStatus);
       
   100 		LOGSTRING2("GppSamplerImpl::Reset - ISA plug-in status %d", iIsaStatus);
       
   101 		}
       
   102 	
       
   103 	if(iIsaStatus > 0)
       
   104 		{
       
   105 		LOGTEXT("GppSamplerImpl::Reset - get isa start address");
       
   106 		iIsaStartAddr.Get(iIsaStart);
       
   107 		LOGTEXT("GppSamplerImpl::Reset - get isa end address");
       
   108 		iIsaEndAddr.Get(iIsaEnd);
       
   109 		LOGTEXT("GppSamplerImpl::Reset - get isa os_task_running address");
       
   110 		iIsaOsTaskRunning.Get(osAddr);
       
   111 		isaOsTaskRunningAddr = reinterpret_cast<TInt*>(osAddr);
       
   112 		LOGSTRING2("GppSamplerImpl::Reset - got isa os_task_running address 0x%X", osAddr);
       
   113 		}
       
   114 	
       
   115 	LOGTEXT("GppSamplerImpl::Reset - initializing isa task list");
       
   116 
       
   117 	iIsaSample = false;
       
   118 	
       
   119 	for(TInt i=0;i<256;i++)
       
   120 		knownIsaTasks[i] = -1;
       
   121 	
       
   122 	knownIsaTaskCount = 0;
       
   123     
       
   124 	iCpuSelector = 0x3;
       
   125 #ifndef __SMP__
       
   126     iMask =  0xfffffffc;
       
   127 #else
       
   128     iMask =  0xfffffff0;
       
   129     switch(iCpuNumber)
       
   130         {
       
   131         case 0:
       
   132             iCpuSelector = 0x1;
       
   133             break;
       
   134         case 1:
       
   135             iCpuSelector = 0x2;
       
   136             break;
       
   137         case 2:
       
   138             iCpuSelector = 0x4;
       
   139             break;
       
   140         case 3:
       
   141             iCpuSelector = 0x8;
       
   142             break;
       
   143         }
       
   144 #endif
       
   145 	}
       
   146 
       
   147 TUint8* DGppSamplerImpl::EncodeTag(TUint8* aPtr)
       
   148 //
       
   149 // Encode a tag and version to the trace data. This allows the offline analyser to 
       
   150 // identify the sample data.
       
   151 //
       
   152 {	
       
   153 	_LIT(KGppSamplerVersion,"Bappea_GPP_V");
       
   154 	_LIT(KProfilerVersion,"#Prof#");
       
   155 	_LIT(KSamplerVersion,"#Samp#");
       
   156 #ifdef __SMP__
       
   157 	_LIT(KCPUNumberText,"#CPU#");
       
   158 #endif
       
   159 	
       
   160 	TBuf<64> buf;
       
   161 	buf.Zero();
       
   162 	buf.Append(KGppSamplerVersion);
       
   163 	buf.Append(PROFILER_GPP_SAMPLER_VERSION);
       
   164 	buf.Append(KProfilerVersion);
       
   165 	buf.Append(PROFILER_VERSION_SHORT);	
       
   166 	buf.Append(KSamplerVersion);
       
   167 	buf.Append(PROFILER_SAMPLER_VERSION);
       
   168 #ifdef __SMP__
       
   169 	buf.Append(KCPUNumberText);
       
   170 	buf.AppendNum(iCpuNumber);
       
   171 #endif
       
   172 	aPtr = EncodeText(aPtr, buf);
       
   173 	return aPtr;
       
   174 }
       
   175 
       
   176 TUint8* DGppSamplerImpl::EncodeInt(TUint8* aPtr,TInt aValue)
       
   177 {
       
   178 	LOGSTRING2("Encoding int 0x%x",aPtr);
       
   179 
       
   180 	LOGSTRING2("TIint = 0x%x",aValue);
       
   181 
       
   182 	TUint byte;
       
   183 	for (;;)
       
   184 		{
       
   185 		byte = aValue & 0x7f;
       
   186 		if ((aValue >> 6) == (aValue >> 7))
       
   187 			break;
       
   188 		aValue >>= 7;
       
   189 		*aPtr++ = byte;
       
   190 		}
       
   191 	*aPtr++ = byte | 0x80;
       
   192 
       
   193 	LOGSTRING2("Encoded int 0x%x",aPtr);
       
   194 
       
   195 	return aPtr;
       
   196 }
       
   197 
       
   198 TUint8* DGppSamplerImpl::EncodeUint(TUint8* aPtr,TUint aValue)
       
   199 {
       
   200 	LOGSTRING2("Encoding Uint 0x%x",aPtr);
       
   201 
       
   202 	LOGSTRING2("TUint = 0x%x",aValue);
       
   203 
       
   204 
       
   205 	TUint byte;
       
   206 	for (;;)
       
   207 		{
       
   208 		byte = aValue & 0x7f;
       
   209 		aValue >>= 7;
       
   210 		if (aValue == 0)
       
   211 			break;
       
   212 		*aPtr++ = byte;
       
   213 		}
       
   214 	*aPtr++ = byte | 0x80;
       
   215 
       
   216 	LOGSTRING2("Encoded Uint 0x%x",aPtr);
       
   217 
       
   218 	return aPtr;
       
   219 }
       
   220 
       
   221 TUint8* DGppSamplerImpl::EncodeText(TUint8* aPtr, const TDesC& aDes)
       
   222 //
       
   223 // Encode a descriptor into the data stream
       
   224 // This is currently limited to a descriptor that is up to 255 characters in length,
       
   225 // and Unicode characters are truncated to 8 bits
       
   226 //
       
   227 {
       
   228 	LOGSTRING2("Encoding text 0x%x",aPtr);
       
   229 	TInt len=aDes.Length();
       
   230 	*aPtr++ = TUint8(len);
       
   231 	const TText* p = aDes.Ptr();
       
   232 	while (--len >= 0)
       
   233 		{
       
   234 		*aPtr++ = TUint8(*p++);
       
   235 		}
       
   236 
       
   237 	LOGSTRING2("Encoded text 0x%x",aPtr);
       
   238 	return aPtr;
       
   239 }
       
   240 
       
   241 
       
   242 TUint8* DGppSamplerImpl::EncodeName(TUint8* aPtr, DObject& aObject,TUint32 id)
       
   243 //
       
   244 // Encode the name of a kernel object
       
   245 //
       
   246 {
       
   247 	LOGSTRING2("Encoding name 0x%x",aPtr);
       
   248 	TBuf8<0x5f> name;
       
   249 	aObject.TraceAppendName(name,false);
       
   250 
       
   251 	if(id != 0xffffffff)
       
   252 	{
       
   253 		name.Append('[');
       
   254 		name.AppendNum(id,EHex);
       
   255 		name.Append(']');
       
   256 	}
       
   257 	else
       
   258 	{
       
   259 		name.Append('[');
       
   260 		name.AppendNum((TUint32)((void*)&(((DThread*)&aObject)->iNThread)),EHex);
       
   261 		name.Append(']');
       
   262 	}
       
   263 
       
   264 	aPtr = EncodeText(aPtr,name);
       
   265 	LOGSTRING2("Encoded name 0x%x",aPtr);
       
   266 	return aPtr;
       
   267 }
       
   268 
       
   269 TUint8* DGppSamplerImpl::EncodeThread(TUint8* aPtr, DThread& aThread)
       
   270 //
       
   271 // Encode a thread name in the data stream.
       
   272 // The thread is identified by its name, and the identity of its owning process.
       
   273 // If the process has not been identified in the data stream already, it's name is
       
   274 // also encoded.
       
   275 //
       
   276 {
       
   277 	LOGSTRING2("Encoding thread 0x%x",aPtr);	
       
   278 
       
   279 	DProcess& p = *aThread.iOwningProcess;
       
   280 	
       
   281 	aPtr = EncodeUint(aPtr, p.iId);
       
   282 
       
   283 #ifdef __SMP__
       
   284     // check if first time founding
       
   285     if ((TAG(p) & iMask) != iStartTime)
       
   286         {
       
   287         // mark tagged for this CPU
       
   288         TAG(p) = (iStartTime | iCpuSelector);
       
   289 
       
   290         // The thread is 'unknown' to this sample, so encode the thread name
       
   291         aPtr = EncodeName(aPtr, p, p.iId);     
       
   292         }
       
   293     // check if thread appeared already on this CPU
       
   294     else if((TAG(p) & iCpuSelector) != iCpuSelector)
       
   295         {
       
   296         TAG(p) = (TAG(p) | iCpuSelector);
       
   297         // The thread is 'unknown' to this sample, so encode the thread name
       
   298         aPtr = EncodeName(aPtr, p, p.iId);     
       
   299         }
       
   300 #else
       
   301 	if (TAG(p) != iStartTime)
       
   302 	    {
       
   303 		TAG(p) = iStartTime;
       
   304 		// Provide the name matching this process ID
       
   305 		aPtr = EncodeName(aPtr, p, p.iId);
       
   306 	    }
       
   307 #endif	    
       
   308 	aPtr = EncodeName(aPtr, aThread,0xffffffff);
       
   309 	
       
   310 	LOGSTRING2("Encoded thread 0x%x",aPtr);	
       
   311 
       
   312 	return aPtr;
       
   313     }
       
   314 
       
   315 TUint8* DGppSamplerImpl::EncodeRepeat(TUint8* aPtr)
       
   316 //
       
   317 // Encode a repeated sequence of samples
       
   318 //
       
   319 {
       
   320 	LOGSTRING2("Encoding repeat, 0x%x",iRepeat);	
       
   321 
       
   322 	aPtr = EncodeInt(aPtr, 0);
       
   323 	aPtr = EncodeUint(aPtr, iRepeat);
       
   324 	iRepeat = 0;
       
   325 
       
   326 	LOGSTRING2("Encoded repeat, 0x%x",iRepeat);	
       
   327 
       
   328 	return aPtr;
       
   329 }
       
   330 
       
   331 TInt DGppSamplerImpl::CreateFirstSample()
       
   332 {
       
   333 	LOGTEXT("GppSamplerImpl::CreateFirstSample");
       
   334 	Reset();
       
   335 
       
   336 	TUint8* w = this->tempBuf;
       
   337 	w = EncodeTag(w);
       
   338 
       
   339 	TInt length = w-tempBuf;
       
   340 
       
   341 	LOGSTRING2("TAG encoded, length %d",length);
       
   342 	return length;
       
   343 }
       
   344 
       
   345 TBool DGppSamplerImpl::IsaTaskKnown(TUint8 task)
       
   346 {
       
   347 	for(TInt i=0;i<256;i++)
       
   348 	{
       
   349 		if(knownIsaTasks[i] == -1)
       
   350 		{
       
   351 			knownIsaTasks[i] = task;
       
   352 			knownIsaTaskCount++;
       
   353 			return false;
       
   354 		}
       
   355 		else if(knownIsaTasks[i] == task)
       
   356 		{
       
   357 			return true;
       
   358 		}
       
   359 	}
       
   360 
       
   361 	return false;
       
   362 }
       
   363 
       
   364 TUint8* DGppSamplerImpl::EncodeIsaTask(TUint8* aPtr, TUint task)
       
   365 
       
   366 {
       
   367 	LOGSTRING2("Encoding ISA task 0x%x",aPtr);	
       
   368 
       
   369 	aPtr = EncodeUint(aPtr,task);
       
   370 	// use the task name as the process name
       
   371 	aPtr = EncodeIsaName(aPtr,task,true);
       
   372 	// then encode the task name
       
   373 	aPtr = EncodeIsaName(aPtr,task,false);
       
   374 	
       
   375 	LOGSTRING2("Encoded ISA task 0x%x",aPtr);	
       
   376 
       
   377 	return aPtr;
       
   378 }
       
   379 
       
   380 TUint8* DGppSamplerImpl::EncodeIsaName(TUint8* aPtr, TUint task,TBool process)
       
   381 //
       
   382 // Encode a descriptor into the data stream
       
   383 // This is currently limited to a descriptor that is up to 255 characters in length,
       
   384 // and Unicode characters are truncated to 8 bits
       
   385 //
       
   386 {
       
   387 	TBuf8<256> aDes;
       
   388 	
       
   389 //	#ifdef NCP_COMMON_PROFILER_ISA_TASKS 
       
   390 	if(iIsaStatus > 0)
       
   391 		{
       
   392 		// resolve the isa task name from the task name array
       
   393 		if((task-100000) < PROFILER_ISA_OS_TASK_AMOUNT && process == false)
       
   394 			{
       
   395 			aDes.Append(isaTaskNames[(task-100000)]);
       
   396 			}
       
   397 		else
       
   398 			{
       
   399 			aDes.Append(_L8("NativeOS_Task"));
       
   400 			}
       
   401 		}
       
   402 	else
       
   403 		{
       
   404 		aDes.Append(_L8("NativeOS_Task"));
       
   405 		}
       
   406 	
       
   407 	aDes.Append('[');
       
   408 	aDes.AppendNum((task-100000),EHex);
       
   409 	aDes.Append(']');
       
   410 
       
   411 	LOGSTRING2("Encoding ISA name 0x%x",aPtr);
       
   412 	TInt len=aDes.Length();
       
   413 	*aPtr++ = TUint8(len);
       
   414 	const TText* p = aDes.Ptr();
       
   415 	while (--len >= 0)
       
   416 		{
       
   417 		*aPtr++ = TUint8(*p++);
       
   418 		}
       
   419 
       
   420 	LOGSTRING2("Encoded ISA name 0x%x",aPtr);
       
   421 	return aPtr;
       
   422 }
       
   423 
       
   424 
       
   425 TInt DGppSamplerImpl::SampleImpl()
       
   426 //
       
   427 // ISR for the profile timer
       
   428 // This extracts the thread and PC that was current when the interrupt went off and
       
   429 // encodes it into the sample data buffer. If enough data has been generated, the
       
   430 // DFC is triggered to complete a read request
       
   431 //
       
   432     {
       
   433 	TUint8* w(this->tempBuf);
       
   434 	
       
   435 //    Kern::Printf(("Got thread 0x%08x"), &t);
       
   436 #ifdef __SMP__
       
   437     // get the program counter of irq mode
       
   438     TUint32 pc = (TUint32)Arm::IrqReturnAddress();
       
   439 #else
       
   440     // get program counter of irq mode
       
   441     TUint32 pc = iInterruptStack[-1];
       
   442 #endif
       
   443     //LOGSTRING3("pc value 0x%x sp 0x%x",pc,iInterruptStack);
       
   444 
       
   445 	// ignore the low bit being set for THUMB mode - we use for something else
       
   446 	pc &= ~1;			
       
   447 	TInt diff = pc - iLastPc;
       
   448 	iLastPc = pc;
       
   449 
       
   450 	if(iIsaStatus > 0)
       
   451 		{
       
   452 		if((TUint32)pc > (TUint32)iIsaStart && (TUint32)pc < (TUint32)iIsaEnd)
       
   453 			{
       
   454 			LOGSTRING2("Identified ISA execution at 0x%x",pc);
       
   455 			iIsaSample = true;
       
   456 			}
       
   457 		else
       
   458 			{
       
   459 			LOGSTRING2("Normal sample at 0x%x",pc);
       
   460 			iIsaSample = false;
       
   461 			}
       
   462 		}
       
   463 
       
   464 	// request for current thread from kernel
       
   465 	DThread& t = ((DThread&)*Kern::NThreadToDThread(NKern::CurrentThread()));
       
   466 	
       
   467 	TUint tid;
       
   468 	TUint8 isaTask = 0;
       
   469 	if(iIsaSample)
       
   470 	{
       
   471 		LOGSTRING2("Reading ISA task number from 0x%x",isaOsTaskRunningAddr);
       
   472 
       
   473 		// if we don't get reasonable ISA address to read, skip ISA task handling
       
   474 		if(isaOsTaskRunningAddr == 0)
       
   475 			{
       
   476 			tid = 100000; // to tell the difference from SOS threads
       
   477 			iIsaSample = false;
       
   478 			}
       
   479 		else	// normal ISA task parsing process
       
   480 			{
       
   481 			isaTask = *isaOsTaskRunningAddr;
       
   482 			LOGSTRING2("ISA task = %d",isaTask);
       
   483 			tid = isaTask;
       
   484 			// this will make sure we don't mix ISA tasks and normal tasks
       
   485 			tid += 100000;
       
   486 			}
       
   487 
       
   488 	}
       
   489 	else
       
   490 	{
       
   491 		tid = t.iId;
       
   492 	}
       
   493 
       
   494 	if (tid != iLastThread)
       
   495 	{
       
   496 		// Change of thread is marked in the low bit of the PC difference
       
   497 		diff |= 1;
       
   498 	}
       
   499 	TUint rp = iRepeat;
       
   500 	if (diff == 0)
       
   501 	{
       
   502 		// Identical sample, bump up the repeat count
       
   503 		iRepeat = rp + 1;
       
   504 	}
       
   505 	else
       
   506 	{
       
   507 		if (rp)
       
   508 		{
       
   509 			// Encode the repeat data
       
   510 			w = EncodeRepeat(w);
       
   511 		}
       
   512 		// Encode the PC difference
       
   513 		w = EncodeInt(w, diff);
       
   514 		if (diff & 1)
       
   515 		{
       
   516 			// Encode the new thread ID
       
   517 			if(iIsaSample)
       
   518 			{
       
   519 				iLastThread = tid;
       
   520 				w = EncodeUint(w,tid);
       
   521 
       
   522 				if(!this->IsaTaskKnown(isaTask))
       
   523 				{
       
   524 					w = EncodeIsaTask(w,iLastThread);
       
   525 				}
       
   526 				//LOGSTRING2("Sample total length: %d",w-tempBuf);
       
   527 				TInt length = w-tempBuf;
       
   528 				// encoded isa task, return here
       
   529 				return length;
       
   530 			}
       
   531 		
       
   532 			iLastThread = tid;
       
   533 			w = EncodeUint(w, tid);
       
   534 
       
   535 #ifdef __SMP__
       
   536 			// iStartTime format: 0xXXXXXXX0, the last byte set to zero
       
   537 			// iMask =  0xfffffff0(0b111....1110000)
       
   538 			// iCpuSelector = 0x1(0b0001), 0x2(0b0010), 0x4(0b0100) or 0x8(0b1000) 
       
   539 			
       
   540 			// check first time founding
       
   541 			if ((TAG(t) & iMask) != iStartTime)
       
   542 			    {
       
   543 			    // mark tagged for this CPU
       
   544 				TAG(t) = (iStartTime | iCpuSelector);
       
   545 				
       
   546 				// The thread is 'unknown' to this sample, so encode the thread name
       
   547 				w = EncodeThread(w, t);		
       
   548 			    }
       
   549 			// check if thread appeared on this CPU
       
   550 			else if((TAG(t) & iCpuSelector) != iCpuSelector)
       
   551 			    {
       
   552                 TAG(t) = (TAG(t) | iCpuSelector);
       
   553                 // The thread is 'unknown' to this sample, so encode the thread name
       
   554                 w = EncodeThread(w, t);     
       
   555 			    }
       
   556 #else
       
   557 			// check if tag has not been set, neither original nor 
       
   558             if ((TAG(t) & 0xfffffffc) != iStartTime)
       
   559                 {
       
   560                 TAG(t) = ((TAG(t) & 0x3) | iStartTime);
       
   561                 // The thread is 'unknown' to this sample, so encode the thread name
       
   562                 w = EncodeThread(w, t);     
       
   563                 }
       
   564 #endif
       
   565 		    }
       
   566 	    }
       
   567 	LOGSTRING2("Sample total length: %d",w-tempBuf);
       
   568 	TInt length = w-tempBuf;
       
   569 
       
   570 	return length;
       
   571 }
       
   572