Implemented RObjectIx-based memoryaccess APIs.
Upshot is that objinfo now works again on platforms that define FSHELL_NO_DOBJECTIX_SUPPORT.
// memsamplerdd.cpp
//
// Copyright (c) 2008 - 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "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:
// Accenture - Initial contribution
//
#include <fshell/extrabtrace.h>
#include <platform.h>
#include <kern_priv.h>
#include "memsamplerdd.h"
#include <fshell/common.mmh>
const TInt KMinRate = 10;
const TInt KMaxRate = 10000;
const TInt KMajorVersionNumber = 1;
const TInt KMinorVersionNumber = 0;
const TInt KBuildVersionNumber = 0;
const TInt KArrayGranularity = 32;
const TInt KDfcThreadPriority = 26;
_LIT(KDfcThreadName, "MemSamplerDD");
class DDeviceMemSampler : public DLogicalDevice
{
public:
DDeviceMemSampler();
virtual TInt Install();
virtual void GetCaps(TDes8& aDes) const;
virtual TInt Create(DLogicalChannelBase*& aChannel);
};
class TChunkInfo
{
public:
TChunkInfo(DChunk& aChunk);
TBool operator==(const TChunkInfo& aChunkInfo);
public:
DChunk* iAddress;
TInt iSize;
TInt iHighWaterMark;
TBool iSeen;
};
TChunkInfo::TChunkInfo(DChunk& aChunk)
: iAddress(&aChunk), iSize(aChunk.Size()), iHighWaterMark(aChunk.Size()), iSeen(ETrue)
{
}
TBool TChunkInfo::operator==(const TChunkInfo& aChunkInfo)
{
return (iSize == aChunkInfo.iSize);
}
class DMemSamplerChannel : public DLogicalChannel
{
public:
DMemSamplerChannel();
~DMemSamplerChannel();
protected:
virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
virtual void HandleMsg(TMessageBase* aMsg);
private:
TInt StartSampling(TInt aRate);
TInt StopSampling();
TInt ResetSampling();
TInt ReadChunks();
void TraceNewChunk(const TChunkInfo& aChunkInfo) const;
void TraceChangedChunk(const TChunkInfo& aChunkInfo) const;
void TraceDeletedChunk(const TChunkInfo& aChunkInfo) const;
void TraceNewSample() const;
#if FSHELL_PLATFORM_SYMTB >= 92
inline TBool Running()
{return iTimer.IsPending();}
#else
inline TBool Running()
{return iTimer.iState!=NTimer::EIdle;}
#endif
private:
static void Sample(TAny*);
static void DoSample(TAny*);
static void ExitDfcThread(TAny*);
private:
RArray<TChunkInfo> iChunkInfo;
NTimer iTimer;
TInt iPeriod;
TInt iPeriodNumber;
TDfcQue iPrivateDfcQ;
TDfc iDoSampleDfc;
TDfc iExitDfc;
DThread* iClient;
mutable TBool iNewSampleTraced;
};
DECLARE_STANDARD_LDD()
{
return new DDeviceMemSampler;
}
DDeviceMemSampler::DDeviceMemSampler()
{
iVersion=TVersion(KMajorVersionNumber, KMinorVersionNumber, KBuildVersionNumber);
}
TInt DDeviceMemSampler::Install()
{
TInt r = SetName(&KMemSamplerName);
return r;
}
void DDeviceMemSampler::GetCaps(TDes8&) const
{
}
TInt DDeviceMemSampler::Create(DLogicalChannelBase*& aChannel)
{
aChannel = new DMemSamplerChannel;
return aChannel ? KErrNone : KErrNoMemory;
}
DMemSamplerChannel::DMemSamplerChannel()
: iChunkInfo(KArrayGranularity, _FOFF(TChunkInfo, iAddress)), iTimer(Sample, this), iPeriodNumber(-1), iDoSampleDfc(DoSample, this, 1), iExitDfc(ExitDfcThread, this, 0), iNewSampleTraced(EFalse)
{
}
DMemSamplerChannel::~DMemSamplerChannel()
{
Kern::SafeClose((DObject*&)iClient, NULL);
iExitDfc.Enque();
}
void DMemSamplerChannel::ExitDfcThread(TAny*)
{
Kern::Exit(KErrNone);
}
TInt DMemSamplerChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer)
{
if (!Kern::QueryVersionSupported(TVersion(1,0,0),aVer))
{
return KErrNotSupported;
}
iClient=&Kern::CurrentThread();
iClient->Open();
TInt err = Kern::DfcQInit(&iPrivateDfcQ, KDfcThreadPriority, &KDfcThreadName);
if (err == KErrNone)
{
SetDfcQ(&iPrivateDfcQ);
iDoSampleDfc.SetDfcQ(&iPrivateDfcQ);
iExitDfc.SetDfcQ(&iPrivateDfcQ);
iMsgQ.Receive();
}
return err;
}
TInt DMemSamplerChannel::StartSampling(TInt aRate)
{
DEBUG_MEMSAMPLER(Kern::Printf("START");)
ReadChunks();
aRate = Min(KMaxRate, Max(KMinRate, aRate));
iPeriod = NKern::TimerTicks(aRate);
if (!Running())
{
iTimer.OneShot(iPeriod, EFalse);
}
DEBUG_MEMSAMPLER(Kern::Printf("START end");)
return KErrNone;
}
TInt DMemSamplerChannel::StopSampling()
{
DEBUG_MEMSAMPLER(Kern::Printf("STOP");)
if (Running())
{
iTimer.Cancel();
}
DEBUG_MEMSAMPLER(Kern::Printf("STOP end");)
return KErrNone;
}
TInt DMemSamplerChannel::ResetSampling()
{
DEBUG_MEMSAMPLER(Kern::Printf("RESET");)
iChunkInfo.Reset();
DEBUG_MEMSAMPLER(Kern::Printf("RESET end");)
return KErrNone;
}
TInt DMemSamplerChannel::ReadChunks()
{
++iPeriodNumber;
iNewSampleTraced = EFalse;
for (TInt i = (iChunkInfo.Count() - 1); i >= 0; --i)
{
iChunkInfo[i].iSeen = EFalse;
}
DObjectCon* const * containers = Kern::Containers();
DObjectCon& container = *containers[EChunk];
container.Wait();
for (TInt i = (container.Count() - 1); i >= 0; --i)
{
TChunkInfo thisChunk(*(DChunk*)container[i]);
TInt pos;
TInt err = iChunkInfo.FindInUnsignedKeyOrder(thisChunk, pos);
if (err == KErrNotFound)
{
if (pos < iChunkInfo.Count())
{
iChunkInfo.Insert(thisChunk, pos);
}
else
{
TInt err = iChunkInfo.Append(thisChunk);
if (err)
{
container.Signal();
return err;
}
}
TraceNewChunk(thisChunk);
}
else
{
if (thisChunk == iChunkInfo[pos])
{
// Chunk size hasn't changed - ignore.
iChunkInfo[pos].iSeen = ETrue;
}
else
{
TChunkInfo& c = iChunkInfo[pos];
if (thisChunk.iSize > c.iHighWaterMark)
{
c.iHighWaterMark = thisChunk.iSize;
}
c.iSize = thisChunk.iSize;
c.iSeen = ETrue;
TraceChangedChunk(c);
}
}
}
container.Signal();
for (TInt i = (iChunkInfo.Count() - 1); i >= 0; --i)
{
const TChunkInfo& chunkInfo = iChunkInfo[i];
if (!chunkInfo.iSeen)
{
TraceDeletedChunk(chunkInfo);
iChunkInfo.Remove(i);
}
}
return KErrNone;
}
void DMemSamplerChannel::TraceNewChunk(const TChunkInfo& aChunkInfo) const
{
TraceNewSample();
TFullName nameBuf;
aChunkInfo.iAddress->FullName(nameBuf);
BTraceN(RMemSampler::EBtraceCategory, RMemSampler::ENewChunk, aChunkInfo.iAddress, aChunkInfo.iAddress->MaxSize(), nameBuf.Ptr(), nameBuf.Size());
TraceChangedChunk(aChunkInfo);
}
void DMemSamplerChannel::TraceChangedChunk(const TChunkInfo& aChunkInfo) const
{
TraceNewSample();
BTraceContext12(RMemSampler::EBtraceCategory, RMemSampler::EChangedChunk, aChunkInfo.iAddress, aChunkInfo.iSize, aChunkInfo.iHighWaterMark);
}
void DMemSamplerChannel::TraceDeletedChunk(const TChunkInfo& aChunkInfo) const
{
TraceNewSample();
BTraceContext4(RMemSampler::EBtraceCategory, RMemSampler::EDeletedChunk, aChunkInfo.iAddress);
}
void DMemSamplerChannel::TraceNewSample() const
{
if (!iNewSampleTraced)
{
iNewSampleTraced = ETrue;
BTraceContext8(RMemSampler::EBtraceCategory, RMemSampler::ENewSample, iPeriod, iPeriodNumber);
}
}
void DMemSamplerChannel::HandleMsg(TMessageBase* aMsg)
{
TInt r=KErrNone;
TThreadMessage& m=*(TThreadMessage*)aMsg;
TInt id=m.iValue;
if (id==(TInt)ECloseMsg)
{
DEBUG_MEMSAMPLER(Kern::Printf("CLOSE");)
iTimer.Cancel();
m.Complete(KErrNone,EFalse);
iMsgQ.CompleteAll(KErrServerTerminated);
DEBUG_MEMSAMPLER(Kern::Printf("CLOSE end");)
return;
}
else
{
switch(id)
{
case RMemSampler::EControlStartProfile:
r = StartSampling(m.Int0());
break;
case RMemSampler::EControlStopProfile:
r = StopSampling();
break;
case RMemSampler::EControlResetProfile:
r = ResetSampling();
break;
default:
r = KErrNotSupported;
break;
}
}
m.Complete(r,ETrue);
}
void DMemSamplerChannel::Sample(TAny* aPtr)
{
DMemSamplerChannel& d = *(DMemSamplerChannel*)aPtr;
d.iTimer.Again(d.iPeriod);
d.iDoSampleDfc.Add();
}
void DMemSamplerChannel::DoSample(TAny* aPtr)
{
DMemSamplerChannel& d = *(DMemSamplerChannel*)aPtr;
d.ReadChunks();
}