sysanadatacapture/piprofiler/piprofiler/plugins/GeneralsPlugin/src/PriSamplerImpl.cpp
author Matti Laitinen <matti.t.laitinen@nokia.com>
Thu, 11 Feb 2010 15:52:57 +0200
changeset 1 3ff3fecb12fe
permissions -rw-r--r--
Add initial version of PI Profiler under EPL

/*
* 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 <piprofiler/ProfilerVersion.h>
#include <piprofiler/ProfilerTraces.h>

#include <kern_priv.h>
#include <plat_priv.h>

#include "PriSamplerImpl.h"

#if !defined(__NKERN_H__)
#include <nkern.h>
#endif 

#define TAG(obj) (*(TUint32*)&(obj->iAsyncDeleteNext))
#define PROFILER_THREAD_MARK		((TUint32)0x00000002)


PriSamplerImpl::PriSamplerImpl() :
	sampleDescriptor(&(this->sample[1]),0,256)
    {
	LOGTEXT("PriSamplerImpl::PriSamplerImpl() - konstruktori");

	iCountti = 50;	// sample threads 16 cycles before actual MEM and PRI sample time...
	iNewThreadCount = 0;
	iThreadCount = 0;
	iProcessing = ENothingToProcess;
	
	for(TInt i=0;i<KProfilerMaxThreadAmount;i++)
	    {
		this->threadsToSample[i] = 0;
		this->threadNamesToReport[i] = 0;
        }

    }

PriSamplerImpl::~PriSamplerImpl()
    {
	
    }

TInt PriSamplerImpl::CreateFirstSample()
    {
	LOGTEXT("PriSamplerImpl::CreateFirstSample - entry");
	
	this->sampleDescriptor.Zero();
	this->sampleDescriptor.Append(_L8("Bappea_V"));
	this->sampleDescriptor.Append(PROFILER_PRI_SAMPLER_VERSION);
	this->sampleDescriptor.Append(_L8("_PRI"));

	sample[0] = this->sampleDescriptor.Size();

	LOGTEXT("PriSamplerImpl::CreateFirstSample - exit");

	return (TInt)(sample[0]+1);
    }

TBool PriSamplerImpl::SampleNeeded()
    {
	iCountti++;
	if(iCountti % (iPriSamplingPeriod) == 0) 
	    {
		LOGTEXT("PriSamplerImpl::SampleNeeded - true");
		return true;
        }
	else 
	    {
		return false;
        }
    }


TInt PriSamplerImpl::SampleImpl()
    {
	/*
	 *
	 *	EKA-2 implementation of PRI trace
	 *
	 */
	if(this->iProcessing == ENothingToProcess)
	    {
	    if((iCountti % iPriSamplingPeriod) != 0 ) return 0;
	    
        LOGTEXT("Processing threads...");

        DObjectCon& threads = *Kern::Containers()[EThread];

        // PRI trace variables
        this->iThreadCount = 0; 
        this->iNewThreadCount = 0;
        TInt totalThreadCount = threads.Count();

        for(TInt i=0;i<totalThreadCount;i++)
            {
            DThread* t = (DThread*)(threads)[i];
            LOGSTRING3("Processing thread %d, tag: 0x%x",i,TAG(t));

            if( (TAG(t) & PROFILER_THREAD_MARK) == 0)
                {
                LOGSTRING2("Marking thread %d",i);
                // this thread's chunk has not been reported yet
                this->threadNamesToReport[iNewThreadCount] = t;
                iNewThreadCount++;
                // tag the thread
                TAG(t) |= PROFILER_THREAD_MARK;
                LOGSTRING2("New Thread %d",i);
                }
            else
                {
                LOGSTRING3("Thread %d marked already - 0x%x",i,TAG(t));
                }

            // the thread has been tagged, add heap chunks to the list
            this->threadsToSample[this->iThreadCount] = t;
            this->iThreadCount++;
            LOGSTRING2("Added thread %d to threads to sample",i);
            }

        if(this->iThreadCount > 0 || this->iNewThreadCount > 0)
            {
            this->iProcessing = EStartingToProcess;
            
            // process the first sample
            TInt length = this->ProcessChunks();
            
            if(length == 0)
                {
                this->iProcessing = ENothingToProcess;
                }
        
            return length;
            }
        else
            {
            // there were no threads, should not take place
            LOGTEXT("PriSamplerImpl::SampleImpl - Error, no threads"); 
            return 0;
            }
	    }
	else
	    {
		TInt length = this->ProcessChunks();
		if(length == 0) 
		    {
			this->iProcessing = ENothingToProcess;
		    }
		return length;
	    }
    }

inline TInt PriSamplerImpl::ProcessChunks()
    {
	/*
	 *
	 *	EKA-2 implementation of PRI trace
	 *
	 */

	if(iNewThreadCount > 0)
	    {
		if(this->iProcessing == EStartingToProcess)
		    {
			// this is the first sample, encode a code for names
			this->iProcessing = EProcessingNames;
			return EncodeNameCode();
            }

		// there are new thread names to report
		iNewThreadCount--;
		DThread* t = this->threadNamesToReport[iNewThreadCount];
		return EncodeChunkName(*t);
        }
	else if(iThreadCount > 0)
	    {
		if(this->iProcessing == EProcessingNames || this->iProcessing == EStartingToProcess)
		    {
			// this is the first data sample, encode a code for data
			this->iProcessing = EProcessingData;
			return EncodeDataCode();
            }

		// there are no new chunks to report
		// thus generate the real report
		iThreadCount--;
		DThread* t = this->threadsToSample[iThreadCount];
		LOGSTRING2("PriSamplerImpl::ProcessChunks - starting to process thread 0x%x",t);
		return EncodeChunkData(*t);
        }
	else
	    {
		// everything is processed
		return 0;
        }
    }

inline TInt PriSamplerImpl::EncodeNameCode()
    {
	sample[0] = 1;
	sample[1] = 0xbb;	// pri trace name code
	return 2;
    }

inline TInt PriSamplerImpl::EncodeDataCode()
    {
	sample[0] = 1;
	sample[1] = 0xee;	// pri trace data code
	return 2;
    }


inline TInt PriSamplerImpl::EncodeChunkName(DThread& t)
    {		
	// the size of the following name is in the first byte
	TUint8* size = &sample[0];
	*size = 0;
	this->sampleDescriptor.Zero();
	
	t.TraceAppendFullName(this->sampleDescriptor,false);
	*size += this->sampleDescriptor.Size();
	
	// copy the 4 bytes from the thread id field
	this->sampleDescriptor.Append((TUint8*)&(t.iId),sizeof(TUint));
	*size += sizeof(TUint);

	// the size is the descriptor length + the size field
	LOGSTRING2("Name size - %d",*size);
	return ((TInt)(*size))+1;
    }


inline TInt PriSamplerImpl::EncodeChunkData(DThread& t)
    {
	LOGTEXT("PriSamplerImpl::EncodeChunkData - entry");
	LOGSTRING2("PriSamplerImpl::EncodeChunkData - processing thread 0x%x ",&t);
		
	// the size of the following name is in the first byte
	TUint8* size = &sample[0];
	*size = 0;
	this->sampleDescriptor.Zero();

	LOGTEXT("PriSamplerImpl::EncodeChunkData - cleared");

    // append the thread id
    this->sampleDescriptor.Append((TUint8*)&(t.iId),sizeof(TUint));
    *size += sizeof(TUint);
    
//    NKern::LockSystem();
//    TInt priority(-1);
//    if(&t && t.Open()== KErrNone)
//        {
//       priority = t.iDefaultPriority;
//        }
//    NKern::UnlockSystem();
    
    // append the priority of the nanokernel fast semaphore
//    this->sampleDescriptor.Append((TUint8*)&priority,sizeof(TUint8));
    // append the priority of the nanokernel fast semaphore
    this->sampleDescriptor.Append((TUint8*)&(t.iNThread.iPriority),sizeof(TUint8));
    // add space because EKA-1 implementation needs it
    this->sampleDescriptor.Append((TUint8)0x0);
    *size += 2*sizeof(TUint8);

    LOGTEXT("PriSamplerImpl::EncodeChunkData - appended priority");
        

    LOGSTRING2("Data size - %d",*size);
    return ((TInt)(*size))+1;	
    }


void PriSamplerImpl::Reset()
    {
	/*
	 *
	 *	EKA-2 implementation of PRI trace
	 *
	 */

	LOGTEXT("PriSamplerImpl::Reset");
	iCountti = 50;	// sample threads 16 cycles before actual MEM and PRI sample time...
	this->iThreadCount = 0;
	this->iNewThreadCount = 0;
	this->iProcessing = ENothingToProcess;
	this->sampleDescriptor.Zero();


	// clear all thread tags
	DObjectCon* threads = Kern::Containers()[EThread];
	TInt totalThreadCount = threads->Count();
	for(TInt i=0;i<totalThreadCount;i++)
	    {
		DThread* t = (DThread*)(*threads)[i];
		TAG(t) = (TAG(t) & 0xfffffffd);
	    }
    }