diff -r d27dfa8884ad -r da2cedce4920 piprofiler/piprofiler_plat/inc/ProfilerGenericClassesKrn.inl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/piprofiler/piprofiler_plat/inc/ProfilerGenericClassesKrn.inl Tue May 25 14:22:58 2010 +0300 @@ -0,0 +1,530 @@ +/* +* 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 + + +/* + * + * Class CProfilerSamplerBase implementation + * + */ + +inline DProfilerSamplerBase::DProfilerSamplerBase() + { + + } + +inline DProfilerSamplerBase::~DProfilerSamplerBase() + { + + } + +/* + * + * Class CProfilerSampleBuffer implementation + * + */ + +inline DProfilerSampleBuffer::DProfilerSampleBuffer(TUint8* aBuffer, + TUint8* aDblBuffer, + TUint32 aBufferSize ) + { + LOGSTRING3("CProfilerSampleBuffer::CProfilerSampleBuffer AtFirst: b:0x%x db:0x%x",aBuffer,aDblBuffer); + + // make sure the alignment is right + if((((TUint32)aBuffer) %4) != 0) + aBuffer += (4-(((TUint32)aBuffer)%4)); + if((((TUint32)aDblBuffer) %4) != 0) + aDblBuffer += (4-(((TUint32)aDblBuffer)%4)); + + LOGSTRING3("CProfilerSampleBuffer::CProfilerSampleBuffer b:0x%x db:0x%x",aBuffer,aDblBuffer); + + iBufStruct = (TProfilerSampleBufStruct*)aBuffer; + iDblBufStruct = (TProfilerSampleBufStruct*)aDblBuffer; + + LOGSTRING3("CProfilerSampleBuffer::CProfilerSampleBuffer bufStruct rem:0x%x dbuStruct rem:0x%x", + &iBufStruct->iSampleRemainder,&iDblBufStruct->iSampleRemainder); + + iBufferDataSize = aBufferSize-4; + iBufferRealSize = aBufferSize; + + ClearBuffer(); + } + +inline DProfilerSampleBuffer::~DProfilerSampleBuffer() + { + + } + +inline TInt DProfilerSampleBuffer::AddSample(TUint8* aSample, TUint32 aLength) + { + TUint32 bytesTotal; + + // check whether the buffer status is + switch (iBufferStatus) + { + case DProfilerSampleBuffer::BufferOk: + // add the data normally to the buffer + bytesTotal = iBytesWritten+aLength; + + if(bytesTotal < iBufferDataSize) + { + memcpy((&(iBufStruct->iDataStart))+iBytesWritten,aSample,aLength); + iBytesWritten+=aLength; + return 0; + } + else + { + + // the sample does not fit to the buffer + // first copy as much data as we can fit to the first buffer + TUint32 fitsToBuffer = iBufferDataSize-iBytesWritten; + TUint32 remaining = aLength-fitsToBuffer; + + memcpy((&(iBufStruct->iDataStart))+iBytesWritten,aSample,fitsToBuffer); + iBytesWritten = iBufferDataSize; + + // ->switch to the double buffer + iBufferStatus = DProfilerSampleBuffer::BufferCopyAsap; + + TProfilerSampleBufStruct* tmpPtr = iBufStruct; + iBufStruct = iDblBufStruct; + iDblBufStruct = tmpPtr; + + iDblBytesWritten = iBytesWritten; + + // and this is the remainder of a sample + // that will be copied to the new buffer + // just in a while + iBufStruct->iSampleRemainder = remaining; + + // now that the buffers have been switched + // add the rest of the sample to the buffer + aSample+=fitsToBuffer; + + // there should be room - in case the single sample + // is smaller than the whole buffer! so we don't + // bother to check + + memcpy((&(iBufStruct->iDataStart)),aSample,remaining); + iBytesWritten = remaining; + return 0; + } + + case DProfilerSampleBuffer::BufferCopyAsap: + + // no difference to the BufferOk case + // unless the double buffer gets filled + // before the data has been copied + // add the data normally to the buffer + bytesTotal = iBytesWritten+aLength; + + if(bytesTotal < iBufferDataSize) + { + memcpy((&(iBufStruct->iDataStart))+iBytesWritten,aSample,aLength); + iBytesWritten+=aLength; + return 0; + } + else + { + // the double buffer is now also full - there is no + // place to put the data -> we have to waste it! + // this is an indication of a too small buffer size + iBufferStatus = DProfilerSampleBuffer::BufferFull; + LOGSTRING("DProfilerSampleBuffer::AddSample - double buffer full1!!"); + return -1; + } + + case DProfilerSampleBuffer::BufferBeingCopied: + + // no difference to the BufferCopyAsap case + bytesTotal = iBytesWritten+aLength; + + if(bytesTotal < iBufferDataSize) + { + memcpy((&(iBufStruct->iDataStart))+iBytesWritten,aSample,aLength); + iBytesWritten+=aLength; + return 0; + } + else + { + // the double buffer is now also full - there is no + // place to put the data -> we have to waste it! + // this is an indication of a too small buffer size + LOGSTRING("DProfilerSampleBuffer::AddSample - double buffer full2!!"); + + // don't change the state to CProfilerSampleBuffer::BufferFull, since it is + // already being copied + return -1; + } + + case DProfilerSampleBuffer::BufferFull: + // the buffer is still full, there is noting we can do + // about it -> return + LOGSTRING("DProfilerSampleBuffer::AddSample - double buffer full3!!"); + return -1; + + default: + LOGSTRING("DProfilerSampleBuffer::AddSample - wrong switch!!"); + return -1; + } + } + +inline void DProfilerSampleBuffer::EndSampling() + { + LOGSTRING("DProfilerSampleBuffer::EndSampling"); + // this will switch to the dbl buffer even though + // the buffer is not full, so that data can be copied + + // during this operation, no other buffer + // operations are allowed + + // ensure that the normal buffer is in use and that the + // buffer is in normal state ( this procedure is performed only once ) + if(iBufferStatus == DProfilerSampleBuffer::BufferOk) + { + // ->switch to the double buffer + LOGSTRING("DProfilerSampleBuffer::EndSampling - switching to double buffer"); + iBufferStatus = DProfilerSampleBuffer::BufferCopyAsap; + + TProfilerSampleBufStruct* tmpPtr = iBufStruct; + iBufStruct = iDblBufStruct; + iDblBufStruct = tmpPtr; + + iDblBytesWritten = iBytesWritten; + + // there is no new sample so the remainder is + // zero, (this shouldn't be used anyway) + iBufStruct->iSampleRemainder = 0; + } + } + +inline TUint32 DProfilerSampleBuffer::GetBufferStatus() + { + return iBufferStatus; + } + +inline void DProfilerSampleBuffer::ClearBuffer() + { + LOGSTRING2("CProfilerSampleBuffer::ClearBuffer - %d",iBufferDataSize); + + // the buffers are of same size + TUint8* ptr1 = (TUint8*)&(iBufStruct->iDataStart); + TUint8* ptr2 = (TUint8*)&(iDblBufStruct->iDataStart); + + for(TUint32 i=0;iiSampleRemainder = 0; + iDblBufStruct->iSampleRemainder = 0; + + // written the dblBufStruct + iBytesWritten = 0; + iDblBytesWritten = 0; + iDblBytesRead = 0; + + iBufferStatus = DProfilerSampleBuffer::BufferOk; + } + +inline void DProfilerSampleBuffer::DataCopied() + { + iDblBytesRead = 0; + iDblBytesWritten = 0; + iBufferStatus = DProfilerSampleBuffer::BufferOk; + } + +/* + * + * Class DProfilerSampleStream implementation + * + */ + +inline DProfilerSampleStream::DProfilerSampleStream() + { + LOGSTRING("DProfilerSampleStream::DProfilerSampleStream"); + + iCurrentBuffer = 0; + iPendingRequest = 0; + iAddingSamples = 0; + iClient = 0; + } + +inline DProfilerSampleStream::~DProfilerSampleStream() + { + LOGSTRING("DProfilerSampleStream::~DProfilerSampleStream"); + } + +inline void DProfilerSampleStream::InsertCurrentClient(DThread* aClient) + { + iClient = aClient; + LOGSTRING2("DProfilerSampleStream::InsertCurrentClient - iClient is 0x%x",iClient); + } + + +inline void DProfilerSampleStream::AddSampleBuffer(TBapBuf* aBuffer,TRequestStatus* aStatus) + { + if(iCurrentBuffer != 0 || iPendingRequest != 0) + { + LOGSTRING("DProfilerSampleStream::AddSampleBuffer - ERROR 1"); + return; + } + + LOGSTRING3("DProfilerSampleStream::AddSampleBuffer - OK 0x%x,0x%x",aBuffer,aStatus); + iCurrentBuffer = aBuffer; + iPendingRequest = aStatus; + + LOGSTRING2("DProfilerSampleStream::AddSampleBuffer - Current Client is 0x%x",iClient); + } + + +inline void DProfilerSampleStream::ReleaseIfPending() + { + LOGSTRING("DProfilerSampleStream::ReleaseIfPending - entry"); + + if(iCurrentBuffer != 0 && iPendingRequest != 0 && iClient != 0) + { + LOGSTRING("DProfilerSampleStream::ReleaseIfPending - release buffer"); + + LOGSTRING2("DProfilerSampleStream::AddSamples - completing request 0x%x",iPendingRequest); + Kern::RequestComplete(iClient,iPendingRequest,KErrNone); + + iPendingRequest = 0; + iCurrentBuffer = 0; + } + + LOGSTRING("DProfilerSampleStream::ReleaseIfPending - exit"); + } + +inline void DProfilerSampleStream::AddSamples(DProfilerSampleBuffer& aBuffer, TInt aSamplerId) + { + LOGSTRING3("DProfilerSampleStream::AddSamples - entry ID: %d, currentbuffer: 0x%x", aSamplerId,iCurrentBuffer); + if(iCurrentBuffer != 0) + { + // the following will perform simple mutual exclusion + iAddingSamples++; + if(iAddingSamples > 1) + { + // there is someone else adding samples to the buffer + LOGSTRING("DProfilerSampleStream::AddSamples - mutex in use"); + iAddingSamples--; + return; + } + + LOGSTRING("DProfilerSampleStream::AddSamples - reading TBapBuf"); + + // use a copy of the client TBapBuf structure during processing + TBapBuf realBuf; + TPtr8 ptr((TUint8*)&realBuf,(TInt)sizeof(TBapBuf)); + + Kern::ThreadRawRead(iClient,(TAny*)(iCurrentBuffer),(TAny*)&realBuf,sizeof(TBapBuf)); + + ptr.SetLength(sizeof(TBapBuf)); + + LOGSTRING4("DProfilerSampleStream::AddSamples - read %d bytes from 0x%x of thread 0x%x",ptr.Size(),iCurrentBuffer,iClient); + + LOGSTRING5("DProfilerSampleStream::AddSamples - current buffer 0x%x -> b:0x%x s:%d d:%d", + &realBuf, + realBuf.iBuffer, + realBuf.iBufferSize, + realBuf.iDataSize); + + // get the address of the source buffer data + TUint8* src = (TUint8*)&(aBuffer.iDblBufStruct->iDataStart); + src += aBuffer.iDblBytesRead; + + // the amount of data to copy is the 4 header bytes + + // the remaining data in the buffer + TInt amount = aBuffer.iDblBytesWritten-aBuffer.iDblBytesRead; + + TUint8* dst = realBuf.iBuffer; + + LOGSTRING4("DProfilerSampleStream::AddSamples - s:0x%x d:0x%x a:%d",src,dst,amount); + + if(realBuf.iDataSize == 0) + { + LOGSTRING("DProfilerSampleStream::AddSamples - case 1"); + + // the buffer is empty + if(realBuf.iBufferSize >= (amount+4)) + { + LOGSTRING("DProfilerSampleStream::AddSamples - case 1.1"); + + // the source buffer is smaller or of equal size than the amount of output data + PerformCopy((TUint8)aSamplerId,src,realBuf.iBufDes,0,amount); + realBuf.iDataSize += amount+4; + // the rest of the source buffer was copied at once, so signal the buffer + aBuffer.DataCopied(); + } + else + { + LOGSTRING("DProfilerSampleStream::AddSamples - case 1.2"); + + // only a part of the source buffer will fit to the client side buffer + amount = realBuf.iBufferSize-4; + PerformCopy((TUint8)aSamplerId,src,realBuf.iBufDes,0,amount); + realBuf.iDataSize += amount+4; + // add the amount of bytes read to the source buffer + aBuffer.iDblBytesRead+=amount; + } + } + else + { + LOGSTRING("DProfilerSampleStream::AddSamples - case 2"); + + // there is data in the client buffer + dst += realBuf.iDataSize; + TInt remainingSpace = realBuf.iBufferSize-realBuf.iDataSize; + + if( remainingSpace >= (amount+4) ) + { + LOGSTRING("DProfilerSampleStream::AddSamples - case 2.1"); + + // the source buffer is smaller or of equal size than the amount of output data + PerformCopy((TUint8)aSamplerId,src,realBuf.iBufDes,realBuf.iDataSize,amount); + realBuf.iDataSize += (amount+4); + // the rest of the source buffer was copied at once, so signal the buffer + aBuffer.DataCopied(); + } + else + { + LOGSTRING("DProfilerSampleStream::AddSamples - case 2.2"); + + // only a part of the source buffer will fit to the client side buffer + if(remainingSpace >= 12) + { + LOGSTRING("DProfilerSampleStream::AddSamples - case 2.3"); + + amount = remainingSpace-4; + // there are at least 8 bytes left for data, write it + PerformCopy((TUint8)aSamplerId,src,realBuf.iBufDes,realBuf.iDataSize,amount); + realBuf.iDataSize += (amount+4); + // add the amount of bytes read to the source buffer + aBuffer.iDblBytesRead+=amount; + } + } + } + + // copy the data in the modified TBapBuf structure back to the client + LOGSTRING("DProfilerSampleStream::AddSamples - writing TBapBuf"); + + Kern::ThreadDesWrite(iClient,(TAny*)(realBuf.iDes),ptr,0,KChunkShiftBy0,iClient); + + // if the client side buffer is full or nearly full, signal the client + LOGSTRING("DProfilerSampleStream::AddSamples - data copied"); + + if(realBuf.iBufferSize-realBuf.iDataSize < 12) + { + LOGSTRING("DProfilerSampleStream::AddSamples - release buffer"); + + LOGSTRING2("DProfilerSampleStream::AddSamples - completing request 0x%x",iPendingRequest); + + Kern::RequestComplete(iClient,iPendingRequest,KErrNone); + + iPendingRequest = 0; + iCurrentBuffer = 0; + //iClient = 0; + } + + // free the lock + iAddingSamples--; + } + LOGSTRING("DProfilerSampleStream::AddSamples - exit"); + } + + + +inline TInt DProfilerSampleStream::EndSampling(DProfilerSampleBuffer& aBuffer,TInt aSamplerId) + { + LOGSTRING2("DProfilerSampleStream::EndSampling, sampler ID: %d",aSamplerId); + + // switch the buffer to double buffer + // even though it would not be full yet + // the switch is done only once / end sampling procedure + // (Only with BufferOk status) + aBuffer.EndSampling(); + + LOGSTRING2("DProfilerSampleStream::EndSampling, iClient: 0x%x",iClient); + + if(aBuffer.iBufferStatus != DProfilerSampleBuffer::BufferDataEnd) + { + // add these final samples to the client buffer + AddSamples(aBuffer,aSamplerId); + + // if all data was copied to the buffer, the buffer status is now BufferOk + + if(aBuffer.iBufferStatus != DProfilerSampleBuffer::BufferOk) + { + LOGSTRING("DProfilerSampleStream::EndSampling - more data to copy"); + // there is still more data to copy, the pending request should have been + // completed in AddSamples(), because the client buffer got filled + return 1; + } + else + { + // buffer status was changed to BufferOk in AddSamples() - + // this means all data from it could be copied + // now we have to change the status of the buffer to BufferDataEnd, so + // we know that the particular buffer has no more data to copy + LOGSTRING("DProfilerSampleStream::EndSampling - switch to BufferDataEnd"); + aBuffer.iBufferStatus = DProfilerSampleBuffer::BufferDataEnd; + } + } + + // the buffer was completely emptied to the client buffer, or there was no + // data to copy to the client side + LOGSTRING("DProfilerSampleStream::EndSampling - no more data to copy"); + + return 0; + } + +inline void DProfilerSampleStream::PerformCopy(TUint8 aSamplerId,TUint8* aSrc,TPtr8* aDst,TInt aOffset,TInt aAmount) + { + LOGSTRING2("DProfilerSampleStream::PerformCopy for sampler ID: %d",aSamplerId); + LOGSTRING5("DProfilerSampleStream::PerformCopy - 0x%x -> 0x%x - %d - offset: %d",aSrc, aDst, aAmount, aOffset); + TUint32 header; + header = aAmount & 0x00ffffff; + header += (aSamplerId << 24); + TPtr8 ptr((TUint8*)&header,4); + ptr.SetLength(4); + + LOGSTRING2("DProfilerSampleStream::PerformCopy - start header copy HDR = 0x%x",header); + + // write the header + Kern::ThreadDesWrite(iClient,(TAny*)aDst,ptr,aOffset,KChunkShiftBy0); + + LOGSTRING2("DProfilerSampleStream::PerformCopy - copied header %d bytes",ptr.Size()); + aOffset+=4; + + LOGSTRING("DProfilerSampleStream::PerformCopy - start copy"); + // write the data + ptr.Set(aSrc,aAmount,aAmount); + ptr.SetLength(aAmount); + + Kern::ThreadDesWrite(iClient,(TAny*)aDst,ptr,aOffset,KChunkShiftBy0); + + + LOGSTRING2("DProfilerSampleStream::PerformCopy - copied data %d bytes",ptr.Size()); + + }