* 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:
parent
2ad2768adc
commit
0f37915687
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 <image.h>
|
||||
|
||||
#include <debug_support.h>
|
||||
#include <system_profiler_defs.h>
|
||||
|
||||
#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();
|
||||
|
@ -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<Image>& 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<Thread> ThreadList;
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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<ThreadImageType>::AbstractThreadProfileResult()
|
||||
:
|
||||
fImages(),
|
||||
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>
|
||||
status_t
|
||||
AbstractThreadProfileResult<ThreadImageType>::AddImage(Image* image)
|
||||
@ -229,12 +261,33 @@ AbstractThreadProfileResult<ThreadImageType>::AddImage(Image* image)
|
||||
return error;
|
||||
}
|
||||
|
||||
fNewImages.Add(threadImage);
|
||||
if (fLazyImages)
|
||||
fNewImages.Add(threadImage);
|
||||
else
|
||||
fImages.Add(threadImage);
|
||||
|
||||
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>
|
||||
void
|
||||
AbstractThreadProfileResult<ThreadImageType>::SynchronizeImages(int32 event)
|
||||
|
@ -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 <OS.h>
|
||||
#include <String.h>
|
||||
|
||||
#include <syscalls.h>
|
||||
#include <system_profiler_defs.h>
|
||||
|
||||
#include <debug_support.h>
|
||||
#include <ObjectList.h>
|
||||
#include <Referenceable.h>
|
||||
@ -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 [ <options> ] <command line>\n"
|
||||
"Executes the given command line <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 [ <options> ] [ <command line> ]\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:
|
||||
|
@ -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<debug_symbol_lookup_context> 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;
|
||||
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user