Author: bonefish Date: 2010-02-22 13:53:47 +0100 (Mon, 22 Feb 2010) New Revision: 35573 Changeset: http://dev.haiku-os.org/changeset/35573/haiku Added: haiku/trunk/src/bin/debug/profile/SummaryProfileResult.cpp haiku/trunk/src/bin/debug/profile/SummaryProfileResult.h Modified: haiku/trunk/src/bin/debug/profile/BasicProfileResult.cpp haiku/trunk/src/bin/debug/profile/BasicProfileResult.h haiku/trunk/src/bin/debug/profile/CallgrindProfileResult.cpp haiku/trunk/src/bin/debug/profile/CallgrindProfileResult.h haiku/trunk/src/bin/debug/profile/Jamfile haiku/trunk/src/bin/debug/profile/Options.h haiku/trunk/src/bin/debug/profile/ProfileResult.h haiku/trunk/src/bin/debug/profile/Thread.cpp haiku/trunk/src/bin/debug/profile/profile.cpp Log: * 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). Modified: haiku/trunk/src/bin/debug/profile/BasicProfileResult.cpp =================================================================== --- haiku/trunk/src/bin/debug/profile/BasicProfileResult.cpp 2010-02-22 08:25:35 UTC (rev 35572) +++ haiku/trunk/src/bin/debug/profile/BasicProfileResult.cpp 2010-02-22 12:53:47 UTC (rev 35573) @@ -220,10 +220,23 @@ } -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; } Modified: haiku/trunk/src/bin/debug/profile/BasicProfileResult.h =================================================================== --- haiku/trunk/src/bin/debug/profile/BasicProfileResult.h 2010-02-22 08:25:35 UTC (rev 35572) +++ haiku/trunk/src/bin/debug/profile/BasicProfileResult.h 2010-02-22 12:53:47 UTC (rev 35573) @@ -16,7 +16,7 @@ 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 @@ 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; Modified: haiku/trunk/src/bin/debug/profile/CallgrindProfileResult.cpp =================================================================== --- haiku/trunk/src/bin/debug/profile/CallgrindProfileResult.cpp 2010-02-22 08:25:35 UTC (rev 35572) +++ haiku/trunk/src/bin/debug/profile/CallgrindProfileResult.cpp 2010-02-22 12:53:47 UTC (rev 35573) @@ -262,11 +262,23 @@ } -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; } Modified: haiku/trunk/src/bin/debug/profile/CallgrindProfileResult.h =================================================================== --- haiku/trunk/src/bin/debug/profile/CallgrindProfileResult.h 2010-02-22 08:25:35 UTC (rev 35572) +++ haiku/trunk/src/bin/debug/profile/CallgrindProfileResult.h 2010-02-22 12:53:47 UTC (rev 35573) @@ -46,7 +46,7 @@ image_id id); virtual ~CallgrindImageProfileResult(); - virtual status_t Init(); + status_t Init(); inline void AddSymbolHit(int32 symbolIndex, CallgrindImageProfileResult* calledImage, @@ -74,8 +74,9 @@ 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, Modified: haiku/trunk/src/bin/debug/profile/Jamfile =================================================================== --- haiku/trunk/src/bin/debug/profile/Jamfile 2010-02-22 08:25:35 UTC (rev 35572) +++ haiku/trunk/src/bin/debug/profile/Jamfile 2010-02-22 12:53:47 UTC (rev 35573) @@ -16,6 +16,7 @@ ProfiledEntity.cpp ProfileResult.cpp SharedImage.cpp + SummaryProfileResult.cpp Team.cpp Thread.cpp profile.cpp Modified: haiku/trunk/src/bin/debug/profile/Options.h =================================================================== --- haiku/trunk/src/bin/debug/profile/Options.h 2010-02-22 08:25:35 UTC (rev 35572) +++ haiku/trunk/src/bin/debug/profile/Options.h 2010-02-22 12:53:47 UTC (rev 35573) @@ -23,7 +23,8 @@ profile_loading(false), profile_teams(true), profile_threads(true), - analyze_full_stack(false) + analyze_full_stack(false), + summary_result(false) { } @@ -37,6 +38,7 @@ bool profile_teams; bool profile_threads; bool analyze_full_stack; + bool summary_result; }; Modified: haiku/trunk/src/bin/debug/profile/ProfileResult.h =================================================================== --- haiku/trunk/src/bin/debug/profile/ProfileResult.h 2010-02-22 08:25:35 UTC (rev 35572) +++ haiku/trunk/src/bin/debug/profile/ProfileResult.h 2010-02-22 12:53:47 UTC (rev 35573) @@ -6,6 +6,8 @@ #define PROFILE_RESULT_H +#include <Referenceable.h> + #include <util/DoublyLinkedList.h> #include "SharedImage.h" @@ -15,7 +17,7 @@ class Team; -class ImageProfileResult { +class ImageProfileResult : public BReferenceable { public: ImageProfileResult(SharedImage* image, image_id id); @@ -58,13 +60,15 @@ }; -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 @@ 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> Added: haiku/trunk/src/bin/debug/profile/SummaryProfileResult.cpp =================================================================== --- haiku/trunk/src/bin/debug/profile/SummaryProfileResult.cpp (rev 0) +++ haiku/trunk/src/bin/debug/profile/SummaryProfileResult.cpp 2010-02-22 12:53:47 UTC (rev 35573) @@ -0,0 +1,148 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@xxxxxxx + * 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; +} Added: haiku/trunk/src/bin/debug/profile/SummaryProfileResult.h =================================================================== --- haiku/trunk/src/bin/debug/profile/SummaryProfileResult.h (rev 0) +++ haiku/trunk/src/bin/debug/profile/SummaryProfileResult.h 2010-02-22 12:53:47 UTC (rev 35573) @@ -0,0 +1,94 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@xxxxxxx + * 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 Modified: haiku/trunk/src/bin/debug/profile/Thread.cpp =================================================================== --- haiku/trunk/src/bin/debug/profile/Thread.cpp 2010-02-22 08:25:35 UTC (rev 35572) +++ haiku/trunk/src/bin/debug/profile/Thread.cpp 2010-02-22 12:53:47 UTC (rev 35573) @@ -27,13 +27,14 @@ fResult(result) { fImage->AcquireReference(); + fResult->AcquireReference(); } ThreadImage::~ThreadImage() { fImage->ReleaseReference(); - delete fResult; + fResult->ReleaseReference(); } @@ -58,7 +59,8 @@ if (fSampleArea >= 0) delete_area(fSampleArea); - delete fProfileResult; + if (fProfileResult != NULL) + fProfileResult->ReleaseReference(); while (ThreadImage* image = fImages.RemoveHead()) delete image; @@ -91,8 +93,14 @@ 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 @@ 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); Modified: haiku/trunk/src/bin/debug/profile/profile.cpp =================================================================== --- haiku/trunk/src/bin/debug/profile/profile.cpp 2010-02-22 08:25:35 UTC (rev 35572) +++ haiku/trunk/src/bin/debug/profile/profile.cpp 2010-02-22 12:53:47 UTC (rev 35573) @@ -35,6 +35,7 @@ #include "debug_utils.h" #include "Image.h" #include "Options.h" +#include "SummaryProfileResult.h" #include "Team.h" @@ -84,6 +85,8 @@ " 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,24 +97,48 @@ 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) { return _AddTeam(teamID, NULL, _team); @@ -145,7 +172,7 @@ 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,7 +271,29 @@ } } + 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 @@ 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 @@ if (profileResult == NULL) return B_NO_MEMORY; - status_t error = profileResult->Init(thread); - if (error != B_OK) { - delete profileResult; + BReference<ProfileResult> profileResultReference(profileResult, true); + + status_t error = profileResult->Init(profiledEntity); + if (error != B_OK) return error; - } - thread->SetProfileResult(profileResult); + _profileResult = profileResultReference.Detach(); return B_OK; } @@ -412,6 +480,7 @@ ImageMap fImages; Team* fKernelTeam; port_id fDebuggerPort; + SummaryProfileResult* fSummaryProfileResult; }; @@ -608,6 +677,12 @@ // 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 @@ 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 @@ Thread* thread = threadManager.ThreadAt(i); thread->PrintResults(); } + + threadManager.PrintSummaryResults(); } @@ -686,10 +763,10 @@ { // 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 @@ // 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 @@ // 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 @@ Thread* thread = threadManager.ThreadAt(i); thread->PrintResults(); } + + threadManager.PrintSummaryResults(); } @@ -771,6 +856,13 @@ // 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 @@ 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 @@ }; 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 @@ case 's': stackDepth = atol(optarg); break; + case 'S': + gOptions.summary_result = true; + break; case 'v': gOptions.callgrind_directory = optarg; gOptions.analyze_full_stack = true;