* Made ProfileResult and ImageProfileResults BReferenceable.

* Added command line option '-S', which triggers a new summary mode. When
  enabled the image/symbol hits aren't counted for individual threads
  anymore, but summed up for all threads. The results are printed at the end.
  Works together with all profiling modes (inclusive, exclusive, callgrind).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35573 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2010-02-22 12:53:47 +00:00
parent a2ce05945a
commit 28f8887517
11 changed files with 430 additions and 52 deletions

View File

@ -220,10 +220,23 @@ BasicProfileResult::PrintResults(ImageProfileResultContainer* container)
}
ImageProfileResult*
BasicProfileResult::CreateImageProfileResult(SharedImage* image, image_id id)
status_t
BasicProfileResult::GetImageProfileResult(SharedImage* image, image_id id,
ImageProfileResult*& _imageResult)
{
return new(std::nothrow) BasicImageProfileResult(image, id);
BasicImageProfileResult* result
= new(std::nothrow) BasicImageProfileResult(image, id);
if (result == NULL)
return B_NO_MEMORY;
status_t error = result->Init();
if (error != B_OK) {
delete result;
return error;
}
_imageResult = result;
return B_OK;
}

View File

@ -16,7 +16,7 @@ public:
image_id id);
virtual ~BasicImageProfileResult();
virtual status_t Init();
status_t Init();
inline bool AddHit(addr_t address);
inline void AddUnknownHit();
@ -40,8 +40,9 @@ public:
virtual void PrintResults(
ImageProfileResultContainer* container);
virtual ImageProfileResult* CreateImageProfileResult(SharedImage* image,
image_id id);
virtual status_t GetImageProfileResult(SharedImage* image,
image_id id,
ImageProfileResult*& _imageResult);
protected:
int64 fTotalTicks;

View File

@ -262,11 +262,23 @@ CallgrindProfileResult::PrintResults(ImageProfileResultContainer* container)
}
ImageProfileResult*
CallgrindProfileResult::CreateImageProfileResult(SharedImage* image,
image_id id)
status_t
CallgrindProfileResult::GetImageProfileResult(SharedImage* image, image_id id,
ImageProfileResult*& _imageResult)
{
return new(std::nothrow) CallgrindImageProfileResult(image, id);
CallgrindImageProfileResult* result
= new(std::nothrow) CallgrindImageProfileResult(image, id);
if (result == NULL)
return B_NO_MEMORY;
status_t error = result->Init();
if (error != B_OK) {
delete result;
return error;
}
_imageResult = result;
return B_OK;
}

View File

@ -46,7 +46,7 @@ public:
image_id id);
virtual ~CallgrindImageProfileResult();
virtual status_t Init();
status_t Init();
inline void AddSymbolHit(int32 symbolIndex,
CallgrindImageProfileResult* calledImage,
@ -74,8 +74,9 @@ public:
virtual void PrintResults(
ImageProfileResultContainer* container);
virtual ImageProfileResult* CreateImageProfileResult(SharedImage* image,
image_id id);
virtual status_t GetImageProfileResult(SharedImage* image,
image_id id,
ImageProfileResult*& _imageResult);
private:
void _PrintFunction(FILE* out,

View File

@ -16,6 +16,7 @@ BinCommand profile
ProfiledEntity.cpp
ProfileResult.cpp
SharedImage.cpp
SummaryProfileResult.cpp
Team.cpp
Thread.cpp
profile.cpp

View File

@ -23,7 +23,8 @@ struct Options {
profile_loading(false),
profile_teams(true),
profile_threads(true),
analyze_full_stack(false)
analyze_full_stack(false),
summary_result(false)
{
}
@ -37,6 +38,7 @@ struct Options {
bool profile_teams;
bool profile_threads;
bool analyze_full_stack;
bool summary_result;
};

View File

@ -6,6 +6,8 @@
#define PROFILE_RESULT_H
#include <Referenceable.h>
#include <util/DoublyLinkedList.h>
#include "SharedImage.h"
@ -15,7 +17,7 @@ class ProfiledEntity;
class Team;
class ImageProfileResult {
class ImageProfileResult : public BReferenceable {
public:
ImageProfileResult(SharedImage* image,
image_id id);
@ -58,13 +60,15 @@ public:
};
class ProfileResult {
class ProfileResult : public BReferenceable {
public:
ProfileResult();
virtual ~ProfileResult();
virtual status_t Init(ProfiledEntity* entity);
ProfiledEntity* Entity() const { return fEntity; }
void SetInterval(bigtime_t interval);
virtual void AddSamples(
@ -75,8 +79,9 @@ public:
virtual void PrintResults(
ImageProfileResultContainer* container) = 0;
virtual ImageProfileResult* CreateImageProfileResult(SharedImage* image,
image_id id) = 0;
virtual status_t GetImageProfileResult(SharedImage* image,
image_id id,
ImageProfileResult*& _imageResult) = 0;
protected:
template<typename ImageProfileResultType>

View File

@ -0,0 +1,148 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "SummaryProfileResult.h"
#include <new>
// #pragma mark - SummaryImage
SummaryImage::SummaryImage(ImageProfileResult* result)
:
fResult(result)
{
fResult->AcquireReference();
}
SummaryImage::~SummaryImage()
{
fResult->ReleaseReference();
}
// #pragma mark - SummaryProfileResult
SummaryProfileResult::SummaryProfileResult(ProfileResult* result)
:
fResult(result),
fNextImageID(1)
{
fResult->AcquireReference();
}
SummaryProfileResult::~SummaryProfileResult()
{
fResult->ReleaseReference();
}
status_t
SummaryProfileResult::Init(ProfiledEntity* entity)
{
status_t error = ProfileResult::Init(entity);
if (error != B_OK)
return error;
error = fImages.Init();
if (error != B_OK)
return error;
return B_OK;
}
void
SummaryProfileResult::AddSamples(ImageProfileResultContainer* container,
addr_t* samples, int32 sampleCount)
{
fResult->AddSamples(container, samples, sampleCount);
}
void
SummaryProfileResult::AddDroppedTicks(int32 dropped)
{
fResult->AddDroppedTicks(dropped);
}
void
SummaryProfileResult::PrintResults(ImageProfileResultContainer* container)
{
// This is called for individual threads. We only print results in
// PrintSummaryResults(), though.
}
void
SummaryProfileResult::PrintSummaryResults()
{
fResult->PrintResults(this);
}
status_t
SummaryProfileResult::GetImageProfileResult(SharedImage* image, image_id id,
ImageProfileResult*& _imageResult)
{
// Check whether we do already know the image.
SummaryImage* summaryImage = fImages.Lookup(image);
if (summaryImage == NULL) {
// nope, create it
ImageProfileResult* imageResult;
status_t error = fResult->GetImageProfileResult(image, fNextImageID++,
imageResult);
if (error != B_OK)
return error;
BReference<ImageProfileResult> imageResultReference(imageResult, true);
summaryImage = new(std::nothrow) SummaryImage(imageResult);
if (summaryImage == NULL)
return B_NO_MEMORY;
fImages.Insert(summaryImage);
}
_imageResult = summaryImage->Result();
_imageResult->AcquireReference();
return B_OK;
}
int32
SummaryProfileResult::CountImages() const
{
return fImages.CountElements();
}
ImageProfileResult*
SummaryProfileResult::VisitImages(Visitor& visitor) const
{
for (ImageTable::Iterator it = fImages.GetIterator();
SummaryImage* image = it.Next();) {
if (visitor.VisitImage(image->Result()))
return image->Result();
}
return NULL;
}
ImageProfileResult*
SummaryProfileResult::FindImage(addr_t address, addr_t& _loadDelta) const
{
// We cannot and don't need to implement this. It's only relevant for
// AddSamples(), where we use the caller's container implementation.
return NULL;
}

View File

@ -0,0 +1,94 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef SUMMARY_PROFILE_RESULT_H
#define SUMMARY_PROFILE_RESULT_H
#include <util/OpenHashTable.h>
#include "ProfileResult.h"
class SummaryImage {
public:
SummaryImage(ImageProfileResult* result);
~SummaryImage();
ImageProfileResult* Result() const { return fResult; }
SharedImage* GetImage() const { return fResult->GetImage(); }
SummaryImage*& HashNext() { return fHashNext; }
private:
ImageProfileResult* fResult;
SummaryImage* fHashNext;
};
struct SummaryImageHashDefinition {
typedef SharedImage* KeyType;
typedef SummaryImage ValueType;
size_t HashKey(SharedImage* key) const
{
return (addr_t)key / (2 * sizeof(void*));
}
size_t Hash(SummaryImage* value) const
{
return HashKey(value->GetImage());
}
bool Compare(SharedImage* key, SummaryImage* value) const
{
return value->GetImage() == key;
}
SummaryImage*& GetLink(SummaryImage* value) const
{
return value->HashNext();
}
};
class SummaryProfileResult : public ProfileResult,
private ImageProfileResultContainer {
public:
SummaryProfileResult(ProfileResult* result);
virtual ~SummaryProfileResult();
virtual status_t Init(ProfiledEntity* entity);
virtual void AddSamples(
ImageProfileResultContainer* container,
addr_t* samples, int32 sampleCount);
virtual void AddDroppedTicks(int32 dropped);
virtual void PrintResults(
ImageProfileResultContainer* container);
virtual status_t GetImageProfileResult(SharedImage* image,
image_id id,
ImageProfileResult*& _imageResult);
void PrintSummaryResults();
private:
typedef BOpenHashTable<SummaryImageHashDefinition> ImageTable;
private:
// ImageProfileResultContainer
virtual int32 CountImages() const;
virtual ImageProfileResult* VisitImages(Visitor& visitor) const;
virtual ImageProfileResult* FindImage(addr_t address,
addr_t& _loadDelta) const;
private:
ProfileResult* fResult;
ImageTable fImages;
image_id fNextImageID;
};
#endif // SUMMARY_PROFILE_RESULT_H

View File

@ -27,13 +27,14 @@ ThreadImage::ThreadImage(Image* image, ImageProfileResult* result)
fResult(result)
{
fImage->AcquireReference();
fResult->AcquireReference();
}
ThreadImage::~ThreadImage()
{
fImage->ReleaseReference();
delete fResult;
fResult->ReleaseReference();
}
@ -58,7 +59,8 @@ Thread::~Thread()
if (fSampleArea >= 0)
delete_area(fSampleArea);
delete fProfileResult;
if (fProfileResult != NULL)
fProfileResult->ReleaseReference();
while (ThreadImage* image = fImages.RemoveHead())
delete image;
@ -91,8 +93,14 @@ Thread::EntityType() const
void
Thread::SetProfileResult(ProfileResult* result)
{
delete fProfileResult;
ProfileResult* oldResult = fProfileResult;
fProfileResult = result;
if (fProfileResult != NULL)
fProfileResult->AcquireReference();
if (oldResult)
oldResult->ReleaseReference();
}
@ -128,22 +136,17 @@ Thread::SetLazyImages(bool lazy)
status_t
Thread::AddImage(Image* image)
{
ImageProfileResult* result = fProfileResult->CreateImageProfileResult(
image->GetSharedImage(), image->ID());
if (result == NULL)
return B_NO_MEMORY;
status_t error = result->Init();
if (error != B_OK) {
delete result;
ImageProfileResult* result;
status_t error = fProfileResult->GetImageProfileResult(
image->GetSharedImage(), image->ID(), result);
if (error != B_OK)
return error;
}
BReference<ImageProfileResult> resultReference(result, true);
ThreadImage* threadImage = new(std::nothrow) ThreadImage(image, result);
if (threadImage == NULL) {
delete result;
if (threadImage == NULL)
return B_NO_MEMORY;
}
if (fLazyImages)
fNewImages.Add(threadImage);

View File

@ -35,6 +35,7 @@
#include "debug_utils.h"
#include "Image.h"
#include "Options.h"
#include "SummaryProfileResult.h"
#include "Team.h"
@ -84,6 +85,8 @@ static const char* kUsage =
" caller stack per tick. If the topmost address doesn't\n"
" hit a known image, the next address will be matched\n"
" (and so on).\n"
" -S - Don't output results for individual threads, but\n"
" produce a combined output at the end.\n"
" -v <directory> - Create valgrind/callgrind output. <directory> is the\n"
" directory where to put the output files.\n"
;
@ -94,22 +97,46 @@ Options gOptions;
static bool sCaughtDeadlySignal = false;
class ThreadManager {
class ThreadManager : private ProfiledEntity {
public:
ThreadManager(port_id debuggerPort)
:
fTeams(20, true),
fThreads(20, true),
fKernelTeam(NULL),
fDebuggerPort(debuggerPort)
fDebuggerPort(debuggerPort),
fSummaryProfileResult(NULL)
{
}
~ThreadManager()
virtual ~ThreadManager()
{
// release image references
for (ImageMap::iterator it = fImages.begin(); it != fImages.end(); ++it)
it->second->RemoveReference();
if (fSummaryProfileResult != NULL)
fSummaryProfileResult->ReleaseReference();
}
status_t Init()
{
if (!gOptions.summary_result)
return B_OK;
ProfileResult* profileResult;
status_t error = _CreateProfileResult(this, profileResult);
if (error != B_OK)
return error;
BReference<ProfileResult> profileResultReference(profileResult, true);
fSummaryProfileResult = new(std::nothrow) SummaryProfileResult(
profileResult);
if (fSummaryProfileResult == NULL)
return B_NO_MEMORY;
return fSummaryProfileResult->Init(profileResult->Entity());
}
status_t AddTeam(team_id teamID, Team** _team = NULL)
@ -145,7 +172,7 @@ public:
if (thread == NULL)
return B_NO_MEMORY;
status_t error = _CreateProfileResult(thread);
status_t error = _CreateThreadProfileResult(thread);
if (error != B_OK) {
delete thread;
return error;
@ -244,6 +271,28 @@ public:
}
}
void PrintSummaryResults()
{
if (fSummaryProfileResult != NULL)
fSummaryProfileResult->PrintSummaryResults();
}
private:
virtual int32 EntityID() const
{
return 1;
}
virtual const char* EntityName() const
{
return "all";
}
virtual const char* EntityType() const
{
return "summary";
}
private:
status_t _AddTeam(team_id teamID, system_profiler_team_added* addedInfo,
Team** _team = NULL)
@ -333,9 +382,28 @@ private:
return B_OK;
}
status_t _CreateProfileResult(Thread* thread)
status_t _CreateThreadProfileResult(Thread* thread)
{
if (fSummaryProfileResult != NULL) {
thread->SetProfileResult(fSummaryProfileResult);
return B_OK;
}
ProfileResult* profileResult;
status_t error = _CreateProfileResult(thread, profileResult);
if (error != B_OK)
return error;
thread->SetProfileResult(profileResult);
return B_OK;
}
status_t _CreateProfileResult(ProfiledEntity* profiledEntity,
ProfileResult*& _profileResult)
{
ProfileResult* profileResult;
if (gOptions.callgrind_directory != NULL)
profileResult = new(std::nothrow) CallgrindProfileResult;
else if (gOptions.analyze_full_stack)
@ -346,13 +414,13 @@ private:
if (profileResult == NULL)
return B_NO_MEMORY;
status_t error = profileResult->Init(thread);
if (error != B_OK) {
delete profileResult;
return error;
}
BReference<ProfileResult> profileResultReference(profileResult, true);
thread->SetProfileResult(profileResult);
status_t error = profileResult->Init(profiledEntity);
if (error != B_OK)
return error;
_profileResult = profileResultReference.Detach();
return B_OK;
}
@ -412,6 +480,7 @@ private:
ImageMap fImages;
Team* fKernelTeam;
port_id fDebuggerPort;
SummaryProfileResult* fSummaryProfileResult;
};
@ -608,6 +677,12 @@ profile_all(const char* const* programArgs, int programArgCount)
// create a thread manager
ThreadManager threadManager(-1); // TODO: We don't need a debugger port!
status_t error = threadManager.Init();
if (error != B_OK) {
fprintf(stderr, "%s: Failed to init thread manager: %s\n", kCommandName,
strerror(error));
exit(1);
}
// start profiling
system_profiler_parameters profilerParameters;
@ -618,7 +693,7 @@ profile_all(const char* const* programArgs, int programArgCount)
profilerParameters.interval = gOptions.interval;
profilerParameters.stack_depth = gOptions.stack_depth;
status_t error = _kern_system_profiler_start(&profilerParameters);
error = _kern_system_profiler_start(&profilerParameters);
if (error != B_OK) {
fprintf(stderr, "%s: Failed to start profiling: %s\n", kCommandName,
strerror(error));
@ -678,6 +753,8 @@ profile_all(const char* const* programArgs, int programArgCount)
Thread* thread = threadManager.ThreadAt(i);
thread->PrintResults();
}
threadManager.PrintSummaryResults();
}
@ -686,10 +763,10 @@ dump_recorded()
{
// retrieve recorded samples and parameters
system_profiler_parameters profilerParameters;
status_t status = _kern_system_profiler_recorded(&profilerParameters);
if (status != B_OK) {
status_t error = _kern_system_profiler_recorded(&profilerParameters);
if (error != B_OK) {
fprintf(stderr, "%s: Failed to get recorded profiling buffer: %s\n",
kCommandName, strerror(status));
kCommandName, strerror(error));
exit(1);
}
@ -699,10 +776,10 @@ dump_recorded()
// create an area for the sample buffer
area_info info;
status = get_area_info(profilerParameters.buffer_area, &info);
if (status != B_OK) {
error = get_area_info(profilerParameters.buffer_area, &info);
if (error != B_OK) {
fprintf(stderr, "%s: Recorded profiling buffer invalid: %s\n",
kCommandName, strerror(status));
kCommandName, strerror(error));
exit(1);
}
@ -714,6 +791,12 @@ dump_recorded()
// create a thread manager
ThreadManager threadManager(-1); // TODO: We don't need a debugger port!
error = threadManager.Init();
if (error != B_OK) {
fprintf(stderr, "%s: Failed to init thread manager: %s\n", kCommandName,
strerror(error));
exit(1);
}
// get the current buffer
size_t bufferStart = bufferHeader->start;
@ -736,6 +819,8 @@ dump_recorded()
Thread* thread = threadManager.ThreadAt(i);
thread->PrintResults();
}
threadManager.PrintSummaryResults();
}
@ -771,6 +856,13 @@ profile_single(const char* const* programArgs, int programArgCount)
// add team and thread to the thread manager
ThreadManager threadManager(debuggerPort);
error = threadManager.Init();
if (error != B_OK) {
fprintf(stderr, "%s: Failed to init thread manager: %s\n", kCommandName,
strerror(error));
exit(1);
}
if (threadManager.AddTeam(teamID) != B_OK
|| threadManager.AddThread(threadID) != B_OK) {
exit(1);
@ -882,6 +974,9 @@ profile_single(const char* const* programArgs, int programArgCount)
if (message.origin.thread >= 0 && message.origin.nub_port >= 0)
continue_thread(message.origin.nub_port, message.origin.thread);
}
// prints summary results
threadManager.PrintSummaryResults();
}
@ -901,7 +996,7 @@ main(int argc, const char* const* argv)
};
opterr = 0; // don't print errors
int c = getopt_long(argc, (char**)argv, "+acCfhi:klo:rs:v:",
int c = getopt_long(argc, (char**)argv, "+acCfhi:klo:rsS:v:",
sLongOptions, NULL);
if (c == -1)
break;
@ -941,6 +1036,9 @@ main(int argc, const char* const* argv)
case 's':
stackDepth = atol(optarg);
break;
case 'S':
gOptions.summary_result = true;
break;
case 'v':
gOptions.callgrind_directory = optarg;
gOptions.analyze_full_stack = true;