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
|
BinCommand profile
|
||||||
:
|
:
|
||||||
|
BasicThreadProfileResult.cpp
|
||||||
Image.cpp
|
Image.cpp
|
||||||
Team.cpp
|
Team.cpp
|
||||||
Thread.cpp
|
Thread.cpp
|
||||||
|
|||||||
@@ -16,106 +16,32 @@
|
|||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
|
|
||||||
|
|
||||||
struct HitSymbol {
|
// #pragma mark - ThreadImage
|
||||||
int64 hits;
|
|
||||||
Symbol* symbol;
|
|
||||||
|
|
||||||
inline bool operator<(const HitSymbol& other) const
|
|
||||||
{
|
|
||||||
return hits > other.hits;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class ThreadImage : public DoublyLinkedListLinkImpl<ThreadImage> {
|
ThreadImage::ThreadImage(Image* image)
|
||||||
public:
|
|
||||||
ThreadImage(Image* image)
|
|
||||||
:
|
:
|
||||||
fImage(image),
|
fImage(image),
|
||||||
fSymbolHits(NULL),
|
fTotalHits(0)
|
||||||
fTotalHits(0),
|
{
|
||||||
fUnknownHits(0)
|
|
||||||
{
|
|
||||||
fImage->AddReference();
|
fImage->AddReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~ThreadImage()
|
|
||||||
{
|
ThreadImage::~ThreadImage()
|
||||||
|
{
|
||||||
fImage->RemoveReference();
|
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);
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ThreadImage::Init()
|
||||||
|
{
|
||||||
return B_OK;
|
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark - Thread
|
||||||
|
|
||||||
|
|
||||||
Thread::Thread(const thread_info& info, Team* team)
|
Thread::Thread(const thread_info& info, Team* team)
|
||||||
@@ -256,291 +182,3 @@ ThreadProfileResult::SetInterval(bigtime_t interval)
|
|||||||
{
|
{
|
||||||
fInterval = 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 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> {
|
class Thread : public DoublyLinkedListLinkImpl<Thread> {
|
||||||
public:
|
public:
|
||||||
Thread(const thread_info& info, Team* team);
|
Thread(const thread_info& info, Team* team);
|
||||||
@@ -75,6 +95,7 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ThreadImageType>
|
||||||
class AbstractThreadProfileResult : public ThreadProfileResult {
|
class AbstractThreadProfileResult : public ThreadProfileResult {
|
||||||
public:
|
public:
|
||||||
AbstractThreadProfileResult();
|
AbstractThreadProfileResult();
|
||||||
@@ -83,17 +104,17 @@ public:
|
|||||||
virtual status_t AddImage(Image* image);
|
virtual status_t AddImage(Image* image);
|
||||||
virtual void SynchronizeImages(int32 event);
|
virtual void SynchronizeImages(int32 event);
|
||||||
|
|
||||||
ThreadImage* FindImage(addr_t address) const;
|
ThreadImageType* FindImage(addr_t address) const;
|
||||||
|
|
||||||
virtual void AddSamples(addr_t* samples,
|
virtual void AddSamples(addr_t* samples,
|
||||||
int32 sampleCount) = 0;
|
int32 sampleCount) = 0;
|
||||||
virtual void AddDroppedTicks(int32 dropped) = 0;
|
virtual void AddDroppedTicks(int32 dropped) = 0;
|
||||||
virtual void PrintResults() = 0;
|
virtual void PrintResults() = 0;
|
||||||
|
|
||||||
virtual ThreadImage* CreateThreadImage(Image* image) = 0;
|
virtual ThreadImageType* CreateThreadImage(Image* image) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef DoublyLinkedList<ThreadImage> ImageList;
|
typedef DoublyLinkedList<ThreadImageType> ImageList;
|
||||||
|
|
||||||
ImageList fImages;
|
ImageList fImages;
|
||||||
ImageList fNewImages;
|
ImageList fNewImages;
|
||||||
@@ -101,35 +122,35 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class BasicThreadProfileResult : public AbstractThreadProfileResult {
|
// #pragma mark -
|
||||||
public:
|
|
||||||
BasicThreadProfileResult();
|
|
||||||
|
|
||||||
virtual void AddDroppedTicks(int32 dropped);
|
|
||||||
virtual void PrintResults();
|
|
||||||
|
|
||||||
virtual ThreadImage* CreateThreadImage(Image* image);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
int64 fTotalTicks;
|
|
||||||
int64 fUnkownTicks;
|
|
||||||
int64 fDroppedTicks;
|
|
||||||
int64 fTotalSampleCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class InclusiveThreadProfileResult : public BasicThreadProfileResult {
|
image_id
|
||||||
public:
|
ThreadImage::ID() const
|
||||||
virtual void AddSamples(addr_t* samples,
|
{
|
||||||
int32 sampleCount);
|
return fImage->ID();
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
class ExclusiveThreadProfileResult : public BasicThreadProfileResult {
|
bool
|
||||||
public:
|
ThreadImage::ContainsAddress(addr_t address) const
|
||||||
virtual void AddSamples(addr_t* samples,
|
{
|
||||||
int32 sampleCount);
|
return fImage->ContainsAddress(address);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Image*
|
||||||
|
ThreadImage::GetImage() const
|
||||||
|
{
|
||||||
|
return fImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int64
|
||||||
|
ThreadImage::TotalHits() const
|
||||||
|
{
|
||||||
|
return fTotalHits;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #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
|
#endif // THREAD_H
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <util/DoublyLinkedList.h>
|
#include <util/DoublyLinkedList.h>
|
||||||
|
|
||||||
|
#include "BasicThreadProfileResult.h"
|
||||||
#include "debug_utils.h"
|
#include "debug_utils.h"
|
||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
#include "Options.h"
|
#include "Options.h"
|
||||||
|
|||||||
Reference in New Issue
Block a user