From 0f3791568750bf18150d932c1e5fba2a215b9344 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 11 Apr 2009 22:59:31 +0000 Subject: [PATCH] * debug_create_symbol_lookup_context() gets a team ID instead of a debug context now. That's all it needs. * Added the option "-a" to the profile command line tool. It triggers profiling of the whole system. There are still some issues, particularly image related ones. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30129 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/debug/debug_support.h | 4 +- src/bin/debug/profile/Options.h | 4 +- src/bin/debug/profile/Team.cpp | 132 ++++++---- src/bin/debug/profile/Team.h | 14 +- src/bin/debug/profile/Thread.cpp | 16 +- src/bin/debug/profile/Thread.h | 61 ++++- src/bin/debug/profile/profile.cpp | 351 +++++++++++++++++++++++--- src/kits/debug/debug_support.cpp | 12 +- src/servers/debug/DebugServer.cpp | 5 +- 9 files changed, 481 insertions(+), 118 deletions(-) diff --git a/headers/private/debug/debug_support.h b/headers/private/debug/debug_support.h index 629c2b3201..f2f8c572a6 100644 --- a/headers/private/debug/debug_support.h +++ b/headers/private/debug/debug_support.h @@ -1,5 +1,5 @@ /* - * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. + * Copyright 2005-2009, Ingo Weinhold, bonefish@users.sf.net. * Distributed under the terms of the MIT License. */ #ifndef _DEBUG_SUPPORT_H @@ -57,7 +57,7 @@ status_t debug_get_stack_frame(debug_context *context, typedef struct debug_symbol_lookup_context debug_symbol_lookup_context; typedef struct debug_symbol_iterator debug_symbol_iterator; -status_t debug_create_symbol_lookup_context(debug_context *debugContext, +status_t debug_create_symbol_lookup_context(team_id team, debug_symbol_lookup_context **lookupContext); void debug_delete_symbol_lookup_context( debug_symbol_lookup_context *lookupContext); diff --git a/src/bin/debug/profile/Options.h b/src/bin/debug/profile/Options.h index db2dcc9dae..22f2aa6e60 100644 --- a/src/bin/debug/profile/Options.h +++ b/src/bin/debug/profile/Options.h @@ -1,5 +1,5 @@ /* - * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #ifndef OPTIONS_H @@ -17,6 +17,7 @@ struct Options { stack_depth(5), output(NULL), callgrind_directory(NULL), + profile_all(false), profile_kernel(true), profile_loading(false), profile_teams(true), @@ -29,6 +30,7 @@ struct Options { int32 stack_depth; FILE* output; const char* callgrind_directory; + bool profile_all; bool profile_kernel; bool profile_loading; bool profile_teams; diff --git a/src/bin/debug/profile/Team.cpp b/src/bin/debug/profile/Team.cpp index 3f3d19ff6f..1efb342e00 100644 --- a/src/bin/debug/profile/Team.cpp +++ b/src/bin/debug/profile/Team.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ @@ -10,12 +10,21 @@ #include #include +#include #include "debug_utils.h" #include "Options.h" +//#define TRACE_PROFILE_TEAM +#ifdef TRACE_PROFILE_TEAM +# define TRACE(x...) printf(x) +#else +# define TRACE(x...) do {} while(false) +#endif + + enum { SAMPLE_AREA_SIZE = 128 * 1024, }; @@ -71,8 +80,7 @@ Team::Init(team_id teamID, port_id debuggerPort) // create symbol lookup context debug_symbol_lookup_context* lookupContext; - error = debug_create_symbol_lookup_context(&fDebugContext, - &lookupContext); + error = debug_create_symbol_lookup_context(ID(), &lookupContext); if (error != B_OK) { fprintf(stderr, "%s: Failed to create symbol lookup context for " "team %ld: %s\n", kCommandName, teamID, strerror(error)); @@ -87,14 +95,8 @@ Team::Init(team_id teamID, port_id debuggerPort) // also try to load the kernel images and symbols if (gOptions.profile_kernel) { - // fake a debug context -- it's not really needed anyway - debug_context debugContext; - debugContext.team = B_SYSTEM_TEAM; - debugContext.nub_port = -1; - debugContext.reply_port = -1; - // create symbol lookup context - error = debug_create_symbol_lookup_context(&debugContext, + error = debug_create_symbol_lookup_context(B_SYSTEM_TEAM, &lookupContext); if (error != B_OK) { fprintf(stderr, "%s: Failed to create symbol lookup context " @@ -116,9 +118,20 @@ Team::Init(team_id teamID, port_id debuggerPort) } +status_t +Team::Init(system_profiler_team_added* addedInfo) +{ + fInfo.team = addedInfo->team; + return B_OK; +} + + status_t Team::InitThread(Thread* thread) { + // The thread + thread->ProfileResult()->SetLazyImages(!_SynchronousProfiling()); + // create the sample area char areaName[B_OS_NAME_LENGTH]; snprintf(areaName, sizeof(areaName), "profiling samples %ld", @@ -142,41 +155,47 @@ Team::InitThread(Thread* thread) return error; } - // set thread debugging flags and start profiling - int32 threadDebugFlags = 0; -// if (!traceTeam) { -// threadDebugFlags = B_THREAD_DEBUG_POST_SYSCALL -// | (traceChildThreads -// ? B_THREAD_DEBUG_SYSCALL_TRACE_CHILD_THREADS : 0); -// } - set_thread_debugging_flags(fNubPort, thread->ID(), threadDebugFlags); + if (!_SynchronousProfiling()) { + // set thread debugging flags and start profiling + int32 threadDebugFlags = 0; +// if (!traceTeam) { +// threadDebugFlags = B_THREAD_DEBUG_POST_SYSCALL +// | (traceChildThreads +// ? B_THREAD_DEBUG_SYSCALL_TRACE_CHILD_THREADS : 0); +// } + set_thread_debugging_flags(fNubPort, thread->ID(), threadDebugFlags); - // start profiling - debug_nub_start_profiler message; - message.reply_port = fDebugContext.reply_port; - message.thread = thread->ID(); - message.interval = gOptions.interval; - message.sample_area = sampleArea; - message.stack_depth = gOptions.stack_depth; - message.variable_stack_depth = gOptions.analyze_full_stack; + // start profiling + debug_nub_start_profiler message; + message.reply_port = fDebugContext.reply_port; + message.thread = thread->ID(); + message.interval = gOptions.interval; + message.sample_area = sampleArea; + message.stack_depth = gOptions.stack_depth; + message.variable_stack_depth = gOptions.analyze_full_stack; - debug_nub_start_profiler_reply reply; - status_t error = send_debug_message(&fDebugContext, - B_DEBUG_START_PROFILER, &message, sizeof(message), &reply, - sizeof(reply)); - if (error != B_OK || (error = reply.error) != B_OK) { - fprintf(stderr, "%s: Failed to start profiler for thread %ld: %s\n", - kCommandName, thread->ID(), strerror(error)); - return error; + debug_nub_start_profiler_reply reply; + status_t error = send_debug_message(&fDebugContext, + B_DEBUG_START_PROFILER, &message, sizeof(message), &reply, + sizeof(reply)); + if (error != B_OK || (error = reply.error) != B_OK) { + fprintf(stderr, "%s: Failed to start profiler for thread %ld: %s\n", + kCommandName, thread->ID(), strerror(error)); + return error; + } + + thread->SetInterval(reply.interval); + + fThreads.Add(thread); + + // resume the target thread to be sure, it's running + resume_thread(thread->ID()); + } else { + // debugger-less profiling + thread->SetInterval(gOptions.interval); + fThreads.Add(thread); } - thread->SetInterval(reply.interval); - - fThreads.Add(thread); - - // resume the target thread to be sure, it's running - resume_thread(thread->ID()); - return B_OK; } @@ -211,20 +230,19 @@ Team::Exec(int32 event) status_t -Team::AddImage(const image_info& imageInfo, int32 event) +Team::AddImage(const image_info& imageInfo, team_id owner, int32 event) { // create symbol lookup context debug_symbol_lookup_context* lookupContext; - status_t error = debug_create_symbol_lookup_context(&fDebugContext, - &lookupContext); + status_t error = debug_create_symbol_lookup_context(owner, &lookupContext); if (error != B_OK) { fprintf(stderr, "%s: Failed to create symbol lookup context for " - "team %ld: %s\n", kCommandName, ID(), strerror(error)); + "team %ld: %s\n", kCommandName, owner, strerror(error)); return error; } Image* image; - error = _LoadImageSymbols(lookupContext, imageInfo, ID(), event, + error = _LoadImageSymbols(lookupContext, imageInfo, owner, event, &image); debug_delete_symbol_lookup_context(lookupContext); @@ -242,10 +260,10 @@ Team::AddImage(const image_info& imageInfo, int32 event) status_t -Team::RemoveImage(const image_info& imageInfo, int32 event) +Team::RemoveImage(image_id imageID, int32 event) { for (int32 i = 0; Image* image = fImages.ItemAt(i); i++) { - if (image->ID() == imageInfo.id) { + if (image->ID() == imageID) { _RemoveImage(i, event); return B_OK; } @@ -295,10 +313,14 @@ Team::_LoadImageSymbols(debug_symbol_lookup_context* lookupContext, status_t error = image->LoadSymbols(lookupContext); if (error != B_OK) { + TRACE("Failed to load symbols of image %ld: %s\n", image->ID(), + strerror(error)); delete image; return error; } + TRACE("image %ld: loaded %ld symbols\n", image->ID(), image->SymbolCount()); + if (!fImages.AddItem(image)) { delete image; return B_NO_MEMORY; @@ -318,10 +340,16 @@ Team::_RemoveImage(int32 index, int32 event) if (image == NULL) return; - // Note: We don't tell the threads that the image has been removed. They - // will be updated lazily when their next profiler update arrives. This - // is necessary, since the update might contain samples hitting that - // image. + if (_SynchronousProfiling()) { + ThreadList::Iterator it = fThreads.GetIterator(); + while (Thread* thread = it.Next()) + thread->ProfileResult()->RemoveImage(image); + } else { + // Note: We don't tell the threads that the image has been removed. They + // will be updated lazily when their next profiler update arrives. This + // is necessary, since the update might contain samples hitting that + // image. + } image->SetDeletionEvent(event); image->RemoveReference(); diff --git a/src/bin/debug/profile/Team.h b/src/bin/debug/profile/Team.h index 1fd152b94e..60773ad4a4 100644 --- a/src/bin/debug/profile/Team.h +++ b/src/bin/debug/profile/Team.h @@ -1,5 +1,5 @@ /* - * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #ifndef TEAM_H @@ -12,12 +12,16 @@ #include "Thread.h" +struct system_profiler_team_added; + + class Team { public: Team(); ~Team(); status_t Init(team_id teamID, port_id debuggerPort); + status_t Init(system_profiler_team_added* addedInfo); status_t InitThread(Thread* thread); void RemoveThread(Thread* thread); @@ -25,9 +29,8 @@ public: void Exec(int32 event); status_t AddImage(const image_info& imageInfo, - int32 event); - status_t RemoveImage(const image_info& imageInfo, - int32 event); + team_id owner, int32 event); + status_t RemoveImage(image_id imageID, int32 event); inline const BObjectList& Images() const; Image* FindImage(image_id id) const; @@ -44,6 +47,9 @@ private: int32 event, Image** _image = NULL); void _RemoveImage(int32 index, int32 event); + bool _SynchronousProfiling() const + { return fDebugContext.nub_port < 0; } + private: typedef DoublyLinkedList ThreadList; diff --git a/src/bin/debug/profile/Thread.cpp b/src/bin/debug/profile/Thread.cpp index 4381a45d37..05a923fe01 100644 --- a/src/bin/debug/profile/Thread.cpp +++ b/src/bin/debug/profile/Thread.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ @@ -96,13 +96,6 @@ Thread::SetInterval(bigtime_t interval) } -status_t -Thread::AddImage(Image* image) -{ - return fProfileResult->AddImage(image); -} - - void Thread::AddSamples(int32 count, int32 dropped, int32 stackDepth, bool variableStackDepth, int32 event) @@ -146,6 +139,13 @@ Thread::AddSamples(int32 count, int32 dropped, int32 stackDepth, } +void +Thread::AddSamples(addr_t* samples, int32 sampleCount) +{ + fProfileResult->AddSamples(samples, sampleCount); +} + + void Thread::PrintResults() const { diff --git a/src/bin/debug/profile/Thread.h b/src/bin/debug/profile/Thread.h index 26a4437ba5..5ade241db8 100644 --- a/src/bin/debug/profile/Thread.h +++ b/src/bin/debug/profile/Thread.h @@ -1,5 +1,5 @@ /* - * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #ifndef THREAD_H @@ -53,11 +53,13 @@ public: void SetSampleArea(area_id area, addr_t* samples); void SetInterval(bigtime_t interval); - status_t AddImage(Image* image); + inline status_t AddImage(Image* image); + inline void RemoveImage(Image* image); void AddSamples(int32 count, int32 dropped, int32 stackDepth, bool variableStackDepth, int32 event); + void AddSamples(addr_t* samples, int32 sampleCount); void PrintResults() const; private: @@ -81,7 +83,10 @@ public: void SetInterval(bigtime_t interval); + virtual void SetLazyImages(bool lazy) = 0; + virtual status_t AddImage(Image* image) = 0; + virtual void RemoveImage(Image* image) = 0; virtual void SynchronizeImages(int32 event) = 0; virtual void AddSamples(addr_t* samples, @@ -101,7 +106,10 @@ public: AbstractThreadProfileResult(); virtual ~AbstractThreadProfileResult(); + virtual void SetLazyImages(bool lazy); + virtual status_t AddImage(Image* image); + virtual void RemoveImage(Image* image); virtual void SynchronizeImages(int32 event); ThreadImageType* FindImage(addr_t address) const; @@ -120,6 +128,7 @@ protected: ImageList fImages; ImageList fNewImages; ImageList fOldImages; + bool fLazyImages; }; @@ -192,6 +201,20 @@ Thread::ProfileResult() const } +status_t +Thread::AddImage(Image* image) +{ + return fProfileResult->AddImage(image); +} + + +void +Thread::RemoveImage(Image* image) +{ + fProfileResult->RemoveImage(image); +} + + // #pragma mark - AbstractThreadProfileResult @@ -200,7 +223,8 @@ AbstractThreadProfileResult::AbstractThreadProfileResult() : fImages(), fNewImages(), - fOldImages() + fOldImages(), + fLazyImages(true) { } @@ -215,6 +239,14 @@ AbstractThreadProfileResult::~AbstractThreadProfileResult() } +template +void +AbstractThreadProfileResult::SetLazyImages(bool lazy) +{ + fLazyImages = lazy; +} + + template status_t AbstractThreadProfileResult::AddImage(Image* image) @@ -229,12 +261,33 @@ AbstractThreadProfileResult::AddImage(Image* image) return error; } - fNewImages.Add(threadImage); + if (fLazyImages) + fNewImages.Add(threadImage); + else + fImages.Add(threadImage); return B_OK; } +template +void +AbstractThreadProfileResult::RemoveImage(Image* image) +{ + typename ImageList::Iterator it = fImages.GetIterator(); + while (ThreadImageType* threadImage = it.Next()) { + if (threadImage->GetImage() == image) { + it.Remove(); + if (threadImage->TotalHits() > 0) + fOldImages.Add(threadImage); + else + delete threadImage; + break; + } + } +} + + template void AbstractThreadProfileResult::SynchronizeImages(int32 event) diff --git a/src/bin/debug/profile/profile.cpp b/src/bin/debug/profile/profile.cpp index 03e54c0827..918c69ed41 100644 --- a/src/bin/debug/profile/profile.cpp +++ b/src/bin/debug/profile/profile.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ @@ -17,6 +17,9 @@ #include #include +#include +#include + #include #include #include @@ -31,6 +34,10 @@ #include "Team.h" +// size of the sample buffer area for system profiling +#define PROFILE_ALL_SAMPLE_AREA_SIZE (4 * 1024 * 1024) + + extern const char* __progname; const char* kCommandName = __progname; @@ -41,12 +48,15 @@ class Thread; static const char* kUsage = - "Usage: %s [ ] \n" - "Executes the given command line and periodically samples\n" - "all started threads' program counters. When a thread terminates, a list\n" - "of the functions where the thread was encountered is printed.\n" + "Usage: %s [ ] [ ]\n" + "Profiles threads by periodically sampling the program counter. There are\n" + "two different modes: One profiles the complete system. The other starts\n" + "a program and profiles that and (optionally) its children. When a thread\n" + "terminates, a list of the functions where the thread was encountered is\n" + "printed.\n" "\n" "Options:\n" + " -a, --all - Profile all teams.\n" " -c - Don't profile child threads. Default is to\n" " recursively profile all threads created by a profiled\n" " thread.\n" @@ -75,6 +85,8 @@ static const char* kUsage = Options gOptions; +static bool sCaughtDeadlySignal = false; + class ThreadManager { public: @@ -88,25 +100,12 @@ public: status_t AddTeam(team_id teamID, Team** _team = NULL) { - if (FindTeam(teamID) != NULL) - return B_BAD_VALUE; + return _AddTeam(teamID, NULL, _team); + } - Team* team = new(std::nothrow) Team; - if (team == NULL) - return B_NO_MEMORY; - - status_t error = team->Init(teamID, fDebuggerPort); - if (error != B_OK) { - delete team; - return error; - } - - fTeams.AddItem(team); - - if (_team != NULL) - *_team = team; - - return B_OK; + status_t AddTeam(system_profiler_team_added* addedInfo, Team** _team = NULL) + { + return _AddTeam(addedInfo->team, addedInfo, _team); } status_t AddThread(thread_id threadID) @@ -175,7 +174,73 @@ public: return NULL; } + int32 CountThreads() const + { + return fThreads.CountItems(); + } + + Thread* ThreadAt(int32 index) const + { + return fThreads.ItemAt(index); + } + + status_t AddImage(team_id teamID, const image_info& imageInfo, int32 event) + { + if (teamID == B_SYSTEM_TEAM) { + // a kernel image -- add it to all teams + int32 count = fTeams.CountItems(); + for (int32 i = 0; i < count; i++) + fTeams.ItemAt(i)->AddImage(imageInfo, teamID, event); + } + + // a userland team image -- add it to that image + if (Team* team = FindTeam(teamID)) + return team->AddImage(imageInfo, teamID, event); + + return B_BAD_TEAM_ID; + } + + void RemoveImage(team_id teamID, image_id imageID, int32 event) + { + if (teamID == B_SYSTEM_TEAM) { + // a kernel image -- remove it from all teams + int32 count = fTeams.CountItems(); + for (int32 i = 0; i < count; i++) + fTeams.ItemAt(i)->RemoveImage(imageID, event); + } else { + // a userland team image -- add it to that image + if (Team* team = FindTeam(teamID)) + team->RemoveImage(imageID, event); + } + } + private: + status_t _AddTeam(team_id teamID, system_profiler_team_added* addedInfo, + Team** _team = NULL) + { + if (FindTeam(teamID) != NULL) + return B_BAD_VALUE; + + Team* team = new(std::nothrow) Team; + if (team == NULL) + return B_NO_MEMORY; + + status_t error = addedInfo != NULL + ? team->Init(addedInfo) + : team->Init(teamID, fDebuggerPort); + if (error != B_OK) { + delete team; + return error; + } + + fTeams.AddItem(team); + + if (_team != NULL) + *_team = team; + + return B_OK; + } + status_t _CreateThreadProfileResult(Thread* thread) { ThreadProfileResult* profileResult; @@ -231,6 +296,211 @@ get_id(const char *str, int32 &id) */ +static void +process_event_buffer(ThreadManager& threadManager, uint8* buffer, + size_t bufferSize) +{ +//printf("process_event_buffer(%p, %lu)\n", buffer, bufferSize); + const uint8* bufferEnd = buffer + bufferSize; + + while (buffer < bufferEnd) { + system_profiler_event_header* header + = (system_profiler_event_header*)buffer; + + buffer += sizeof(system_profiler_event_header); + + switch (header->event) { + case B_SYSTEM_PROFILER_TEAM_ADDED: + { + system_profiler_team_added* event + = (system_profiler_team_added*)buffer; + + threadManager.AddTeam(event); +// TODO: ATM we're not adding kernel images to the team, if this is a team +// created after we started profiling! + break; + } + + case B_SYSTEM_PROFILER_TEAM_REMOVED: + { + system_profiler_team_removed* event + = (system_profiler_team_removed*)buffer; + + // TODO: Print results! + threadManager.RemoveTeam(event->team); + break; + } + + case B_SYSTEM_PROFILER_TEAM_EXEC: + { + system_profiler_team_exec* event + = (system_profiler_team_exec*)event; + + if (Team* team = threadManager.FindTeam(event->team)) + team->Exec(0); + break; + } + + case B_SYSTEM_PROFILER_THREAD_ADDED: + { + system_profiler_thread_added* event + = (system_profiler_thread_added*)buffer; + + threadManager.AddThread(event->thread); + break; + } + + case B_SYSTEM_PROFILER_THREAD_REMOVED: + { + system_profiler_thread_removed* event + = (system_profiler_thread_removed*)buffer; + + if (Thread* thread = threadManager.FindThread(event->thread)) { + thread->PrintResults(); + threadManager.RemoveThread(event->thread); + } + break; + } + + case B_SYSTEM_PROFILER_IMAGE_ADDED: + { + system_profiler_image_added* event + = (system_profiler_image_added*)buffer; + + threadManager.AddImage(event->team, event->info, 0); + break; + } + + case B_SYSTEM_PROFILER_IMAGE_REMOVED: + { + system_profiler_image_removed* event + = (system_profiler_image_removed*)buffer; + + threadManager.RemoveImage(event->team, event->image, 0); + break; + } + + case B_SYSTEM_PROFILER_SAMPLES: + { + system_profiler_samples* event + = (system_profiler_samples*)buffer; + + Thread* thread = threadManager.FindThread(event->thread); + if (thread != NULL) { + thread->AddSamples(event->samples, + (addr_t*)(buffer + header->size) - event->samples); + } + + break; + } + + case B_SYSTEM_PROFILER_SAMPLES_END: + { + // Marks the end of the ring buffer -- we need to ignore the + // remaining bytes. + return; + } + } + + buffer += header->size; + } +} + + +static void +signal_handler(int signal, void* data) +{ + sCaughtDeadlySignal = true; +} + + +static void +profile_all() +{ + // install signal handlers so we can exit gracefully + struct sigaction action; + action.sa_handler = (sighandler_t)signal_handler; + sigemptyset(&action.sa_mask); + action.sa_userdata = NULL; + if (sigaction(SIGHUP, &action, NULL) < 0 + || sigaction(SIGINT, &action, NULL) < 0 + || sigaction(SIGQUIT, &action, NULL) < 0) { + fprintf(stderr, "%s: Failed to install signal handlers: %s\n", + kCommandName, strerror(errno)); + exit(1); + } + + // create and area for the sample buffer + system_profiler_buffer_header* bufferHeader; + area_id area = create_area("profiling buffer", (void**)&bufferHeader, + B_ANY_ADDRESS, PROFILE_ALL_SAMPLE_AREA_SIZE, B_NO_LOCK, B_READ_AREA); + if (area < 0) { + fprintf(stderr, "%s: Failed to create sample area: %s\n", kCommandName, + strerror(area)); + exit(1); + } + + uint8* bufferBase = (uint8*)(bufferHeader + 1); + size_t totalBufferSize = PROFILE_ALL_SAMPLE_AREA_SIZE + - (bufferBase - (uint8*)bufferHeader); + + // create a thread manager + ThreadManager threadManager(-1); // TODO: We don't need a debugger port! + + // start profiling + status_t error = _kern_system_profiler_start(area, gOptions.interval, + gOptions.stack_depth); + if (error != B_OK) { + fprintf(stderr, "%s: Failed to start profiling: %s\n", kCommandName, + strerror(error)); + exit(1); + } + + // main event loop + while (true) { + // get the current buffer + size_t bufferStart = bufferHeader->start; + size_t bufferSize = bufferHeader->size; + uint8* buffer = bufferBase + bufferStart; +//printf("processing buffer of size %lu bytes\n", bufferSize); + + if (bufferStart + bufferSize <= totalBufferSize) { + process_event_buffer(threadManager, buffer, bufferSize); + } else { + size_t remainingSize = bufferStart + bufferSize - totalBufferSize; + process_event_buffer(threadManager, buffer, + bufferSize - remainingSize); + process_event_buffer(threadManager, bufferBase, remainingSize); + } + + // get next buffer + error = _kern_system_profiler_next_buffer(bufferSize); + + if (error != B_OK) { + if (error == B_INTERRUPTED) { + if (sCaughtDeadlySignal) + break; + continue; + } + + fprintf(stderr, "%s: Failed to get next sample buffer: %s\n", + kCommandName, strerror(error)); + break; + } + } + + // stop profiling + _kern_system_profiler_stop(); + + // print results + int32 threadCount = threadManager.CountThreads(); + for (int32 i = 0; i < threadCount; i++) { + Thread* thread = threadManager.ThreadAt(i); + thread->PrintResults(); + } +} + + int main(int argc, const char* const* argv) { @@ -239,17 +509,21 @@ main(int argc, const char* const* argv) while (true) { static struct option sLongOptions[] = { + { "all", no_argument, 0, 'a' }, { "help", no_argument, 0, 'h' }, { 0, 0, 0, 0 } }; opterr = 0; // don't print errors - int c = getopt_long(argc, (char**)argv, "+cCfhi:klo:s:v:", sLongOptions, - NULL); + int c = getopt_long(argc, (char**)argv, "+acCfhi:klo:s:v:", + sLongOptions, NULL); if (c == -1) break; switch (c) { + case 'a': + gOptions.profile_all = true; + break; case 'c': gOptions.profile_threads = false; break; @@ -289,15 +563,12 @@ main(int argc, const char* const* argv) } } - if (optind >= argc) + if (!gOptions.profile_all && optind >= argc) print_usage_and_exit(true); if (stackDepth != 0) gOptions.stack_depth = stackDepth; - const char* const* programArgs = argv + optind; - int programArgCount = argc - optind; - if (outputFile != NULL) { gOptions.output = fopen(outputFile, "w+"); if (gOptions.output == NULL) { @@ -308,6 +579,14 @@ main(int argc, const char* const* argv) } else gOptions.output = stdout; + if (gOptions.profile_all) { + profile_all(); + return 0; + } + + const char* const* programArgs = argv + optind; + int programArgCount = argc - optind; + // get thread/team to be debugged thread_id threadID = -1; team_id teamID = -1; @@ -417,16 +696,14 @@ main(int argc, const char* const* argv) break; case B_DEBUGGER_MESSAGE_IMAGE_CREATED: - if (Team* team = threadManager.FindTeam(message.origin.team)) { - team->AddImage(message.image_created.info, - message.image_created.image_event); - } + threadManager.AddImage(message.origin.team, + message.image_created.info, + message.image_created.image_event); break; case B_DEBUGGER_MESSAGE_IMAGE_DELETED: - if (Team* team = threadManager.FindTeam(message.origin.team)) { - team->RemoveImage(message.image_deleted.info, - message.image_deleted.image_event); - } + threadManager.RemoveImage(message.origin.team, + message.image_deleted.info.id, + message.image_deleted.image_event); break; case B_DEBUGGER_MESSAGE_POST_SYSCALL: diff --git a/src/kits/debug/debug_support.cpp b/src/kits/debug/debug_support.cpp index f7a212ca24..8be1d9d37e 100644 --- a/src/kits/debug/debug_support.cpp +++ b/src/kits/debug/debug_support.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ @@ -18,8 +18,7 @@ using std::nothrow; struct debug_symbol_lookup_context { - debug_context context; - SymbolLookup *lookup; + SymbolLookup* lookup; }; struct debug_symbol_iterator : BPrivate::SymbolIterator { @@ -266,20 +265,19 @@ debug_get_stack_frame(debug_context *context, void *stackFrameAddress, // debug_create_symbol_lookup_context status_t -debug_create_symbol_lookup_context(debug_context *debugContext, +debug_create_symbol_lookup_context(team_id team, debug_symbol_lookup_context **_lookupContext) { - if (!debugContext || !_lookupContext) + if (team < 0 || !_lookupContext) return B_BAD_VALUE; // create the lookup context debug_symbol_lookup_context *lookupContext = new(nothrow) debug_symbol_lookup_context; - lookupContext->context = *debugContext; ObjectDeleter contextDeleter(lookupContext); // create and init symbol lookup - SymbolLookup *lookup = new(nothrow) SymbolLookup(debugContext->team); + SymbolLookup *lookup = new(nothrow) SymbolLookup(team); if (!lookup) return B_NO_MEMORY; diff --git a/src/servers/debug/DebugServer.cpp b/src/servers/debug/DebugServer.cpp index c33a581230..04a2bbe685 100644 --- a/src/servers/debug/DebugServer.cpp +++ b/src/servers/debug/DebugServer.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006, Ingo Weinhold, bonefish@users.sf.net. + * Copyright 2005-2009, Ingo Weinhold, bonefish@users.sf.net. * Distributed under the terms of the MIT License. */ @@ -644,8 +644,7 @@ TeamDebugHandler::_PrintStackTrace(thread_id thread) if (error == B_OK) { // create a symbol lookup context debug_symbol_lookup_context *lookupContext = NULL; - error = debug_create_symbol_lookup_context(&fDebugContext, - &lookupContext); + error = debug_create_symbol_lookup_context(fTeam, &lookupContext); if (error != B_OK) { debug_printf("debug_server: Failed to create symbol lookup " "context: %s\n", strerror(error));