os/kernelhwsrv/kerneltest/e32utils/analyse/distribution.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
//
sl@0
    15
sl@0
    16
#include "analyse.h"
sl@0
    17
#include "distribution.h"
sl@0
    18
#include "output.h"
sl@0
    19
sl@0
    20
#ifdef __MSVCDOTNET__
sl@0
    21
#include <ostream>
sl@0
    22
#include <iomanip>
sl@0
    23
#else //!__MSVCDOTNET__
sl@0
    24
#include <ostream.h>
sl@0
    25
#include <iomanip.h>
sl@0
    26
#endif //__MSVCDOTNET__
sl@0
    27
sl@0
    28
#include <algorithm>
sl@0
    29
sl@0
    30
// class Distribution
sl@0
    31
sl@0
    32
namespace {
sl@0
    33
sl@0
    34
int* BucketBox(int aSize)
sl@0
    35
	{
sl@0
    36
	int* buckets = new int[aSize];
sl@0
    37
	memset(buckets, 0, sizeof(int) * aSize);
sl@0
    38
	return buckets;
sl@0
    39
	}
sl@0
    40
sl@0
    41
class BucketTotals
sl@0
    42
	{
sl@0
    43
private:
sl@0
    44
	class Generator
sl@0
    45
		{
sl@0
    46
	public:
sl@0
    47
		inline Generator()
sl@0
    48
			:iValue(0)
sl@0
    49
			{}
sl@0
    50
		inline int operator()()
sl@0
    51
			{return iValue++;}
sl@0
    52
	private:
sl@0
    53
		int iValue;
sl@0
    54
		};
sl@0
    55
	class Sorter
sl@0
    56
		{
sl@0
    57
	public:
sl@0
    58
		inline Sorter(const int* aTotals)
sl@0
    59
			:iTotals(aTotals)
sl@0
    60
			{}
sl@0
    61
		inline bool operator()(int aLhs, int aRhs) const
sl@0
    62
			{return (iTotals[aLhs] > iTotals[aRhs]);}
sl@0
    63
	private:
sl@0
    64
		const int* iTotals;
sl@0
    65
		};
sl@0
    66
public:
sl@0
    67
	BucketTotals(Distribution::Data& aData, int aSize);
sl@0
    68
	~BucketTotals();
sl@0
    69
	void Sort();
sl@0
    70
//
sl@0
    71
	inline int Total() const;
sl@0
    72
	inline int Map(int aBucket) const;
sl@0
    73
	inline int operator[](int aBucket) const;
sl@0
    74
	inline Result Sample(int aSample) const;
sl@0
    75
private:
sl@0
    76
	void Total(Distribution::Data& aData);
sl@0
    77
private:
sl@0
    78
	int iSize;
sl@0
    79
	int* iTotals;
sl@0
    80
	int* iOrdering;
sl@0
    81
	int iTotal;
sl@0
    82
	};
sl@0
    83
sl@0
    84
BucketTotals::BucketTotals(Distribution::Data& aData, int aSize)
sl@0
    85
	:iSize(aSize), iTotals(BucketBox(aSize)), iOrdering(BucketBox(aSize))
sl@0
    86
	{
sl@0
    87
	Total(aData);
sl@0
    88
	std::generate_n(iOrdering, iSize, Generator());
sl@0
    89
	}
sl@0
    90
sl@0
    91
BucketTotals::~BucketTotals()
sl@0
    92
	{
sl@0
    93
	delete [] iTotals;
sl@0
    94
	delete [] iOrdering;
sl@0
    95
	}
sl@0
    96
sl@0
    97
void BucketTotals::Total(Distribution::Data& aData)
sl@0
    98
	{
sl@0
    99
	int total = 0;
sl@0
   100
	for (Distribution::Data::iterator p = aData.begin(), e = aData.end(); p != e; ++p)
sl@0
   101
		{
sl@0
   102
		const int* box = p->iBuckets;
sl@0
   103
		int threadTotal = 0;
sl@0
   104
		for (int j = p->iBucketsLength; --j >=0;)
sl@0
   105
			{
sl@0
   106
			threadTotal += box[j];
sl@0
   107
			iTotals[j] += box[j];
sl@0
   108
			}
sl@0
   109
		p->iTotal = threadTotal;
sl@0
   110
		total += threadTotal;
sl@0
   111
		}
sl@0
   112
	iTotal = total;
sl@0
   113
	}
sl@0
   114
sl@0
   115
void BucketTotals::Sort()
sl@0
   116
	{
sl@0
   117
	std::sort(iOrdering, iOrdering + iSize, Sorter(iTotals));
sl@0
   118
	}
sl@0
   119
sl@0
   120
inline int BucketTotals::Total() const
sl@0
   121
	{return iTotal;}
sl@0
   122
sl@0
   123
inline int BucketTotals::Map(int aBucket) const
sl@0
   124
	{return iOrdering[aBucket];}
sl@0
   125
sl@0
   126
inline int BucketTotals::operator[](int aBucket) const
sl@0
   127
	{return iTotals[iOrdering[aBucket]];}
sl@0
   128
sl@0
   129
inline Result BucketTotals::Sample(int aSample) const
sl@0
   130
	{return Result(aSample, iTotal);}
sl@0
   131
sl@0
   132
};
sl@0
   133
sl@0
   134
inline Distribution::ThreadData::ThreadData(const Thread& aThread, int aSize)
sl@0
   135
	:iThread(&aThread), iBuckets(BucketBox(aSize)), iTotal(0), iBucketsLength(aSize)
sl@0
   136
	{}
sl@0
   137
sl@0
   138
inline Distribution::ThreadData::ThreadData(int aCutoff)
sl@0
   139
	:iTotal(aCutoff)
sl@0
   140
	{}
sl@0
   141
sl@0
   142
inline bool Distribution::ThreadData::operator<(const Distribution::ThreadData& aRhs) const
sl@0
   143
	{return (iTotal > aRhs.iTotal);}
sl@0
   144
sl@0
   145
Distribution::Distribution(CodeSpace& aCodeSpace, double aCutOff)
sl@0
   146
	:iCodeSpace(aCodeSpace), iCutOff(aCutOff)
sl@0
   147
	{
sl@0
   148
	cout << "Profile distribution\n\n";
sl@0
   149
	}
sl@0
   150
sl@0
   151
void Distribution::Sample(unsigned , const Thread& aThread, PC aPc)
sl@0
   152
//
sl@0
   153
// Collect the sample in the bucket as allocated by the code space
sl@0
   154
//
sl@0
   155
	{
sl@0
   156
	if (aThread.iIndex == iData.size())
sl@0
   157
		iData.push_back(ThreadData(aThread,iCodeSpace.Size()));
sl@0
   158
sl@0
   159
	///
sl@0
   160
	int bucket = iCodeSpace.Bucket(aPc);
sl@0
   161
	if (bucket >= iData[aThread.iIndex].iBucketsLength)
sl@0
   162
		{
sl@0
   163
		int* new_buckets = new int[bucket+1];
sl@0
   164
		memset(new_buckets, 0, sizeof(int) * (bucket+1));
sl@0
   165
		memcpy(new_buckets, iData[aThread.iIndex].iBuckets, sizeof(int) * iData[aThread.iIndex].iBucketsLength);
sl@0
   166
		delete [] iData[aThread.iIndex].iBuckets;
sl@0
   167
		iData[aThread.iIndex].iBuckets = new_buckets;
sl@0
   168
		iData[aThread.iIndex].iBucketsLength = bucket+1;
sl@0
   169
		}
sl@0
   170
sl@0
   171
	++iData[aThread.iIndex].iBuckets[bucket];
sl@0
   172
	}
sl@0
   173
sl@0
   174
void Distribution::Complete(unsigned aTotal, unsigned aActive)
sl@0
   175
	{
sl@0
   176
	// accumulate thread and bucket totals
sl@0
   177
	const int nbuckets = iCodeSpace.Size();
sl@0
   178
	BucketTotals totals(iData, nbuckets);
sl@0
   179
	if (iCodeSpace.Ordering() == CodeSpace::ERandom)
sl@0
   180
		totals.Sort();
sl@0
   181
sl@0
   182
	int cutoff = int(iCutOff * totals.Total() * 0.01);
sl@0
   183
	std::sort(iData.begin(), iData.end());
sl@0
   184
	iData.erase(std::upper_bound(iData.begin(), iData.end(), ThreadData(cutoff)), iData.end());
sl@0
   185
//
sl@0
   186
	cout.setf(ios::fixed, ios::floatfield);
sl@0
   187
	cout.precision(2);
sl@0
   188
//
sl@0
   189
	cout << "Samples: " << aTotal << '\n';
sl@0
   190
	cout << " Active: " << aActive << "  (" << double(aActive*100)/aTotal << "%)\n";
sl@0
   191
	cout << "Counted: " << totals.Total() << "  (" << double(totals.Total()*100)/aTotal << "%)\n\n";
sl@0
   192
	cout << setfill(' ');
sl@0
   193
//
sl@0
   194
	Data::iterator p, e;
sl@0
   195
	if (!Analyse::Option(Analyse::ETotalOnly))
sl@0
   196
		{
sl@0
   197
		if (Analyse::Format() != Analyse::EExcel)
sl@0
   198
			{
sl@0
   199
			cout << "ID  Thread name\n";
sl@0
   200
			char id = 'A';
sl@0
   201
			for (p = iData.begin(), e = iData.end(); p != e; ++p)
sl@0
   202
				cout << id++ << "   " << *p->iThread << '\n';
sl@0
   203
			cout << '\n';
sl@0
   204
sl@0
   205
			id = 'A';
sl@0
   206
			for (p = iData.begin(), e = iData.end(); p != e; ++p)
sl@0
   207
				cout << setw(4) << id++ << "    ";
sl@0
   208
			cout << "  total\n\n";
sl@0
   209
sl@0
   210
			for (p = iData.begin(), e = iData.end(); p != e; ++p)
sl@0
   211
				cout << totals.Sample(p->iTotal) << " ";
sl@0
   212
			cout << "  " << totals.Sample(totals.Total()) << "  total\n\n";
sl@0
   213
			}
sl@0
   214
		else
sl@0
   215
			{
sl@0
   216
			cout.precision(5);
sl@0
   217
			for (p = iData.begin(), e = iData.end(); p != e; ++p)
sl@0
   218
				cout << '\t' << *p->iThread;
sl@0
   219
			cout << "\ttotal\n";
sl@0
   220
			}
sl@0
   221
		}
sl@0
   222
sl@0
   223
	if (cutoff == 0 && iCodeSpace.Ordering() != CodeSpace::ELinear)
sl@0
   224
		cutoff = 1;
sl@0
   225
sl@0
   226
	for (int ix = 0; ix< nbuckets; ++ix)
sl@0
   227
		{
sl@0
   228
		int total = totals[ix];
sl@0
   229
		if (total >= cutoff)
sl@0
   230
			{
sl@0
   231
			int jx = totals.Map(ix);
sl@0
   232
			if (jx == CodeSpace::KOtherBucket && Analyse::Option(Analyse::ENoOther))
sl@0
   233
				continue;
sl@0
   234
			if (Analyse::Format() == Analyse::EExcel)
sl@0
   235
				{
sl@0
   236
				cout << iCodeSpace.Name(jx);
sl@0
   237
				if (!Analyse::Option(Analyse::ETotalOnly))
sl@0
   238
					{
sl@0
   239
					for (p = iData.begin(), e = iData.end(); p != e; ++p)
sl@0
   240
						cout << '\t' << totals.Sample(jx>=p->iBucketsLength ? 0 : p->iBuckets[jx]);
sl@0
   241
					}
sl@0
   242
				cout << '\t' << totals.Sample(total) << '\n';
sl@0
   243
				}
sl@0
   244
			else
sl@0
   245
				{
sl@0
   246
				if (!Analyse::Option(Analyse::ETotalOnly))
sl@0
   247
					{
sl@0
   248
					for (p = iData.begin(), e = iData.end(); p != e; ++p)
sl@0
   249
						cout << totals.Sample(jx>=p->iBucketsLength ? 0 : p->iBuckets[jx]) << " ";
sl@0
   250
					cout << "  ";
sl@0
   251
					}
sl@0
   252
				cout << totals.Sample(total) << "  " << iCodeSpace.Name(jx) << '\n';
sl@0
   253
				}
sl@0
   254
			}
sl@0
   255
		}
sl@0
   256
sl@0
   257
	if (!Analyse::Option(Analyse::ETotalOnly))
sl@0
   258
		{
sl@0
   259
		if (Analyse::Format() == Analyse::EExcel)
sl@0
   260
			{
sl@0
   261
			cout << "total";
sl@0
   262
			for (p = iData.begin(), e = iData.end(); p != e; ++p)
sl@0
   263
				cout << '\t' << totals.Sample(p->iTotal);
sl@0
   264
			cout << '\t' << totals.Sample(totals.Total()) << '\n';
sl@0
   265
			}
sl@0
   266
		}
sl@0
   267
	}