* 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
This commit is contained in:
Ingo Weinhold 2009-04-11 22:59:31 +00:00
parent 2ad2768adc
commit 0f37915687
9 changed files with 481 additions and 118 deletions

View File

@ -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. * Distributed under the terms of the MIT License.
*/ */
#ifndef _DEBUG_SUPPORT_H #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_lookup_context debug_symbol_lookup_context;
typedef struct debug_symbol_iterator debug_symbol_iterator; 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); debug_symbol_lookup_context **lookupContext);
void debug_delete_symbol_lookup_context( void debug_delete_symbol_lookup_context(
debug_symbol_lookup_context *lookupContext); debug_symbol_lookup_context *lookupContext);

View File

@ -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. * Distributed under the terms of the MIT License.
*/ */
#ifndef OPTIONS_H #ifndef OPTIONS_H
@ -17,6 +17,7 @@ struct Options {
stack_depth(5), stack_depth(5),
output(NULL), output(NULL),
callgrind_directory(NULL), callgrind_directory(NULL),
profile_all(false),
profile_kernel(true), profile_kernel(true),
profile_loading(false), profile_loading(false),
profile_teams(true), profile_teams(true),
@ -29,6 +30,7 @@ struct Options {
int32 stack_depth; int32 stack_depth;
FILE* output; FILE* output;
const char* callgrind_directory; const char* callgrind_directory;
bool profile_all;
bool profile_kernel; bool profile_kernel;
bool profile_loading; bool profile_loading;
bool profile_teams; bool profile_teams;

View File

@ -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. * Distributed under the terms of the MIT License.
*/ */
@ -10,12 +10,21 @@
#include <image.h> #include <image.h>
#include <debug_support.h> #include <debug_support.h>
#include <system_profiler_defs.h>
#include "debug_utils.h" #include "debug_utils.h"
#include "Options.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 { enum {
SAMPLE_AREA_SIZE = 128 * 1024, SAMPLE_AREA_SIZE = 128 * 1024,
}; };
@ -71,8 +80,7 @@ Team::Init(team_id teamID, port_id debuggerPort)
// create symbol lookup context // create symbol lookup context
debug_symbol_lookup_context* lookupContext; debug_symbol_lookup_context* lookupContext;
error = debug_create_symbol_lookup_context(&fDebugContext, error = debug_create_symbol_lookup_context(ID(), &lookupContext);
&lookupContext);
if (error != B_OK) { if (error != B_OK) {
fprintf(stderr, "%s: Failed to create symbol lookup context for " fprintf(stderr, "%s: Failed to create symbol lookup context for "
"team %ld: %s\n", kCommandName, teamID, strerror(error)); "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 // also try to load the kernel images and symbols
if (gOptions.profile_kernel) { 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 // create symbol lookup context
error = debug_create_symbol_lookup_context(&debugContext, error = debug_create_symbol_lookup_context(B_SYSTEM_TEAM,
&lookupContext); &lookupContext);
if (error != B_OK) { if (error != B_OK) {
fprintf(stderr, "%s: Failed to create symbol lookup context " 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 status_t
Team::InitThread(Thread* thread) Team::InitThread(Thread* thread)
{ {
// The thread
thread->ProfileResult()->SetLazyImages(!_SynchronousProfiling());
// create the sample area // create the sample area
char areaName[B_OS_NAME_LENGTH]; char areaName[B_OS_NAME_LENGTH];
snprintf(areaName, sizeof(areaName), "profiling samples %ld", snprintf(areaName, sizeof(areaName), "profiling samples %ld",
@ -142,41 +155,47 @@ Team::InitThread(Thread* thread)
return error; return error;
} }
// set thread debugging flags and start profiling if (!_SynchronousProfiling()) {
int32 threadDebugFlags = 0; // set thread debugging flags and start profiling
// if (!traceTeam) { int32 threadDebugFlags = 0;
// threadDebugFlags = B_THREAD_DEBUG_POST_SYSCALL // if (!traceTeam) {
// | (traceChildThreads // threadDebugFlags = B_THREAD_DEBUG_POST_SYSCALL
// ? B_THREAD_DEBUG_SYSCALL_TRACE_CHILD_THREADS : 0); // | (traceChildThreads
// } // ? B_THREAD_DEBUG_SYSCALL_TRACE_CHILD_THREADS : 0);
set_thread_debugging_flags(fNubPort, thread->ID(), threadDebugFlags); // }
set_thread_debugging_flags(fNubPort, thread->ID(), threadDebugFlags);
// start profiling // start profiling
debug_nub_start_profiler message; debug_nub_start_profiler message;
message.reply_port = fDebugContext.reply_port; message.reply_port = fDebugContext.reply_port;
message.thread = thread->ID(); message.thread = thread->ID();
message.interval = gOptions.interval; message.interval = gOptions.interval;
message.sample_area = sampleArea; message.sample_area = sampleArea;
message.stack_depth = gOptions.stack_depth; message.stack_depth = gOptions.stack_depth;
message.variable_stack_depth = gOptions.analyze_full_stack; message.variable_stack_depth = gOptions.analyze_full_stack;
debug_nub_start_profiler_reply reply; debug_nub_start_profiler_reply reply;
status_t error = send_debug_message(&fDebugContext, status_t error = send_debug_message(&fDebugContext,
B_DEBUG_START_PROFILER, &message, sizeof(message), &reply, B_DEBUG_START_PROFILER, &message, sizeof(message), &reply,
sizeof(reply)); sizeof(reply));
if (error != B_OK || (error = reply.error) != B_OK) { if (error != B_OK || (error = reply.error) != B_OK) {
fprintf(stderr, "%s: Failed to start profiler for thread %ld: %s\n", fprintf(stderr, "%s: Failed to start profiler for thread %ld: %s\n",
kCommandName, thread->ID(), strerror(error)); kCommandName, thread->ID(), strerror(error));
return 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; return B_OK;
} }
@ -211,20 +230,19 @@ Team::Exec(int32 event)
status_t 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 // create symbol lookup context
debug_symbol_lookup_context* lookupContext; debug_symbol_lookup_context* lookupContext;
status_t error = debug_create_symbol_lookup_context(&fDebugContext, status_t error = debug_create_symbol_lookup_context(owner, &lookupContext);
&lookupContext);
if (error != B_OK) { if (error != B_OK) {
fprintf(stderr, "%s: Failed to create symbol lookup context for " 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; return error;
} }
Image* image; Image* image;
error = _LoadImageSymbols(lookupContext, imageInfo, ID(), event, error = _LoadImageSymbols(lookupContext, imageInfo, owner, event,
&image); &image);
debug_delete_symbol_lookup_context(lookupContext); debug_delete_symbol_lookup_context(lookupContext);
@ -242,10 +260,10 @@ Team::AddImage(const image_info& imageInfo, int32 event)
status_t 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++) { for (int32 i = 0; Image* image = fImages.ItemAt(i); i++) {
if (image->ID() == imageInfo.id) { if (image->ID() == imageID) {
_RemoveImage(i, event); _RemoveImage(i, event);
return B_OK; return B_OK;
} }
@ -295,10 +313,14 @@ Team::_LoadImageSymbols(debug_symbol_lookup_context* lookupContext,
status_t error = image->LoadSymbols(lookupContext); status_t error = image->LoadSymbols(lookupContext);
if (error != B_OK) { if (error != B_OK) {
TRACE("Failed to load symbols of image %ld: %s\n", image->ID(),
strerror(error));
delete image; delete image;
return error; return error;
} }
TRACE("image %ld: loaded %ld symbols\n", image->ID(), image->SymbolCount());
if (!fImages.AddItem(image)) { if (!fImages.AddItem(image)) {
delete image; delete image;
return B_NO_MEMORY; return B_NO_MEMORY;
@ -318,10 +340,16 @@ Team::_RemoveImage(int32 index, int32 event)
if (image == NULL) if (image == NULL)
return; return;
// Note: We don't tell the threads that the image has been removed. They if (_SynchronousProfiling()) {
// will be updated lazily when their next profiler update arrives. This ThreadList::Iterator it = fThreads.GetIterator();
// is necessary, since the update might contain samples hitting that while (Thread* thread = it.Next())
// image. 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->SetDeletionEvent(event);
image->RemoveReference(); image->RemoveReference();

View File

@ -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. * Distributed under the terms of the MIT License.
*/ */
#ifndef TEAM_H #ifndef TEAM_H
@ -12,12 +12,16 @@
#include "Thread.h" #include "Thread.h"
struct system_profiler_team_added;
class Team { class Team {
public: public:
Team(); Team();
~Team(); ~Team();
status_t Init(team_id teamID, port_id debuggerPort); status_t Init(team_id teamID, port_id debuggerPort);
status_t Init(system_profiler_team_added* addedInfo);
status_t InitThread(Thread* thread); status_t InitThread(Thread* thread);
void RemoveThread(Thread* thread); void RemoveThread(Thread* thread);
@ -25,9 +29,8 @@ public:
void Exec(int32 event); void Exec(int32 event);
status_t AddImage(const image_info& imageInfo, status_t AddImage(const image_info& imageInfo,
int32 event); team_id owner, int32 event);
status_t RemoveImage(const image_info& imageInfo, status_t RemoveImage(image_id imageID, int32 event);
int32 event);
inline const BObjectList<Image>& Images() const; inline const BObjectList<Image>& Images() const;
Image* FindImage(image_id id) const; Image* FindImage(image_id id) const;
@ -44,6 +47,9 @@ private:
int32 event, Image** _image = NULL); int32 event, Image** _image = NULL);
void _RemoveImage(int32 index, int32 event); void _RemoveImage(int32 index, int32 event);
bool _SynchronousProfiling() const
{ return fDebugContext.nub_port < 0; }
private: private:
typedef DoublyLinkedList<Thread> ThreadList; typedef DoublyLinkedList<Thread> ThreadList;

View File

@ -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. * 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 void
Thread::AddSamples(int32 count, int32 dropped, int32 stackDepth, Thread::AddSamples(int32 count, int32 dropped, int32 stackDepth,
bool variableStackDepth, int32 event) 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 void
Thread::PrintResults() const Thread::PrintResults() const
{ {

View File

@ -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. * Distributed under the terms of the MIT License.
*/ */
#ifndef THREAD_H #ifndef THREAD_H
@ -53,11 +53,13 @@ public:
void SetSampleArea(area_id area, addr_t* samples); void SetSampleArea(area_id area, addr_t* samples);
void SetInterval(bigtime_t interval); 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, void AddSamples(int32 count, int32 dropped,
int32 stackDepth, bool variableStackDepth, int32 stackDepth, bool variableStackDepth,
int32 event); int32 event);
void AddSamples(addr_t* samples, int32 sampleCount);
void PrintResults() const; void PrintResults() const;
private: private:
@ -81,7 +83,10 @@ public:
void SetInterval(bigtime_t interval); void SetInterval(bigtime_t interval);
virtual void SetLazyImages(bool lazy) = 0;
virtual status_t AddImage(Image* image) = 0; virtual status_t AddImage(Image* image) = 0;
virtual void RemoveImage(Image* image) = 0;
virtual void SynchronizeImages(int32 event) = 0; virtual void SynchronizeImages(int32 event) = 0;
virtual void AddSamples(addr_t* samples, virtual void AddSamples(addr_t* samples,
@ -101,7 +106,10 @@ public:
AbstractThreadProfileResult(); AbstractThreadProfileResult();
virtual ~AbstractThreadProfileResult(); virtual ~AbstractThreadProfileResult();
virtual void SetLazyImages(bool lazy);
virtual status_t AddImage(Image* image); virtual status_t AddImage(Image* image);
virtual void RemoveImage(Image* image);
virtual void SynchronizeImages(int32 event); virtual void SynchronizeImages(int32 event);
ThreadImageType* FindImage(addr_t address) const; ThreadImageType* FindImage(addr_t address) const;
@ -120,6 +128,7 @@ protected:
ImageList fImages; ImageList fImages;
ImageList fNewImages; ImageList fNewImages;
ImageList fOldImages; 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 // #pragma mark - AbstractThreadProfileResult
@ -200,7 +223,8 @@ AbstractThreadProfileResult<ThreadImageType>::AbstractThreadProfileResult()
: :
fImages(), fImages(),
fNewImages(), fNewImages(),
fOldImages() fOldImages(),
fLazyImages(true)
{ {
} }
@ -215,6 +239,14 @@ AbstractThreadProfileResult<ThreadImageType>::~AbstractThreadProfileResult()
} }
template<typename ThreadImageType>
void
AbstractThreadProfileResult<ThreadImageType>::SetLazyImages(bool lazy)
{
fLazyImages = lazy;
}
template<typename ThreadImageType> template<typename ThreadImageType>
status_t status_t
AbstractThreadProfileResult<ThreadImageType>::AddImage(Image* image) AbstractThreadProfileResult<ThreadImageType>::AddImage(Image* image)
@ -229,12 +261,33 @@ AbstractThreadProfileResult<ThreadImageType>::AddImage(Image* image)
return error; return error;
} }
fNewImages.Add(threadImage); if (fLazyImages)
fNewImages.Add(threadImage);
else
fImages.Add(threadImage);
return B_OK; return B_OK;
} }
template<typename ThreadImageType>
void
AbstractThreadProfileResult<ThreadImageType>::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<typename ThreadImageType> template<typename ThreadImageType>
void void
AbstractThreadProfileResult<ThreadImageType>::SynchronizeImages(int32 event) AbstractThreadProfileResult<ThreadImageType>::SynchronizeImages(int32 event)

View File

@ -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. * Distributed under the terms of the MIT License.
*/ */
@ -17,6 +17,9 @@
#include <OS.h> #include <OS.h>
#include <String.h> #include <String.h>
#include <syscalls.h>
#include <system_profiler_defs.h>
#include <debug_support.h> #include <debug_support.h>
#include <ObjectList.h> #include <ObjectList.h>
#include <Referenceable.h> #include <Referenceable.h>
@ -31,6 +34,10 @@
#include "Team.h" #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; extern const char* __progname;
const char* kCommandName = __progname; const char* kCommandName = __progname;
@ -41,12 +48,15 @@ class Thread;
static const char* kUsage = static const char* kUsage =
"Usage: %s [ <options> ] <command line>\n" "Usage: %s [ <options> ] [ <command line> ]\n"
"Executes the given command line <command line> and periodically samples\n" "Profiles threads by periodically sampling the program counter. There are\n"
"all started threads' program counters. When a thread terminates, a list\n" "two different modes: One profiles the complete system. The other starts\n"
"of the functions where the thread was encountered is printed.\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" "\n"
"Options:\n" "Options:\n"
" -a, --all - Profile all teams.\n"
" -c - Don't profile child threads. Default is to\n" " -c - Don't profile child threads. Default is to\n"
" recursively profile all threads created by a profiled\n" " recursively profile all threads created by a profiled\n"
" thread.\n" " thread.\n"
@ -75,6 +85,8 @@ static const char* kUsage =
Options gOptions; Options gOptions;
static bool sCaughtDeadlySignal = false;
class ThreadManager { class ThreadManager {
public: public:
@ -88,25 +100,12 @@ public:
status_t AddTeam(team_id teamID, Team** _team = NULL) status_t AddTeam(team_id teamID, Team** _team = NULL)
{ {
if (FindTeam(teamID) != NULL) return _AddTeam(teamID, NULL, _team);
return B_BAD_VALUE; }
Team* team = new(std::nothrow) Team; status_t AddTeam(system_profiler_team_added* addedInfo, Team** _team = NULL)
if (team == NULL) {
return B_NO_MEMORY; return _AddTeam(addedInfo->team, addedInfo, _team);
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 AddThread(thread_id threadID) status_t AddThread(thread_id threadID)
@ -175,7 +174,73 @@ public:
return NULL; 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: 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) status_t _CreateThreadProfileResult(Thread* thread)
{ {
ThreadProfileResult* profileResult; 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 int
main(int argc, const char* const* argv) main(int argc, const char* const* argv)
{ {
@ -239,17 +509,21 @@ main(int argc, const char* const* argv)
while (true) { while (true) {
static struct option sLongOptions[] = { static struct option sLongOptions[] = {
{ "all", no_argument, 0, 'a' },
{ "help", no_argument, 0, 'h' }, { "help", no_argument, 0, 'h' },
{ 0, 0, 0, 0 } { 0, 0, 0, 0 }
}; };
opterr = 0; // don't print errors opterr = 0; // don't print errors
int c = getopt_long(argc, (char**)argv, "+cCfhi:klo:s:v:", sLongOptions, int c = getopt_long(argc, (char**)argv, "+acCfhi:klo:s:v:",
NULL); sLongOptions, NULL);
if (c == -1) if (c == -1)
break; break;
switch (c) { switch (c) {
case 'a':
gOptions.profile_all = true;
break;
case 'c': case 'c':
gOptions.profile_threads = false; gOptions.profile_threads = false;
break; 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); print_usage_and_exit(true);
if (stackDepth != 0) if (stackDepth != 0)
gOptions.stack_depth = stackDepth; gOptions.stack_depth = stackDepth;
const char* const* programArgs = argv + optind;
int programArgCount = argc - optind;
if (outputFile != NULL) { if (outputFile != NULL) {
gOptions.output = fopen(outputFile, "w+"); gOptions.output = fopen(outputFile, "w+");
if (gOptions.output == NULL) { if (gOptions.output == NULL) {
@ -308,6 +579,14 @@ main(int argc, const char* const* argv)
} else } else
gOptions.output = stdout; 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 // get thread/team to be debugged
thread_id threadID = -1; thread_id threadID = -1;
team_id teamID = -1; team_id teamID = -1;
@ -417,16 +696,14 @@ main(int argc, const char* const* argv)
break; break;
case B_DEBUGGER_MESSAGE_IMAGE_CREATED: case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
if (Team* team = threadManager.FindTeam(message.origin.team)) { threadManager.AddImage(message.origin.team,
team->AddImage(message.image_created.info, message.image_created.info,
message.image_created.image_event); message.image_created.image_event);
}
break; break;
case B_DEBUGGER_MESSAGE_IMAGE_DELETED: case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
if (Team* team = threadManager.FindTeam(message.origin.team)) { threadManager.RemoveImage(message.origin.team,
team->RemoveImage(message.image_deleted.info, message.image_deleted.info.id,
message.image_deleted.image_event); message.image_deleted.image_event);
}
break; break;
case B_DEBUGGER_MESSAGE_POST_SYSCALL: case B_DEBUGGER_MESSAGE_POST_SYSCALL:

View File

@ -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. * Distributed under the terms of the MIT License.
*/ */
@ -18,8 +18,7 @@ using std::nothrow;
struct debug_symbol_lookup_context { struct debug_symbol_lookup_context {
debug_context context; SymbolLookup* lookup;
SymbolLookup *lookup;
}; };
struct debug_symbol_iterator : BPrivate::SymbolIterator { struct debug_symbol_iterator : BPrivate::SymbolIterator {
@ -266,20 +265,19 @@ debug_get_stack_frame(debug_context *context, void *stackFrameAddress,
// debug_create_symbol_lookup_context // debug_create_symbol_lookup_context
status_t status_t
debug_create_symbol_lookup_context(debug_context *debugContext, debug_create_symbol_lookup_context(team_id team,
debug_symbol_lookup_context **_lookupContext) debug_symbol_lookup_context **_lookupContext)
{ {
if (!debugContext || !_lookupContext) if (team < 0 || !_lookupContext)
return B_BAD_VALUE; return B_BAD_VALUE;
// create the lookup context // create the lookup context
debug_symbol_lookup_context *lookupContext debug_symbol_lookup_context *lookupContext
= new(nothrow) debug_symbol_lookup_context; = new(nothrow) debug_symbol_lookup_context;
lookupContext->context = *debugContext;
ObjectDeleter<debug_symbol_lookup_context> contextDeleter(lookupContext); ObjectDeleter<debug_symbol_lookup_context> contextDeleter(lookupContext);
// create and init symbol lookup // create and init symbol lookup
SymbolLookup *lookup = new(nothrow) SymbolLookup(debugContext->team); SymbolLookup *lookup = new(nothrow) SymbolLookup(team);
if (!lookup) if (!lookup)
return B_NO_MEMORY; return B_NO_MEMORY;

View File

@ -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. * Distributed under the terms of the MIT License.
*/ */
@ -644,8 +644,7 @@ TeamDebugHandler::_PrintStackTrace(thread_id thread)
if (error == B_OK) { if (error == B_OK) {
// create a symbol lookup context // create a symbol lookup context
debug_symbol_lookup_context *lookupContext = NULL; debug_symbol_lookup_context *lookupContext = NULL;
error = debug_create_symbol_lookup_context(&fDebugContext, error = debug_create_symbol_lookup_context(fTeam, &lookupContext);
&lookupContext);
if (error != B_OK) { if (error != B_OK) {
debug_printf("debug_server: Failed to create symbol lookup " debug_printf("debug_server: Failed to create symbol lookup "
"context: %s\n", strerror(error)); "context: %s\n", strerror(error));