diff -r f0f2b8682603 -r 3ff3fecb12fe sysanadatacapture/piprofiler/piprofiler/plugins/GeneralsPlugin/src/GppSamplerImpl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sysanadatacapture/piprofiler/piprofiler/plugins/GeneralsPlugin/src/GppSamplerImpl.cpp Thu Feb 11 15:52:57 2010 +0200 @@ -0,0 +1,488 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + +#include +#include +#include + +#include "GppSamplerImpl.h" + +extern TUint* IntStackPtr(); +#define TAG(obj) (*(TUint32*)&(obj.iAsyncDeleteNext)) + +// properties for ISA task parsing +const TUid KIsaPropertyCat={0x2001E5AD}; +enum TIsaPropertyKeys + { + EIsaPropertyIsaTaskParserStatus = 1, + EIsaPropertyIsaTaskAddressStart, + EIsaPropertyIsaTaskAddressEnd, + EIsaPropertyIsaTaskAddress, + EIsaPropertyIsaOsTaskRunningAddress, + EIsaPropertyIsaTaskParsedName + }; + + +GppSamplerImpl::GppSamplerImpl() + { + LOGTEXT("GppSamplerImpl::GppSamplerImpl"); + iInterruptStack = (TUint*)IntStackPtr(); + + LOGTEXT("GppSamplerImpl::GppSamplerImpl - attaching to properties"); + + TInt err = iIsaStartAddr.Attach(KIsaPropertyCat, EIsaPropertyIsaTaskAddressStart); + if(err != KErrNone) + LOGTEXT("GppSamplerImpl::GppSamplerImpl() - Property EIsaPropertyIsaTaskAddressStart not available"); + err = iIsaEndAddr.Attach(KIsaPropertyCat, EIsaPropertyIsaTaskAddressEnd); + if(err != KErrNone) + LOGTEXT("GppSamplerImpl::GppSamplerImpl() - Property EIsaPropertyIsaTaskAddressEnd not available"); + err = iIsaPluginStatus.Attach(KIsaPropertyCat, EIsaPropertyIsaTaskParserStatus); + if(err != KErrNone) + LOGTEXT("GppSamplerImpl::GppSamplerImpl() - Property EIsaPropertyIsaTaskParserStatus not available"); + err = iIsaOsTaskRunning.Attach(KIsaPropertyCat, EIsaPropertyIsaOsTaskRunningAddress); + if(err != KErrNone) + LOGTEXT("GppSamplerImpl::GppSamplerImpl() - Property EIsaPropertyIsaOsTaskRunningAddress not available"); + + PROFILER_ISA_TASK_NAMES + + Reset(); + } + +GppSamplerImpl::~GppSamplerImpl() + { + iIsaStartAddr.Close(); + iIsaEndAddr.Close(); + iIsaPluginStatus.Close(); + iIsaOsTaskRunning.Close(); + } + +void GppSamplerImpl::Reset() + { + LOGTEXT("GppSamplerImpl::Reset"); + iLastPc = 0; + iLastThread = 0; + iRepeat = 0; + iIsaStatus = 0; + iIsaStart = 0; + iIsaEnd = 0; +// isaOsTaskRunningAddr = 0; + iStartTime=( NKern::TickCount() & 0xfffffffc ); + + TPropertyStatus status; + TInt osAddr = 0; + + LOGTEXT("GppSamplerImpl::Reset - getting status"); + + // get status of ISA plug-in + if(iIsaPluginStatus.GetStatus(status)) + { + iIsaPluginStatus.Get(iIsaStatus); + LOGSTRING2("GppSamplerImpl::Reset - ISA plug-in status %d", iIsaStatus); + } + + if(iIsaStatus > 0) + { + LOGTEXT("GppSamplerImpl::Reset - get isa start address"); + iIsaStartAddr.Get(iIsaStart); + LOGTEXT("GppSamplerImpl::Reset - get isa end address"); + iIsaEndAddr.Get(iIsaEnd); + LOGTEXT("GppSamplerImpl::Reset - get isa os_task_running address"); + iIsaOsTaskRunning.Get(osAddr); + isaOsTaskRunningAddr = reinterpret_cast(osAddr); + LOGSTRING2("GppSamplerImpl::Reset - got isa os_task_running address 0x%X", osAddr); + } + + LOGTEXT("GppSamplerImpl::Reset - initializing isa task list"); + + iIsaSample = false; + + for(TInt i=0;i<256;i++) + knownIsaTasks[i] = -1; + + knownIsaTaskCount = 0; + + } + +TUint8* GppSamplerImpl::EncodeTag(TUint8* aPtr) +// +// Encode a tag and version to the trace data. This allows the offline analyser to +// identify the sample data. +// +{ + _LIT(KGppSamplerVersion,"Bappea_GPP_V"); + _LIT(KProfilerVersion,"#Prof#"); + _LIT(KSamplerVersion,"#Samp#"); + + TBuf<64> buf; + buf.Zero(); + buf.Append(KGppSamplerVersion); + buf.Append(PROFILER_GPP_SAMPLER_VERSION); + buf.Append(KProfilerVersion); + buf.Append(PROFILER_VERSION_SHORT); + buf.Append(KSamplerVersion); + buf.Append(PROFILER_SAMPLER_VERSION); + aPtr = EncodeText(aPtr, buf); + return aPtr; +} + +TUint8* GppSamplerImpl::EncodeInt(TUint8* aPtr,TInt aValue) +{ + LOGSTRING2("Encoding int 0x%x",aPtr); + + LOGSTRING2("TIint = 0x%x",aValue); + + TUint byte; + for (;;) + { + byte = aValue & 0x7f; + if ((aValue >> 6) == (aValue >> 7)) + break; + aValue >>= 7; + *aPtr++ = byte; + } + *aPtr++ = byte | 0x80; + + LOGSTRING2("Encoded int 0x%x",aPtr); + + return aPtr; +} + +TUint8* GppSamplerImpl::EncodeUint(TUint8* aPtr,TUint aValue) +{ + LOGSTRING2("Encoding Uint 0x%x",aPtr); + + LOGSTRING2("TUint = 0x%x",aValue); + + + TUint byte; + for (;;) + { + byte = aValue & 0x7f; + aValue >>= 7; + if (aValue == 0) + break; + *aPtr++ = byte; + } + *aPtr++ = byte | 0x80; + + LOGSTRING2("Encoded Uint 0x%x",aPtr); + + return aPtr; +} + +TUint8* GppSamplerImpl::EncodeText(TUint8* aPtr, const TDesC& aDes) +// +// Encode a descriptor into the data stream +// This is currently limited to a descriptor that is up to 255 characters in length, +// and Unicode characters are truncated to 8 bits +// +{ + LOGSTRING2("Encoding text 0x%x",aPtr); + TInt len=aDes.Length(); + *aPtr++ = TUint8(len); + const TText* p = aDes.Ptr(); + while (--len >= 0) + { + *aPtr++ = TUint8(*p++); + } + + LOGSTRING2("Encoded text 0x%x",aPtr); + return aPtr; +} + + +TUint8* GppSamplerImpl::EncodeName(TUint8* aPtr, DObject& aObject,TUint32 id) +// +// Encode the name of a kernel object +// +{ + LOGSTRING2("Encoding name 0x%x",aPtr); + TBuf8<0x5f> name; + aObject.TraceAppendName(name,false); + + if(id != 0xffffffff) + { + name.Append('['); + name.AppendNum(id,EHex); + name.Append(']'); + } + else + { + name.Append('['); + name.AppendNum((TUint32)((void*)&(((DThread*)&aObject)->iNThread)),EHex); + name.Append(']'); + } + + aPtr = EncodeText(aPtr,name); + LOGSTRING2("Encoded name 0x%x",aPtr); + return aPtr; +} + +TUint8* GppSamplerImpl::EncodeThread(TUint8* aPtr, DThread& aThread) +// +// Encode a thread name in the data stream. +// The thread is identified by its name, and the identity of its owning process. +// If the process has not been identified in the data stream already, it's name is +// also encoded. +// +{ + LOGSTRING2("Encoding thread 0x%x",aPtr); + + DProcess& p = *aThread.iOwningProcess; + + aPtr = EncodeUint(aPtr, p.iId); + if (TAG(p) != iStartTime) + { + TAG(p) = iStartTime; + // Provide the name matching this process ID + aPtr = EncodeName(aPtr, p, p.iId); + } + aPtr = EncodeName(aPtr, aThread,0xffffffff); + + LOGSTRING2("Encoded thread 0x%x",aPtr); + + return aPtr; +} + +TUint8* GppSamplerImpl::EncodeRepeat(TUint8* aPtr) +// +// Encode a repeated sequence of samples +// +{ + LOGSTRING2("Encoding repeat, 0x%x",iRepeat); + + aPtr = EncodeInt(aPtr, 0); + aPtr = EncodeUint(aPtr, iRepeat); + iRepeat = 0; + + LOGSTRING2("Encoded repeat, 0x%x",iRepeat); + + return aPtr; +} + +TInt GppSamplerImpl::CreateFirstSample() +{ + LOGTEXT("GppSamplerImpl::CreateFirstSample"); + Reset(); + + TUint8* w = this->tempBuf; + w = EncodeTag(w); + + TInt length = w-tempBuf; + + LOGSTRING2("TAG encoded, length %d",length); + return length; +} + +TBool GppSamplerImpl::IsaTaskKnown(TUint8 task) +{ + for(TInt i=0;i<256;i++) + { + if(knownIsaTasks[i] == -1) + { + knownIsaTasks[i] = task; + knownIsaTaskCount++; + return false; + } + else if(knownIsaTasks[i] == task) + { + return true; + } + } + + return false; +} + +TUint8* GppSamplerImpl::EncodeIsaTask(TUint8* aPtr, TUint task) + +{ + LOGSTRING2("Encoding ISA task 0x%x",aPtr); + + aPtr = EncodeUint(aPtr,task); + // use the task name as the process name + aPtr = EncodeIsaName(aPtr,task,true); + // then encode the task name + aPtr = EncodeIsaName(aPtr,task,false); + + LOGSTRING2("Encoded ISA task 0x%x",aPtr); + + return aPtr; +} + +TUint8* GppSamplerImpl::EncodeIsaName(TUint8* aPtr, TUint task,TBool process) +// +// Encode a descriptor into the data stream +// This is currently limited to a descriptor that is up to 255 characters in length, +// and Unicode characters are truncated to 8 bits +// +{ + TBuf8<256> aDes; + +// #ifdef NCP_COMMON_PROFILER_ISA_TASKS + if(iIsaStatus > 0) + { + // resolve the isa task name from the task name array + if((task-100000) < PROFILER_ISA_OS_TASK_AMOUNT && process == false) + { + aDes.Append(isaTaskNames[(task-100000)]); + } + else + { + aDes.Append(_L8("NativeOS_Task")); + } + } + else + { + aDes.Append(_L8("NativeOS_Task")); + } + + aDes.Append('['); + aDes.AppendNum((task-100000),EHex); + aDes.Append(']'); + + LOGSTRING2("Encoding ISA name 0x%x",aPtr); + TInt len=aDes.Length(); + *aPtr++ = TUint8(len); + const TText* p = aDes.Ptr(); + while (--len >= 0) + { + *aPtr++ = TUint8(*p++); + } + + LOGSTRING2("Encoded ISA name 0x%x",aPtr); + return aPtr; +} + + +TInt GppSamplerImpl::SampleImpl() +// +// ISR for the profile timer +// This extracts the thread and PC that was current when the interrupt went off and +// encodes it into the sample data buffer. If enough data has been generated, the +// DFC is triggered to complete a read request +// +{ + TUint8* w = this->tempBuf; + + TUint32 pc = iInterruptStack[-1]; + LOGSTRING3("pc value 0x%x sp 0x%x",pc,iInterruptStack); + + // ignore the low bit being set for THUMB mode - we use for something else + pc &= ~1; + TInt diff = pc - iLastPc; + iLastPc = pc; + + if(iIsaStatus > 0) + { + if((TUint32)pc > (TUint32)iIsaStart && (TUint32)pc < (TUint32)iIsaEnd) + { + LOGSTRING2("Identified ISA execution at 0x%x",pc); + iIsaSample = true; + } + else + { + LOGSTRING2("Normal sample at 0x%x",pc); + iIsaSample = false; + } + } + + DThread& t = Kern::CurrentThread(); + + TUint tid; + TUint8 isaTask = 0; + if(iIsaSample) + { + LOGSTRING2("Reading ISA task number from 0x%x",isaOsTaskRunningAddr); + + // if we don't get reasonable ISA address to read, skip ISA task handling + if(isaOsTaskRunningAddr == 0) + { + tid = 100000; // to tell the difference from SOS threads + iIsaSample = false; + } + else // normal ISA task parsing process + { + isaTask = *isaOsTaskRunningAddr; + LOGSTRING2("ISA task = %d",isaTask); + tid = isaTask; + // this will make sure we don't mix ISA tasks and normal tasks + tid += 100000; + } + + } + else + { + tid = t.iId; + } + + if (tid != iLastThread) + { + // Change of thread is marked in the low bit of the PC difference + diff |= 1; + } + TUint rp = iRepeat; + if (diff == 0) + { + // Identical sample, bump up the repeat count + iRepeat = rp + 1; + } + else + { + if (rp) + { + // Encode the repeat data + w = EncodeRepeat(w); + } + // Encode the PC difference + w = EncodeInt(w, diff); + if (diff & 1) + { + // Encode the new thread ID + if(iIsaSample) + { + iLastThread = tid; + w = EncodeUint(w,tid); + + if(!this->IsaTaskKnown(isaTask)) + { + w = EncodeIsaTask(w,iLastThread); + } + //LOGSTRING2("Sample total length: %d",w-tempBuf); + TInt length = w-tempBuf; + // encoded isa task, return here + return length; + } + + iLastThread = tid; + w = EncodeUint(w, tid); + + if ((TAG(t) & 0xfffffffc) != iStartTime) + { + + TAG(t) = ((TAG(t) & 0x3) | iStartTime); + // The thread is 'unknown' to this sample, so encode the thread name + w = EncodeThread(w, t); + } + } + } + LOGSTRING2("Sample total length: %d",w-tempBuf); + TInt length = w-tempBuf; + + return length; +} +