diff --git a/src/bin/debug/profile/BasicProfileResult.cpp b/src/bin/debug/profile/BasicProfileResult.cpp index ae3928be43..15e8fa3f85 100644 --- a/src/bin/debug/profile/BasicProfileResult.cpp +++ b/src/bin/debug/profile/BasicProfileResult.cpp @@ -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; } diff --git a/src/bin/debug/profile/BasicProfileResult.h b/src/bin/debug/profile/BasicProfileResult.h index e3cd38e54b..de159ca31a 100644 --- a/src/bin/debug/profile/BasicProfileResult.h +++ b/src/bin/debug/profile/BasicProfileResult.h @@ -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; diff --git a/src/bin/debug/profile/CallgrindProfileResult.cpp b/src/bin/debug/profile/CallgrindProfileResult.cpp index e88f858389..eec6008f00 100644 --- a/src/bin/debug/profile/CallgrindProfileResult.cpp +++ b/src/bin/debug/profile/CallgrindProfileResult.cpp @@ -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; } diff --git a/src/bin/debug/profile/CallgrindProfileResult.h b/src/bin/debug/profile/CallgrindProfileResult.h index 1517967e52..1407d0c82e 100644 --- a/src/bin/debug/profile/CallgrindProfileResult.h +++ b/src/bin/debug/profile/CallgrindProfileResult.h @@ -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, diff --git a/src/bin/debug/profile/Jamfile b/src/bin/debug/profile/Jamfile index 6b88df472a..e3f3fc2eee 100644 --- a/src/bin/debug/profile/Jamfile +++ b/src/bin/debug/profile/Jamfile @@ -16,6 +16,7 @@ BinCommand profile ProfiledEntity.cpp ProfileResult.cpp SharedImage.cpp + SummaryProfileResult.cpp Team.cpp Thread.cpp profile.cpp diff --git a/src/bin/debug/profile/Options.h b/src/bin/debug/profile/Options.h index b4cc6eaaae..eeaac04c21 100644 --- a/src/bin/debug/profile/Options.h +++ b/src/bin/debug/profile/Options.h @@ -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; }; diff --git a/src/bin/debug/profile/ProfileResult.h b/src/bin/debug/profile/ProfileResult.h index 16b8be142e..11d497baa1 100644 --- a/src/bin/debug/profile/ProfileResult.h +++ b/src/bin/debug/profile/ProfileResult.h @@ -6,6 +6,8 @@ #define PROFILE_RESULT_H +#include + #include #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 diff --git a/src/bin/debug/profile/SummaryProfileResult.cpp b/src/bin/debug/profile/SummaryProfileResult.cpp new file mode 100644 index 0000000000..3dd4f0e5fa --- /dev/null +++ b/src/bin/debug/profile/SummaryProfileResult.cpp @@ -0,0 +1,148 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "SummaryProfileResult.h" + +#include + + +// #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 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; +} diff --git a/src/bin/debug/profile/SummaryProfileResult.h b/src/bin/debug/profile/SummaryProfileResult.h new file mode 100644 index 0000000000..1f85274d8a --- /dev/null +++ b/src/bin/debug/profile/SummaryProfileResult.h @@ -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 + +#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 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 diff --git a/src/bin/debug/profile/Thread.cpp b/src/bin/debug/profile/Thread.cpp index 75ad661e88..c82608177a 100644 --- a/src/bin/debug/profile/Thread.cpp +++ b/src/bin/debug/profile/Thread.cpp @@ -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 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); diff --git a/src/bin/debug/profile/profile.cpp b/src/bin/debug/profile/profile.cpp index 412f8b27db..4f169b6076 100644 --- a/src/bin/debug/profile/profile.cpp +++ b/src/bin/debug/profile/profile.cpp @@ -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 - Create valgrind/callgrind output. 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 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 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;