More refactoring:
* Moved the BasicThreadProfileResult class, its subclasses and related code into separate files. * Made ThreadImage an abstract base class. Pulled the meaty part into new subclass BasicThreadImage. * Templatized AbstractThreadProfileResult over the ThreadImage type. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27788 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* Copyright 2008, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "BasicThreadProfileResult.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <new>
|
||||
|
||||
#include "Options.h"
|
||||
|
||||
|
||||
struct HitSymbol {
|
||||
int64 hits;
|
||||
Symbol* symbol;
|
||||
|
||||
inline bool operator<(const HitSymbol& other) const
|
||||
{
|
||||
return hits > other.hits;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - BasicThreadImage
|
||||
|
||||
|
||||
BasicThreadImage::BasicThreadImage(Image* image)
|
||||
:
|
||||
ThreadImage(image),
|
||||
fSymbolHits(NULL),
|
||||
fUnknownHits(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BasicThreadImage::~BasicThreadImage()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BasicThreadImage::Init()
|
||||
{
|
||||
int32 symbolCount = fImage->SymbolCount();
|
||||
fSymbolHits = new(std::nothrow) int64[symbolCount];
|
||||
if (fSymbolHits == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
memset(fSymbolHits, 0, 8 * symbolCount);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BasicThreadImage::AddHit(addr_t address)
|
||||
{
|
||||
int32 symbolIndex = fImage->FindSymbol(address);
|
||||
if (symbolIndex >= 0)
|
||||
fSymbolHits[symbolIndex]++;
|
||||
else
|
||||
fUnknownHits++;
|
||||
|
||||
fTotalHits++;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BasicThreadImage::AddSymbolHit(int32 symbolIndex)
|
||||
{
|
||||
fSymbolHits[symbolIndex]++;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BasicThreadImage::AddImageHit()
|
||||
{
|
||||
fTotalHits++;
|
||||
}
|
||||
|
||||
|
||||
const int64*
|
||||
BasicThreadImage::SymbolHits() const
|
||||
{
|
||||
return fSymbolHits;
|
||||
}
|
||||
|
||||
|
||||
int64
|
||||
BasicThreadImage::UnknownHits() const
|
||||
{
|
||||
return fUnknownHits;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - BasicThreadProfileResult
|
||||
|
||||
|
||||
BasicThreadProfileResult::BasicThreadProfileResult()
|
||||
:
|
||||
fTotalTicks(0),
|
||||
fUnkownTicks(0),
|
||||
fDroppedTicks(0),
|
||||
fTotalSampleCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BasicThreadProfileResult::AddDroppedTicks(int32 dropped)
|
||||
{
|
||||
fDroppedTicks += dropped;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BasicThreadProfileResult::PrintResults()
|
||||
{
|
||||
// count images and symbols
|
||||
int32 imageCount = 0;
|
||||
int32 symbolCount = 0;
|
||||
|
||||
ImageList::Iterator it = fOldImages.GetIterator();
|
||||
while (BasicThreadImage* image = it.Next()) {
|
||||
if (image->TotalHits() > 0) {
|
||||
imageCount++;
|
||||
if (image->TotalHits() > image->UnknownHits())
|
||||
symbolCount += image->GetImage()->SymbolCount();
|
||||
}
|
||||
}
|
||||
|
||||
it = fImages.GetIterator();
|
||||
while (BasicThreadImage* image = it.Next()) {
|
||||
if (image->TotalHits() > 0) {
|
||||
imageCount++;
|
||||
if (image->TotalHits() > image->UnknownHits())
|
||||
symbolCount += image->GetImage()->SymbolCount();
|
||||
}
|
||||
}
|
||||
|
||||
BasicThreadImage* images[imageCount];
|
||||
imageCount = 0;
|
||||
|
||||
it = fOldImages.GetIterator();
|
||||
while (BasicThreadImage* image = it.Next()) {
|
||||
if (image->TotalHits() > 0)
|
||||
images[imageCount++] = image;
|
||||
}
|
||||
|
||||
it = fImages.GetIterator();
|
||||
while (BasicThreadImage* image = it.Next()) {
|
||||
if (image->TotalHits() > 0)
|
||||
images[imageCount++] = image;
|
||||
}
|
||||
|
||||
// find and sort the hit symbols
|
||||
HitSymbol hitSymbols[symbolCount];
|
||||
int32 hitSymbolCount = 0;
|
||||
|
||||
for (int32 k = 0; k < imageCount; k++) {
|
||||
BasicThreadImage* image = images[k];
|
||||
if (image->TotalHits() > image->UnknownHits()) {
|
||||
Symbol** symbols = image->GetImage()->Symbols();
|
||||
const int64* symbolHits = image->SymbolHits();
|
||||
int32 imageSymbolCount = image->GetImage()->SymbolCount();
|
||||
for (int32 i = 0; i < imageSymbolCount; i++) {
|
||||
if (symbolHits[i] > 0) {
|
||||
HitSymbol& hitSymbol = hitSymbols[hitSymbolCount++];
|
||||
hitSymbol.hits = symbolHits[i];
|
||||
hitSymbol.symbol = symbols[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hitSymbolCount > 1)
|
||||
std::sort(hitSymbols, hitSymbols + hitSymbolCount);
|
||||
|
||||
int64 totalTicks = fTotalTicks;
|
||||
fprintf(gOptions.output, "\nprofiling results for thread \"%s\" "
|
||||
"(%ld):\n", fThread->Name(), fThread->ID());
|
||||
fprintf(gOptions.output, " tick interval: %lld us\n", fInterval);
|
||||
fprintf(gOptions.output, " total ticks: %lld (%lld us)\n",
|
||||
totalTicks, totalTicks * fInterval);
|
||||
if (totalTicks == 0)
|
||||
totalTicks = 1;
|
||||
fprintf(gOptions.output, " unknown ticks: %lld (%lld us, %6.2f%%)\n",
|
||||
fUnkownTicks, fUnkownTicks * fInterval,
|
||||
100.0 * fUnkownTicks / totalTicks);
|
||||
fprintf(gOptions.output, " dropped ticks: %lld (%lld us, %6.2f%%)\n",
|
||||
fDroppedTicks, fDroppedTicks * fInterval,
|
||||
100.0 * fDroppedTicks / totalTicks);
|
||||
if (gOptions.analyze_full_stack) {
|
||||
fprintf(gOptions.output, " samples/tick: %.1f\n",
|
||||
(double)fTotalSampleCount / totalTicks);
|
||||
}
|
||||
|
||||
if (imageCount > 0) {
|
||||
fprintf(gOptions.output, "\n");
|
||||
fprintf(gOptions.output, " hits unknown image\n");
|
||||
fprintf(gOptions.output, " ---------------------------------------"
|
||||
"---------------------------------------\n");
|
||||
for (int32 k = 0; k < imageCount; k++) {
|
||||
BasicThreadImage* image = images[k];
|
||||
const image_info& imageInfo = image->GetImage()->Info();
|
||||
fprintf(gOptions.output, " %10lld %10lld %7ld %s\n",
|
||||
image->TotalHits(), image->UnknownHits(), imageInfo.id,
|
||||
imageInfo.name);
|
||||
}
|
||||
}
|
||||
|
||||
if (hitSymbolCount > 0) {
|
||||
fprintf(gOptions.output, "\n");
|
||||
fprintf(gOptions.output, " hits in us in %% "
|
||||
"image function\n");
|
||||
fprintf(gOptions.output, " ---------------------------------------"
|
||||
"---------------------------------------\n");
|
||||
for (int32 i = 0; i < hitSymbolCount; i++) {
|
||||
const HitSymbol& hitSymbol = hitSymbols[i];
|
||||
const Symbol* symbol = hitSymbol.symbol;
|
||||
fprintf(gOptions.output, " %10lld %10lld %6.2f %6ld %s\n",
|
||||
hitSymbol.hits, hitSymbol.hits * fInterval,
|
||||
100.0 * hitSymbol.hits / totalTicks, symbol->image->ID(),
|
||||
symbol->Name());
|
||||
}
|
||||
} else
|
||||
fprintf(gOptions.output, " no functions were hit\n");
|
||||
}
|
||||
|
||||
|
||||
BasicThreadImage*
|
||||
BasicThreadProfileResult::CreateThreadImage(Image* image)
|
||||
{
|
||||
return new(std::nothrow) BasicThreadImage(image);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - InclusiveThreadProfileResult
|
||||
|
||||
|
||||
void
|
||||
InclusiveThreadProfileResult::AddSamples(addr_t* samples, int32 sampleCount)
|
||||
{
|
||||
// Sort the samples. This way hits of the same symbol are
|
||||
// successive and we can avoid incrementing the hit count of the
|
||||
// same symbol twice. Same for images.
|
||||
std::sort(samples, samples + sampleCount);
|
||||
|
||||
int32 unknownSamples = 0;
|
||||
BasicThreadImage* previousImage = NULL;
|
||||
int32 previousSymbol = -1;
|
||||
|
||||
for (int32 i = 0; i < sampleCount; i++) {
|
||||
addr_t address = samples[i];
|
||||
BasicThreadImage* image = FindImage(address);
|
||||
int32 symbol = -1;
|
||||
if (image != NULL) {
|
||||
symbol = image->GetImage()->FindSymbol(address);
|
||||
if (symbol < 0) {
|
||||
// TODO: Count unknown image hits?
|
||||
} else if (symbol != previousSymbol)
|
||||
image->AddSymbolHit(symbol);
|
||||
|
||||
if (image != previousImage)
|
||||
image->AddImageHit();
|
||||
} else
|
||||
unknownSamples++;
|
||||
|
||||
previousImage = image;
|
||||
previousSymbol = symbol;
|
||||
}
|
||||
|
||||
if (unknownSamples == sampleCount)
|
||||
fUnkownTicks++;
|
||||
|
||||
fTotalTicks++;
|
||||
fTotalSampleCount += sampleCount;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - ExclusiveThreadProfileResult
|
||||
|
||||
|
||||
void
|
||||
ExclusiveThreadProfileResult::AddSamples(addr_t* samples, int32 sampleCount)
|
||||
{
|
||||
BasicThreadImage* image = NULL;
|
||||
for (int32 k = 0; k < sampleCount; k++) {
|
||||
addr_t address = samples[k];
|
||||
image = FindImage(address);
|
||||
if (image != NULL) {
|
||||
image->AddHit(address);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (image == NULL)
|
||||
fUnkownTicks++;
|
||||
|
||||
fTotalTicks++;
|
||||
fTotalSampleCount += sampleCount;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2008, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef BASIC_THREAD_PROFILE_RESULT_H
|
||||
#define BASIC_THREAD_PROFILE_RESULT_H
|
||||
|
||||
#include "Thread.h"
|
||||
|
||||
|
||||
class BasicThreadImage : public ThreadImage,
|
||||
public DoublyLinkedListLinkImpl<BasicThreadImage> {
|
||||
public:
|
||||
BasicThreadImage(Image* image);
|
||||
virtual ~BasicThreadImage();
|
||||
|
||||
virtual status_t Init();
|
||||
|
||||
inline void AddHit(addr_t address);
|
||||
inline void AddSymbolHit(int32 symbolIndex);
|
||||
inline void AddImageHit();
|
||||
|
||||
inline const int64* SymbolHits() const;
|
||||
inline int64 UnknownHits() const;
|
||||
|
||||
private:
|
||||
int64* fSymbolHits;
|
||||
int64 fUnknownHits;
|
||||
};
|
||||
|
||||
|
||||
class BasicThreadProfileResult
|
||||
: public AbstractThreadProfileResult<BasicThreadImage> {
|
||||
public:
|
||||
BasicThreadProfileResult();
|
||||
|
||||
virtual void AddDroppedTicks(int32 dropped);
|
||||
virtual void PrintResults();
|
||||
|
||||
virtual BasicThreadImage* CreateThreadImage(Image* image);
|
||||
|
||||
protected:
|
||||
int64 fTotalTicks;
|
||||
int64 fUnkownTicks;
|
||||
int64 fDroppedTicks;
|
||||
int64 fTotalSampleCount;
|
||||
};
|
||||
|
||||
|
||||
class InclusiveThreadProfileResult : public BasicThreadProfileResult {
|
||||
public:
|
||||
virtual void AddSamples(addr_t* samples,
|
||||
int32 sampleCount);
|
||||
};
|
||||
|
||||
|
||||
class ExclusiveThreadProfileResult : public BasicThreadProfileResult {
|
||||
public:
|
||||
virtual void AddSamples(addr_t* samples,
|
||||
int32 sampleCount);
|
||||
};
|
||||
|
||||
|
||||
#endif // BASIC_THREAD_PROFILE_RESULT_H
|
||||
@@ -10,6 +10,7 @@ SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ;
|
||||
|
||||
BinCommand profile
|
||||
:
|
||||
BasicThreadProfileResult.cpp
|
||||
Image.cpp
|
||||
Team.cpp
|
||||
Thread.cpp
|
||||
|
||||
@@ -16,106 +16,32 @@
|
||||
#include "Team.h"
|
||||
|
||||
|
||||
struct HitSymbol {
|
||||
int64 hits;
|
||||
Symbol* symbol;
|
||||
|
||||
inline bool operator<(const HitSymbol& other) const
|
||||
{
|
||||
return hits > other.hits;
|
||||
}
|
||||
};
|
||||
// #pragma mark - ThreadImage
|
||||
|
||||
|
||||
class ThreadImage : public DoublyLinkedListLinkImpl<ThreadImage> {
|
||||
public:
|
||||
ThreadImage(Image* image)
|
||||
:
|
||||
fImage(image),
|
||||
fSymbolHits(NULL),
|
||||
fTotalHits(0),
|
||||
fUnknownHits(0)
|
||||
{
|
||||
fImage->AddReference();
|
||||
}
|
||||
|
||||
virtual ~ThreadImage()
|
||||
{
|
||||
fImage->RemoveReference();
|
||||
}
|
||||
|
||||
status_t Init()
|
||||
{
|
||||
int32 symbolCount = fImage->SymbolCount();
|
||||
fSymbolHits = new(std::nothrow) int64[symbolCount];
|
||||
if (fSymbolHits == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
memset(fSymbolHits, 0, 8 * symbolCount);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
image_id ID() const
|
||||
{
|
||||
return fImage->ID();
|
||||
}
|
||||
|
||||
bool ContainsAddress(addr_t address) const
|
||||
{
|
||||
return fImage->ContainsAddress(address);
|
||||
}
|
||||
|
||||
void AddHit(addr_t address)
|
||||
{
|
||||
int32 symbolIndex = fImage->FindSymbol(address);
|
||||
if (symbolIndex >= 0)
|
||||
fSymbolHits[symbolIndex]++;
|
||||
else
|
||||
fUnknownHits++;
|
||||
|
||||
fTotalHits++;
|
||||
}
|
||||
|
||||
void AddSymbolHit(int32 symbolIndex)
|
||||
{
|
||||
fSymbolHits[symbolIndex]++;
|
||||
}
|
||||
|
||||
void AddImageHit()
|
||||
{
|
||||
fTotalHits++;
|
||||
}
|
||||
|
||||
Image* GetImage() const
|
||||
{
|
||||
return fImage;
|
||||
}
|
||||
|
||||
const int64* SymbolHits() const
|
||||
{
|
||||
return fSymbolHits;
|
||||
}
|
||||
|
||||
int64 TotalHits() const
|
||||
{
|
||||
return fTotalHits;
|
||||
}
|
||||
|
||||
int64 UnknownHits() const
|
||||
{
|
||||
return fUnknownHits;
|
||||
}
|
||||
|
||||
private:
|
||||
Image* fImage;
|
||||
int64* fSymbolHits;
|
||||
int64 fTotalHits;
|
||||
int64 fUnknownHits;
|
||||
};
|
||||
ThreadImage::ThreadImage(Image* image)
|
||||
:
|
||||
fImage(image),
|
||||
fTotalHits(0)
|
||||
{
|
||||
fImage->AddReference();
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
ThreadImage::~ThreadImage()
|
||||
{
|
||||
fImage->RemoveReference();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ThreadImage::Init()
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Thread
|
||||
|
||||
|
||||
Thread::Thread(const thread_info& info, Team* team)
|
||||
@@ -256,291 +182,3 @@ ThreadProfileResult::SetInterval(bigtime_t interval)
|
||||
{
|
||||
fInterval = interval;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - AbstractThreadProfileResult
|
||||
|
||||
|
||||
AbstractThreadProfileResult::AbstractThreadProfileResult()
|
||||
:
|
||||
fImages(),
|
||||
fNewImages(),
|
||||
fOldImages()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
AbstractThreadProfileResult::~AbstractThreadProfileResult()
|
||||
{
|
||||
while (ThreadImage* image = fImages.RemoveHead())
|
||||
delete image;
|
||||
while (ThreadImage* image = fOldImages.RemoveHead())
|
||||
delete image;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AbstractThreadProfileResult::AddImage(Image* image)
|
||||
{
|
||||
ThreadImage* threadImage = CreateThreadImage(image);
|
||||
if (threadImage == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t error = threadImage->Init();
|
||||
if (error != B_OK) {
|
||||
delete threadImage;
|
||||
return error;
|
||||
}
|
||||
|
||||
fNewImages.Add(threadImage);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AbstractThreadProfileResult::SynchronizeImages(int32 event)
|
||||
{
|
||||
// remove obsolete images
|
||||
ImageList::Iterator it = fImages.GetIterator();
|
||||
while (ThreadImage* image = it.Next()) {
|
||||
int32 deleted = image->GetImage()->DeletionEvent();
|
||||
if (deleted >= 0 && event >= deleted) {
|
||||
it.Remove();
|
||||
if (image->TotalHits() > 0)
|
||||
fOldImages.Add(image);
|
||||
else
|
||||
delete image;
|
||||
}
|
||||
}
|
||||
|
||||
// add new images
|
||||
it = fNewImages.GetIterator();
|
||||
while (ThreadImage* image = it.Next()) {
|
||||
if (image->GetImage()->CreationEvent() >= event) {
|
||||
it.Remove();
|
||||
fImages.Add(image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ThreadImage*
|
||||
AbstractThreadProfileResult::FindImage(addr_t address) const
|
||||
{
|
||||
ImageList::ConstIterator it = fImages.GetIterator();
|
||||
while (ThreadImage* image = it.Next()) {
|
||||
if (image->ContainsAddress(address))
|
||||
return image;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - BasicThreadProfileResult
|
||||
|
||||
|
||||
BasicThreadProfileResult::BasicThreadProfileResult()
|
||||
:
|
||||
fTotalTicks(0),
|
||||
fUnkownTicks(0),
|
||||
fDroppedTicks(0),
|
||||
fTotalSampleCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BasicThreadProfileResult::AddDroppedTicks(int32 dropped)
|
||||
{
|
||||
fDroppedTicks += dropped;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BasicThreadProfileResult::PrintResults()
|
||||
{
|
||||
// count images and symbols
|
||||
int32 imageCount = 0;
|
||||
int32 symbolCount = 0;
|
||||
|
||||
ImageList::Iterator it = fOldImages.GetIterator();
|
||||
while (ThreadImage* image = it.Next()) {
|
||||
if (image->TotalHits() > 0) {
|
||||
imageCount++;
|
||||
if (image->TotalHits() > image->UnknownHits())
|
||||
symbolCount += image->GetImage()->SymbolCount();
|
||||
}
|
||||
}
|
||||
|
||||
it = fImages.GetIterator();
|
||||
while (ThreadImage* image = it.Next()) {
|
||||
if (image->TotalHits() > 0) {
|
||||
imageCount++;
|
||||
if (image->TotalHits() > image->UnknownHits())
|
||||
symbolCount += image->GetImage()->SymbolCount();
|
||||
}
|
||||
}
|
||||
|
||||
ThreadImage* images[imageCount];
|
||||
imageCount = 0;
|
||||
|
||||
it = fOldImages.GetIterator();
|
||||
while (ThreadImage* image = it.Next()) {
|
||||
if (image->TotalHits() > 0)
|
||||
images[imageCount++] = image;
|
||||
}
|
||||
|
||||
it = fImages.GetIterator();
|
||||
while (ThreadImage* image = it.Next()) {
|
||||
if (image->TotalHits() > 0)
|
||||
images[imageCount++] = image;
|
||||
}
|
||||
|
||||
// find and sort the hit symbols
|
||||
HitSymbol hitSymbols[symbolCount];
|
||||
int32 hitSymbolCount = 0;
|
||||
|
||||
for (int32 k = 0; k < imageCount; k++) {
|
||||
ThreadImage* image = images[k];
|
||||
if (image->TotalHits() > image->UnknownHits()) {
|
||||
Symbol** symbols = image->GetImage()->Symbols();
|
||||
const int64* symbolHits = image->SymbolHits();
|
||||
int32 imageSymbolCount = image->GetImage()->SymbolCount();
|
||||
for (int32 i = 0; i < imageSymbolCount; i++) {
|
||||
if (symbolHits[i] > 0) {
|
||||
HitSymbol& hitSymbol = hitSymbols[hitSymbolCount++];
|
||||
hitSymbol.hits = symbolHits[i];
|
||||
hitSymbol.symbol = symbols[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hitSymbolCount > 1)
|
||||
std::sort(hitSymbols, hitSymbols + hitSymbolCount);
|
||||
|
||||
int64 totalTicks = fTotalTicks;
|
||||
fprintf(gOptions.output, "\nprofiling results for thread \"%s\" "
|
||||
"(%ld):\n", fThread->Name(), fThread->ID());
|
||||
fprintf(gOptions.output, " tick interval: %lld us\n", fInterval);
|
||||
fprintf(gOptions.output, " total ticks: %lld (%lld us)\n",
|
||||
totalTicks, totalTicks * fInterval);
|
||||
if (totalTicks == 0)
|
||||
totalTicks = 1;
|
||||
fprintf(gOptions.output, " unknown ticks: %lld (%lld us, %6.2f%%)\n",
|
||||
fUnkownTicks, fUnkownTicks * fInterval,
|
||||
100.0 * fUnkownTicks / totalTicks);
|
||||
fprintf(gOptions.output, " dropped ticks: %lld (%lld us, %6.2f%%)\n",
|
||||
fDroppedTicks, fDroppedTicks * fInterval,
|
||||
100.0 * fDroppedTicks / totalTicks);
|
||||
if (gOptions.analyze_full_stack) {
|
||||
fprintf(gOptions.output, " samples/tick: %.1f\n",
|
||||
(double)fTotalSampleCount / totalTicks);
|
||||
}
|
||||
|
||||
if (imageCount > 0) {
|
||||
fprintf(gOptions.output, "\n");
|
||||
fprintf(gOptions.output, " hits unknown image\n");
|
||||
fprintf(gOptions.output, " ---------------------------------------"
|
||||
"---------------------------------------\n");
|
||||
for (int32 k = 0; k < imageCount; k++) {
|
||||
ThreadImage* image = images[k];
|
||||
const image_info& imageInfo = image->GetImage()->Info();
|
||||
fprintf(gOptions.output, " %10lld %10lld %7ld %s\n",
|
||||
image->TotalHits(), image->UnknownHits(), imageInfo.id,
|
||||
imageInfo.name);
|
||||
}
|
||||
}
|
||||
|
||||
if (hitSymbolCount > 0) {
|
||||
fprintf(gOptions.output, "\n");
|
||||
fprintf(gOptions.output, " hits in us in %% "
|
||||
"image function\n");
|
||||
fprintf(gOptions.output, " ---------------------------------------"
|
||||
"---------------------------------------\n");
|
||||
for (int32 i = 0; i < hitSymbolCount; i++) {
|
||||
const HitSymbol& hitSymbol = hitSymbols[i];
|
||||
const Symbol* symbol = hitSymbol.symbol;
|
||||
fprintf(gOptions.output, " %10lld %10lld %6.2f %6ld %s\n",
|
||||
hitSymbol.hits, hitSymbol.hits * fInterval,
|
||||
100.0 * hitSymbol.hits / totalTicks, symbol->image->ID(),
|
||||
symbol->Name());
|
||||
}
|
||||
} else
|
||||
fprintf(gOptions.output, " no functions were hit\n");
|
||||
}
|
||||
|
||||
|
||||
ThreadImage*
|
||||
BasicThreadProfileResult::CreateThreadImage(Image* image)
|
||||
{
|
||||
return new(std::nothrow) ThreadImage(image);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - InclusiveThreadProfileResult
|
||||
|
||||
|
||||
void
|
||||
InclusiveThreadProfileResult::AddSamples(addr_t* samples, int32 sampleCount)
|
||||
{
|
||||
// Sort the samples. This way hits of the same symbol are
|
||||
// successive and we can avoid incrementing the hit count of the
|
||||
// same symbol twice. Same for images.
|
||||
std::sort(samples, samples + sampleCount);
|
||||
|
||||
int32 unknownSamples = 0;
|
||||
ThreadImage* previousImage = NULL;
|
||||
int32 previousSymbol = -1;
|
||||
|
||||
for (int32 i = 0; i < sampleCount; i++) {
|
||||
addr_t address = samples[i];
|
||||
ThreadImage* image = FindImage(address);
|
||||
int32 symbol = -1;
|
||||
if (image != NULL) {
|
||||
symbol = image->GetImage()->FindSymbol(address);
|
||||
if (symbol < 0) {
|
||||
// TODO: Count unknown image hits?
|
||||
} else if (symbol != previousSymbol)
|
||||
image->AddSymbolHit(symbol);
|
||||
|
||||
if (image != previousImage)
|
||||
image->AddImageHit();
|
||||
} else
|
||||
unknownSamples++;
|
||||
|
||||
previousImage = image;
|
||||
previousSymbol = symbol;
|
||||
}
|
||||
|
||||
if (unknownSamples == sampleCount)
|
||||
fUnkownTicks++;
|
||||
|
||||
fTotalTicks++;
|
||||
fTotalSampleCount += sampleCount;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - ExclusiveThreadProfileResult
|
||||
|
||||
|
||||
void
|
||||
ExclusiveThreadProfileResult::AddSamples(addr_t* samples, int32 sampleCount)
|
||||
{
|
||||
ThreadImage* image = NULL;
|
||||
for (int32 k = 0; k < sampleCount; k++) {
|
||||
addr_t address = samples[k];
|
||||
image = FindImage(address);
|
||||
if (image != NULL) {
|
||||
image->AddHit(address);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (image == NULL)
|
||||
fUnkownTicks++;
|
||||
|
||||
fTotalTicks++;
|
||||
fTotalSampleCount += sampleCount;
|
||||
}
|
||||
|
||||
+133
-28
@@ -15,6 +15,26 @@ class ThreadImage;
|
||||
class ThreadProfileResult;
|
||||
|
||||
|
||||
class ThreadImage {
|
||||
public:
|
||||
ThreadImage(Image* image);
|
||||
virtual ~ThreadImage();
|
||||
|
||||
virtual status_t Init();
|
||||
|
||||
inline image_id ID() const;
|
||||
inline Image* GetImage() const;
|
||||
|
||||
inline bool ContainsAddress(addr_t address) const;
|
||||
|
||||
inline int64 TotalHits() const;
|
||||
|
||||
protected:
|
||||
Image* fImage;
|
||||
int64 fTotalHits;
|
||||
};
|
||||
|
||||
|
||||
class Thread : public DoublyLinkedListLinkImpl<Thread> {
|
||||
public:
|
||||
Thread(const thread_info& info, Team* team);
|
||||
@@ -75,6 +95,7 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
template<typename ThreadImageType>
|
||||
class AbstractThreadProfileResult : public ThreadProfileResult {
|
||||
public:
|
||||
AbstractThreadProfileResult();
|
||||
@@ -83,17 +104,17 @@ public:
|
||||
virtual status_t AddImage(Image* image);
|
||||
virtual void SynchronizeImages(int32 event);
|
||||
|
||||
ThreadImage* FindImage(addr_t address) const;
|
||||
ThreadImageType* FindImage(addr_t address) const;
|
||||
|
||||
virtual void AddSamples(addr_t* samples,
|
||||
int32 sampleCount) = 0;
|
||||
virtual void AddDroppedTicks(int32 dropped) = 0;
|
||||
virtual void PrintResults() = 0;
|
||||
|
||||
virtual ThreadImage* CreateThreadImage(Image* image) = 0;
|
||||
virtual ThreadImageType* CreateThreadImage(Image* image) = 0;
|
||||
|
||||
protected:
|
||||
typedef DoublyLinkedList<ThreadImage> ImageList;
|
||||
typedef DoublyLinkedList<ThreadImageType> ImageList;
|
||||
|
||||
ImageList fImages;
|
||||
ImageList fNewImages;
|
||||
@@ -101,35 +122,35 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
class BasicThreadProfileResult : public AbstractThreadProfileResult {
|
||||
public:
|
||||
BasicThreadProfileResult();
|
||||
|
||||
virtual void AddDroppedTicks(int32 dropped);
|
||||
virtual void PrintResults();
|
||||
|
||||
virtual ThreadImage* CreateThreadImage(Image* image);
|
||||
|
||||
protected:
|
||||
int64 fTotalTicks;
|
||||
int64 fUnkownTicks;
|
||||
int64 fDroppedTicks;
|
||||
int64 fTotalSampleCount;
|
||||
};
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
class InclusiveThreadProfileResult : public BasicThreadProfileResult {
|
||||
public:
|
||||
virtual void AddSamples(addr_t* samples,
|
||||
int32 sampleCount);
|
||||
};
|
||||
image_id
|
||||
ThreadImage::ID() const
|
||||
{
|
||||
return fImage->ID();
|
||||
}
|
||||
|
||||
|
||||
class ExclusiveThreadProfileResult : public BasicThreadProfileResult {
|
||||
public:
|
||||
virtual void AddSamples(addr_t* samples,
|
||||
int32 sampleCount);
|
||||
};
|
||||
bool
|
||||
ThreadImage::ContainsAddress(addr_t address) const
|
||||
{
|
||||
return fImage->ContainsAddress(address);
|
||||
}
|
||||
|
||||
|
||||
Image*
|
||||
ThreadImage::GetImage() const
|
||||
{
|
||||
return fImage;
|
||||
}
|
||||
|
||||
|
||||
int64
|
||||
ThreadImage::TotalHits() const
|
||||
{
|
||||
return fTotalHits;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
@@ -170,4 +191,88 @@ Thread::ProfileResult() const
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - AbstractThreadProfileResult
|
||||
|
||||
|
||||
template<typename ThreadImageType>
|
||||
AbstractThreadProfileResult<ThreadImageType>::AbstractThreadProfileResult()
|
||||
:
|
||||
fImages(),
|
||||
fNewImages(),
|
||||
fOldImages()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
template<typename ThreadImageType>
|
||||
AbstractThreadProfileResult<ThreadImageType>::~AbstractThreadProfileResult()
|
||||
{
|
||||
while (ThreadImageType* image = fImages.RemoveHead())
|
||||
delete image;
|
||||
while (ThreadImageType* image = fOldImages.RemoveHead())
|
||||
delete image;
|
||||
}
|
||||
|
||||
|
||||
template<typename ThreadImageType>
|
||||
status_t
|
||||
AbstractThreadProfileResult<ThreadImageType>::AddImage(Image* image)
|
||||
{
|
||||
ThreadImageType* threadImage = CreateThreadImage(image);
|
||||
if (threadImage == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t error = threadImage->Init();
|
||||
if (error != B_OK) {
|
||||
delete threadImage;
|
||||
return error;
|
||||
}
|
||||
|
||||
fNewImages.Add(threadImage);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
template<typename ThreadImageType>
|
||||
void
|
||||
AbstractThreadProfileResult<ThreadImageType>::SynchronizeImages(int32 event)
|
||||
{
|
||||
// remove obsolete images
|
||||
ImageList::Iterator it = fImages.GetIterator();
|
||||
while (ThreadImageType* image = it.Next()) {
|
||||
int32 deleted = image->GetImage()->DeletionEvent();
|
||||
if (deleted >= 0 && event >= deleted) {
|
||||
it.Remove();
|
||||
if (image->TotalHits() > 0)
|
||||
fOldImages.Add(image);
|
||||
else
|
||||
delete image;
|
||||
}
|
||||
}
|
||||
|
||||
// add new images
|
||||
it = fNewImages.GetIterator();
|
||||
while (ThreadImageType* image = it.Next()) {
|
||||
if (image->GetImage()->CreationEvent() >= event) {
|
||||
it.Remove();
|
||||
fImages.Add(image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename ThreadImageType>
|
||||
ThreadImageType*
|
||||
AbstractThreadProfileResult<ThreadImageType>::FindImage(addr_t address) const
|
||||
{
|
||||
ImageList::ConstIterator it = fImages.GetIterator();
|
||||
while (ThreadImageType* image = it.Next()) {
|
||||
if (image->ContainsAddress(address))
|
||||
return image;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#endif // THREAD_H
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
#include "BasicThreadProfileResult.h"
|
||||
#include "debug_utils.h"
|
||||
#include "Image.h"
|
||||
#include "Options.h"
|
||||
|
||||
Reference in New Issue
Block a user