Some refactoring: Separated the profile result collection from the

thread management. There's now a ThreadProfileResult (abstract base
class) object associated with a Thread object. Currently there's only
one (currently misnamed) derived class AbstractThreadProfileResult, but
some more refactoring will make the purpose clearer.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27780 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2008-09-29 15:14:31 +00:00
parent 120cfc6238
commit ed2fc87300
3 changed files with 282 additions and 202 deletions

View File

@ -124,26 +124,25 @@ Thread::Thread(const thread_info& info, Team* team)
fTeam(team),
fSampleArea(-1),
fSamples(NULL),
fImages(),
fOldImages(),
fTotalTicks(0),
fUnkownTicks(0),
fDroppedTicks(0),
fInterval(1),
fTotalSampleCount(0)
fProfileResult(NULL)
{
}
Thread::~Thread()
{
while (ThreadImage* image = fImages.RemoveHead())
delete image;
while (ThreadImage* image = fOldImages.RemoveHead())
delete image;
if (fSampleArea >= 0)
delete_area(fSampleArea);
delete fProfileResult;
}
void
Thread::SetProfileResult(ThreadProfileResult* result)
{
delete fProfileResult;
fProfileResult = result;
}
@ -167,12 +166,131 @@ Thread::SetSampleArea(area_id area, addr_t* samples)
void
Thread::SetInterval(bigtime_t interval)
{
fInterval = interval;
fProfileResult->SetInterval(interval);
}
status_t
Thread::AddImage(Image* image)
{
return fProfileResult->AddImage(image);
}
void
Thread::AddSamples(int32 count, int32 dropped, int32 stackDepth,
bool variableStackDepth, int32 event)
{
fProfileResult->SynchronizeImages(event);
if (variableStackDepth) {
addr_t* samples = fSamples;
while (count > 0) {
addr_t sampleCount = *(samples++);
if (sampleCount >= B_DEBUG_PROFILE_EVENT_BASE) {
int32 eventParameterCount
= sampleCount & B_DEBUG_PROFILE_EVENT_PARAMETER_MASK;
if (sampleCount == B_DEBUG_PROFILE_IMAGE_EVENT) {
fProfileResult->SynchronizeImages((int32)samples[0]);
} else {
fprintf(stderr, "unknown profile event: %#lx\n",
sampleCount);
}
samples += eventParameterCount;
count -= eventParameterCount + 1;
continue;
}
fProfileResult->AddSamples(samples, sampleCount);
samples += sampleCount;
count -= sampleCount + 1;
}
} else {
count = count / stackDepth * stackDepth;
for (int32 i = 0; i < count; i += stackDepth)
fProfileResult->AddSamples(fSamples + i, stackDepth);
}
fProfileResult->AddDroppedTicks(dropped);
}
void
Thread::PrintResults() const
{
fProfileResult->PrintResults();
}
// #pragma mark - ThreadProfileResult
ThreadProfileResult::ThreadProfileResult()
:
fThread(NULL),
fInterval(1)
{
}
ThreadProfileResult::~ThreadProfileResult()
{
}
status_t
ThreadProfileResult::Init(Thread* thread)
{
fThread = thread;
return B_OK;
}
void
ThreadProfileResult::SetInterval(bigtime_t interval)
{
fInterval = interval;
}
// #pragma mark - AbstractThreadProfileResult
AbstractThreadProfileResult::AbstractThreadProfileResult()
:
fImages(),
fNewImages(),
fOldImages(),
fTotalTicks(0),
fUnkownTicks(0),
fDroppedTicks(0),
fTotalSampleCount(0)
{
}
AbstractThreadProfileResult::~AbstractThreadProfileResult()
{
while (ThreadImage* image = fImages.RemoveHead())
delete image;
while (ThreadImage* image = fOldImages.RemoveHead())
delete image;
}
status_t
AbstractThreadProfileResult::Init(Thread* thread)
{
return ThreadProfileResult::Init(thread);
}
status_t
AbstractThreadProfileResult::AddImage(Image* image)
{
ThreadImage* threadImage = new(std::nothrow) ThreadImage(image);
if (threadImage == NULL)
@ -184,31 +302,41 @@ Thread::AddImage(Image* image)
return error;
}
fImages.Add(threadImage);
fNewImages.Add(threadImage);
return B_OK;
}
void
Thread::ImageRemoved(Image* image)
AbstractThreadProfileResult::SynchronizeImages(int32 event)
{
// remove obsolete images
ImageList::Iterator it = fImages.GetIterator();
while (ThreadImage* threadImage = it.Next()) {
if (threadImage->GetImage() == image) {
fImages.Remove(threadImage);
if (threadImage->TotalHits() > 0)
fOldImages.Add(threadImage);
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 threadImage;
return;
delete image;
}
}
// add new images
it = fNewImages.GetIterator();
while (ThreadImage* image = it.Next()) {
if (image->GetImage()->CreationEvent() >= event) {
it.Remove();
fImages.Add(image);
}
}
}
ThreadImage*
Thread::FindImage(addr_t address) const
AbstractThreadProfileResult::FindImage(addr_t address) const
{
ImageList::ConstIterator it = fImages.GetIterator();
while (ThreadImage* image = it.Next()) {
@ -220,127 +348,75 @@ Thread::FindImage(addr_t address) const
void
Thread::AddSamples(int32 count, int32 dropped, int32 stackDepth,
bool variableStackDepth, int32 event)
AbstractThreadProfileResult::AddSamples(addr_t* samples, int32 sampleCount)
{
_RemoveObsoleteImages(event);
if (gOptions.analyze_full_stack) {
// 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);
// Temporarily remove images that have been created after the given
// event.
ImageList newImages;
ImageList::Iterator it = fImages.GetIterator();
while (ThreadImage* image = it.Next()) {
if (image->GetImage()->CreationEvent() > event) {
it.Remove();
newImages.Add(image);
}
}
int32 unknownSamples = 0;
ThreadImage* previousImage = NULL;
int32 previousSymbol = -1;
if (variableStackDepth) {
// Variable stack depth means we have full caller stack analyzes
// enabled.
int32 totalSampleCount = 0;
int32 tickCount = 0;
addr_t* samples = fSamples;
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);
while (count > 0) {
addr_t sampleCount = *(samples++);
if (image != previousImage)
image->AddImageHit();
} else
unknownSamples++;
if (sampleCount >= B_DEBUG_PROFILE_EVENT_BASE) {
int32 eventParameterCount
= sampleCount & B_DEBUG_PROFILE_EVENT_PARAMETER_MASK;
if (sampleCount == B_DEBUG_PROFILE_IMAGE_EVENT) {
int32 imageEvent = (int32)samples[0];
_RemoveObsoleteImages(imageEvent);
_AddNewImages(newImages, imageEvent);
} else {
fprintf(stderr, "unknown profile event: %#lx\n",
sampleCount);
}
samples += eventParameterCount;
count -= eventParameterCount + 1;
continue;
}
// 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 (uint32 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 == (int32)sampleCount)
fUnkownTicks++;
samples += sampleCount;
count -= sampleCount + 1;
tickCount++;
totalSampleCount += sampleCount;
previousImage = image;
previousSymbol = symbol;
}
fTotalTicks += tickCount;
fTotalSampleCount += totalSampleCount;
if (unknownSamples == sampleCount)
fUnkownTicks++;
} else {
count = count / stackDepth * stackDepth;
for (int32 i = 0; i < count; i += stackDepth) {
ThreadImage* image = NULL;
for (int32 k = 0; k < stackDepth; k++) {
addr_t address = fSamples[i + k];
image = FindImage(address);
if (image != NULL) {
image->AddHit(address);
break;
}
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 += count / stackDepth;
if (image == NULL)
fUnkownTicks++;
}
fDroppedTicks += dropped;
// re-add the new images
fImages.MoveFrom(&newImages);
_SynchronizeImages();
fTotalTicks++;
fTotalSampleCount += sampleCount;
}
void
Thread::PrintResults() const
AbstractThreadProfileResult::AddDroppedTicks(int32 dropped)
{
fDroppedTicks += dropped;
}
void
AbstractThreadProfileResult::PrintResults()
{
// count images and symbols
int32 imageCount = 0;
int32 symbolCount = 0;
ImageList::ConstIterator it = fOldImages.GetIterator();
ImageList::Iterator it = fOldImages.GetIterator();
while (ThreadImage* image = it.Next()) {
if (image->TotalHits() > 0) {
imageCount++;
@ -398,7 +474,7 @@ Thread::PrintResults() const
int64 totalTicks = fTotalTicks;
fprintf(gOptions.output, "\nprofiling results for thread \"%s\" "
"(%ld):\n", Name(), ID());
"(%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);
@ -447,71 +523,3 @@ Thread::PrintResults() const
fprintf(gOptions.output, " no functions were hit\n");
}
void
Thread::_SynchronizeImages()
{
const BObjectList<Image>& teamImages = fTeam->Images();
// remove obsolete images
ImageList::Iterator it = fImages.GetIterator();
while (ThreadImage* image = it.Next()) {
if (fTeam->FindImage(image->ID()) == NULL) {
it.Remove();
if (image->TotalHits() > 0)
fOldImages.Add(image);
else
delete image;
}
}
// add new images
for (int32 i = 0; Image* image = teamImages.ItemAt(i); i++) {
if (_FindImageByID(image->ID()) == NULL)
AddImage(image);
}
}
void
Thread::_AddNewImages(ImageList& newImages, int32 event)
{
ImageList::Iterator it = newImages.GetIterator();
while (ThreadImage* image = it.Next()) {
if (image->GetImage()->CreationEvent() >= event) {
it.Remove();
fImages.Add(image);
}
}
}
void
Thread::_RemoveObsoleteImages(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;
}
}
}
ThreadImage*
Thread::_FindImageByID(image_id id) const
{
ImageList::ConstIterator it = fImages.GetIterator();
while (ThreadImage* image = it.Next()) {
if (image->ID() == id)
return image;
}
return NULL;
}

View File

@ -12,6 +12,7 @@
class Team;
class ThreadImage;
class ThreadProfileResult;
class Thread : public DoublyLinkedListLinkImpl<Thread> {
@ -24,14 +25,15 @@ public:
inline addr_t* Samples() const;
inline Team* GetTeam() const;
inline ThreadProfileResult* ProfileResult() const;
void SetProfileResult(ThreadProfileResult* result);
void UpdateInfo();
void SetSampleArea(area_id area, addr_t* samples);
void SetInterval(bigtime_t interval);
status_t AddImage(Image* image);
void ImageRemoved(Image* image);
ThreadImage* FindImage(addr_t address) const;
void AddSamples(int32 count, int32 dropped,
int32 stackDepth, bool variableStackDepth,
@ -41,25 +43,64 @@ public:
private:
typedef DoublyLinkedList<ThreadImage> ImageList;
void _SynchronizeImages();
void _AddNewImages(ImageList& newImages,
int32 event);
void _RemoveObsoleteImages(int32 event);
ThreadImage* _FindImageByID(image_id id) const;
private:
thread_info fInfo;
::Team* fTeam;
area_id fSampleArea;
addr_t* fSamples;
ThreadProfileResult* fProfileResult;
};
class ThreadProfileResult {
public:
ThreadProfileResult();
virtual ~ThreadProfileResult();
virtual status_t Init(Thread* thread);
void SetInterval(bigtime_t interval);
virtual status_t AddImage(Image* image) = 0;
virtual void SynchronizeImages(int32 event) = 0;
virtual void AddSamples(addr_t* samples,
int32 sampleCount) = 0;
virtual void AddDroppedTicks(int32 dropped) = 0;
virtual void PrintResults() = 0;
protected:
Thread* fThread;
bigtime_t fInterval;
};
class AbstractThreadProfileResult : public ThreadProfileResult {
public:
AbstractThreadProfileResult();
virtual ~AbstractThreadProfileResult();
virtual status_t Init(Thread* thread);
virtual status_t AddImage(Image* image);
virtual void SynchronizeImages(int32 event);
ThreadImage* FindImage(addr_t address) const;
virtual void AddSamples(addr_t* samples,
int32 sampleCount);
virtual void AddDroppedTicks(int32 dropped);
virtual void PrintResults();
protected:
typedef DoublyLinkedList<ThreadImage> ImageList;
ImageList fImages;
ImageList fNewImages;
ImageList fOldImages;
int64 fTotalTicks;
int64 fUnkownTicks;
int64 fDroppedTicks;
bigtime_t fInterval;
int64 fTotalSampleCount;
};
@ -95,4 +136,11 @@ Thread::GetTeam() const
}
ThreadProfileResult*
Thread::ProfileResult() const
{
return fProfileResult;
}
#endif // THREAD_H

View File

@ -123,6 +123,12 @@ public:
if (thread == NULL)
return B_NO_MEMORY;
error = _CreateThreadProfileResult(thread);
if (error != B_OK) {
delete thread;
return error;
}
error = team->InitThread(thread);
if (error != B_OK) {
delete thread;
@ -165,6 +171,24 @@ public:
return NULL;
}
private:
status_t _CreateThreadProfileResult(Thread* thread)
{
ThreadProfileResult* profileResult
= new(std::nothrow) AbstractThreadProfileResult;
if (profileResult == NULL)
return B_NO_MEMORY;
status_t error = profileResult->Init(thread);
if (error != B_OK) {
delete profileResult;
return error;
}
thread->SetProfileResult(profileResult);
return B_OK;
}
private:
BObjectList<Team> fTeams;
BObjectList<Thread> fThreads;