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:
Ingo Weinhold
2008-09-29 23:49:29 +00:00
parent 394def6bf6
commit 051fad0f92
6 changed files with 526 additions and 412 deletions
@@ -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
+1
View File
@@ -10,6 +10,7 @@ SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ;
BinCommand profile
:
BasicThreadProfileResult.cpp
Image.cpp
Team.cpp
Thread.cpp
+22 -384
View File
@@ -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
View File
@@ -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
+1
View File
@@ -23,6 +23,7 @@
#include <util/DoublyLinkedList.h>
#include "BasicThreadProfileResult.h"
#include "debug_utils.h"
#include "Image.h"
#include "Options.h"