* Introduced a per-team counter that is incremented whenever an image
is created or deleted (or exec*() has been invoked). The counter is sent with several debugger messages. * Track the image event counter that is used when samples are added to the profiling buffer. If the current team counter differs, we flush the buffer first (sending an update message to the debugger), so that the debugger has a chance to match the addresses to the correct images. * Disable profiling for a thread while it runs in the debugger support code. This fixes potential deadlocks which could occur when a profiling timer event occurred that would require the buffer to be flushed while the thread was just sending something to the debugger or waiting for a command. As it turns out, this is not sufficient either, since we should never try to flush the buffer when the timer event occurred in the kernel, since the thread might hold a lock that the debugger thread could try to acquire. Will implement a more general solution later. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27656 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -371,9 +371,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
status_t error;
|
status_t error;
|
||||||
int32 profile_event; // number of the last event influencing
|
int32 image_event; // number of the last image event
|
||||||
// profiling (e.g. image
|
|
||||||
// created/deleted)
|
|
||||||
bigtime_t interval; // actual sample interval (might
|
bigtime_t interval; // actual sample interval (might
|
||||||
// differ from the requested one)
|
// differ from the requested one)
|
||||||
} debug_nub_start_profiler_reply;
|
} debug_nub_start_profiler_reply;
|
||||||
@@ -515,6 +513,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
debug_origin origin;
|
debug_origin origin;
|
||||||
|
int32 image_event; // number of the image event
|
||||||
} debug_team_exec;
|
} debug_team_exec;
|
||||||
|
|
||||||
// B_DEBUGGER_MESSAGE_THREAD_CREATED
|
// B_DEBUGGER_MESSAGE_THREAD_CREATED
|
||||||
@@ -535,6 +534,7 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
debug_origin origin;
|
debug_origin origin;
|
||||||
image_info info; // info for the image
|
image_info info; // info for the image
|
||||||
|
int32 image_event; // number of the image event
|
||||||
} debug_image_created;
|
} debug_image_created;
|
||||||
|
|
||||||
// B_DEBUGGER_MESSAGE_IMAGE_DELETED
|
// B_DEBUGGER_MESSAGE_IMAGE_DELETED
|
||||||
@@ -542,17 +542,17 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
debug_origin origin;
|
debug_origin origin;
|
||||||
image_info info; // info for the image
|
image_info info; // info for the image
|
||||||
|
int32 image_event; // number of the image event
|
||||||
} debug_image_deleted;
|
} debug_image_deleted;
|
||||||
|
|
||||||
// B_DEBUGGER_MESSAGE_PROFILER_UPDATE
|
// B_DEBUGGER_MESSAGE_PROFILER_UPDATE
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
debug_origin origin;
|
debug_origin origin;
|
||||||
int32 profile_event; // number of the last event
|
int32 image_event; // number of the last image event;
|
||||||
// influencing profiling (e.g.
|
// all samples were recorded after
|
||||||
// image created/deleted); all
|
// this event and before the next
|
||||||
// samples were recorded after this
|
// one
|
||||||
// event and before the next one
|
|
||||||
int32 stack_depth; // number of return addresses per
|
int32 stack_depth; // number of return addresses per
|
||||||
// tick
|
// tick
|
||||||
int32 sample_count; // number of samples in the buffer
|
int32 sample_count; // number of samples in the buffer
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ struct team_debug_info {
|
|||||||
sem_id debugger_write_lock;
|
sem_id debugger_write_lock;
|
||||||
// synchronizes writes to the debugger port with the setting (but not
|
// synchronizes writes to the debugger port with the setting (but not
|
||||||
// clearing) of the B_TEAM_DEBUG_DEBUGGER_HANDOVER flag
|
// clearing) of the B_TEAM_DEBUG_DEBUGGER_HANDOVER flag
|
||||||
|
vint32 image_event;
|
||||||
|
// counter incremented whenever an image is created/deleted
|
||||||
|
|
||||||
struct arch_team_debug_info arch_info;
|
struct arch_team_debug_info arch_info;
|
||||||
};
|
};
|
||||||
@@ -86,6 +88,11 @@ struct thread_debug_info {
|
|||||||
// number of samples the buffer currently holds
|
// number of samples the buffer currently holds
|
||||||
int32 stack_depth;
|
int32 stack_depth;
|
||||||
// number of return addresses to record per timer interval
|
// number of return addresses to record per timer interval
|
||||||
|
int32 image_event;
|
||||||
|
// number of the image event when the first sample was written into
|
||||||
|
// the buffer
|
||||||
|
int32 disabled;
|
||||||
|
// if > 0, profiling is temporarily disabled for the thread
|
||||||
bool buffer_full;
|
bool buffer_full;
|
||||||
// indicates that the sample buffer is full
|
// indicates that the sample buffer is full
|
||||||
union {
|
union {
|
||||||
|
|||||||
@@ -47,11 +47,58 @@ static timer sProfilingTimers[B_MAX_CPU_COUNT];
|
|||||||
// on that CPU
|
// on that CPU
|
||||||
|
|
||||||
|
|
||||||
|
static void schedule_profiling_timer(struct thread* thread,
|
||||||
|
bigtime_t interval);
|
||||||
static int32 profiling_event(timer* unused);
|
static int32 profiling_event(timer* unused);
|
||||||
static status_t ensure_debugger_installed(team_id teamID, port_id *port = NULL);
|
static status_t ensure_debugger_installed(team_id teamID, port_id *port = NULL);
|
||||||
static void get_team_debug_info(team_debug_info &teamDebugInfo);
|
static void get_team_debug_info(team_debug_info &teamDebugInfo);
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
enable_profiling()
|
||||||
|
{
|
||||||
|
struct thread* thread = thread_get_current_thread();
|
||||||
|
|
||||||
|
InterruptsSpinLocker _(gThreadSpinlock);
|
||||||
|
|
||||||
|
if (--thread->debug_info.profile.disabled > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (thread->debug_info.profile.samples != NULL
|
||||||
|
&& !thread->debug_info.profile.buffer_full) {
|
||||||
|
// install profiling timer
|
||||||
|
schedule_profiling_timer(thread,
|
||||||
|
thread->debug_info.profile.interval_left);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
disable_profiling()
|
||||||
|
{
|
||||||
|
struct thread* thread = thread_get_current_thread();
|
||||||
|
|
||||||
|
InterruptsSpinLocker _(gThreadSpinlock);
|
||||||
|
|
||||||
|
if (thread->debug_info.profile.disabled++ > 0) {
|
||||||
|
ASSERT(thread->debug_info.profile.installed_timer == NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if running, cancel the profiling timer
|
||||||
|
struct timer* timer = thread->debug_info.profile.installed_timer;
|
||||||
|
if (timer != NULL) {
|
||||||
|
// track remaining time
|
||||||
|
bigtime_t left = thread->debug_info.profile.timer_end - system_time();
|
||||||
|
thread->debug_info.profile.interval_left = max_c(left, 0);
|
||||||
|
thread->debug_info.profile.installed_timer = NULL;
|
||||||
|
|
||||||
|
// cancel timer
|
||||||
|
cancel_timer(timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
kill_interruptable_write_port(port_id port, int32 code, const void *buffer,
|
kill_interruptable_write_port(port_id port, int32 code, const void *buffer,
|
||||||
size_t bufferSize)
|
size_t bufferSize)
|
||||||
@@ -72,6 +119,8 @@ debugger_write(port_id port, int32 code, const void *buffer, size_t bufferSize,
|
|||||||
|
|
||||||
status_t error = B_OK;
|
status_t error = B_OK;
|
||||||
|
|
||||||
|
disable_profiling();
|
||||||
|
|
||||||
// get the team debug info
|
// get the team debug info
|
||||||
team_debug_info teamDebugInfo;
|
team_debug_info teamDebugInfo;
|
||||||
get_team_debug_info(teamDebugInfo);
|
get_team_debug_info(teamDebugInfo);
|
||||||
@@ -83,6 +132,7 @@ debugger_write(port_id port, int32 code, const void *buffer, size_t bufferSize,
|
|||||||
dontWait ? (uint32)B_RELATIVE_TIMEOUT : (uint32)B_KILL_CAN_INTERRUPT, 0);
|
dontWait ? (uint32)B_RELATIVE_TIMEOUT : (uint32)B_KILL_CAN_INTERRUPT, 0);
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
TRACE(("debugger_write() done1: %lx\n", error));
|
TRACE(("debugger_write() done1: %lx\n", error));
|
||||||
|
enable_profiling();
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +159,7 @@ debugger_write(port_id port, int32 code, const void *buffer, size_t bufferSize,
|
|||||||
|
|
||||||
TRACE(("debugger_write() done: %lx\n", error));
|
TRACE(("debugger_write() done: %lx\n", error));
|
||||||
|
|
||||||
|
enable_profiling();
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,6 +270,7 @@ clear_team_debug_info(struct team_debug_info *info, bool initLock)
|
|||||||
info->nub_thread = -1;
|
info->nub_thread = -1;
|
||||||
info->nub_port = -1;
|
info->nub_port = -1;
|
||||||
info->debugger_write_lock = -1;
|
info->debugger_write_lock = -1;
|
||||||
|
info->image_event = 0;
|
||||||
|
|
||||||
if (initLock)
|
if (initLock)
|
||||||
B_INITIALIZE_SPINLOCK(&info->lock);
|
B_INITIALIZE_SPINLOCK(&info->lock);
|
||||||
@@ -269,6 +321,7 @@ destroy_team_debug_info(struct team_debug_info *info)
|
|||||||
atomic_set(&info->flags, 0);
|
atomic_set(&info->flags, 0);
|
||||||
info->debugger_team = -1;
|
info->debugger_team = -1;
|
||||||
info->debugger_port = -1;
|
info->debugger_port = -1;
|
||||||
|
info->image_event = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,6 +337,7 @@ init_thread_debug_info(struct thread_debug_info *info)
|
|||||||
info->ignore_signals_once = 0;
|
info->ignore_signals_once = 0;
|
||||||
info->profile.sample_area = -1;
|
info->profile.sample_area = -1;
|
||||||
info->profile.samples = NULL;
|
info->profile.samples = NULL;
|
||||||
|
info->profile.disabled = 0;
|
||||||
info->profile.buffer_full = false;
|
info->profile.buffer_full = false;
|
||||||
info->profile.installed_timer = NULL;
|
info->profile.installed_timer = NULL;
|
||||||
}
|
}
|
||||||
@@ -310,6 +364,7 @@ clear_thread_debug_info(struct thread_debug_info *info, bool dying)
|
|||||||
info->ignore_signals_once = 0;
|
info->ignore_signals_once = 0;
|
||||||
info->profile.sample_area = -1;
|
info->profile.sample_area = -1;
|
||||||
info->profile.samples = NULL;
|
info->profile.samples = NULL;
|
||||||
|
info->profile.disabled = 0;
|
||||||
info->profile.buffer_full = false;
|
info->profile.buffer_full = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -680,6 +735,8 @@ static status_t
|
|||||||
thread_hit_debug_event(debug_debugger_message event, const void *message,
|
thread_hit_debug_event(debug_debugger_message event, const void *message,
|
||||||
int32 size, bool requireDebugger)
|
int32 size, bool requireDebugger)
|
||||||
{
|
{
|
||||||
|
disable_profiling();
|
||||||
|
|
||||||
status_t result;
|
status_t result;
|
||||||
bool restart;
|
bool restart;
|
||||||
do {
|
do {
|
||||||
@@ -688,6 +745,8 @@ thread_hit_debug_event(debug_debugger_message event, const void *message,
|
|||||||
requireDebugger, restart);
|
requireDebugger, restart);
|
||||||
} while (result >= 0 && restart);
|
} while (result >= 0 && restart);
|
||||||
|
|
||||||
|
enable_profiling();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -897,7 +956,9 @@ user_debug_team_exec()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prepare the message
|
// prepare the message
|
||||||
debug_team_created message;
|
debug_team_exec message;
|
||||||
|
message.image_event = atomic_add(&thread->team->debug_info.image_event, 1)
|
||||||
|
+ 1;
|
||||||
|
|
||||||
thread_hit_debug_event(B_DEBUGGER_MESSAGE_TEAM_EXEC, &message,
|
thread_hit_debug_event(B_DEBUGGER_MESSAGE_TEAM_EXEC, &message,
|
||||||
sizeof(message), true);
|
sizeof(message), true);
|
||||||
@@ -1022,8 +1083,10 @@ user_debug_thread_exiting(struct thread* thread)
|
|||||||
area_id sampleArea = threadDebugInfo.profile.sample_area;
|
area_id sampleArea = threadDebugInfo.profile.sample_area;
|
||||||
int32 sampleCount = threadDebugInfo.profile.sample_count;
|
int32 sampleCount = threadDebugInfo.profile.sample_count;
|
||||||
int32 stackDepth = threadDebugInfo.profile.stack_depth;
|
int32 stackDepth = threadDebugInfo.profile.stack_depth;
|
||||||
|
int32 imageEvent = threadDebugInfo.profile.image_event;
|
||||||
threadDebugInfo.profile.sample_area = -1;
|
threadDebugInfo.profile.sample_area = -1;
|
||||||
threadDebugInfo.profile.samples = NULL;
|
threadDebugInfo.profile.samples = NULL;
|
||||||
|
threadDebugInfo.profile.disabled = 0;
|
||||||
threadDebugInfo.profile.buffer_full = false;
|
threadDebugInfo.profile.buffer_full = false;
|
||||||
|
|
||||||
atomic_or(&threadDebugInfo.flags, B_THREAD_DEBUG_DYING);
|
atomic_or(&threadDebugInfo.flags, B_THREAD_DEBUG_DYING);
|
||||||
@@ -1038,6 +1101,7 @@ user_debug_thread_exiting(struct thread* thread)
|
|||||||
message.origin.nub_port = -1; // asynchronous message
|
message.origin.nub_port = -1; // asynchronous message
|
||||||
message.sample_count = sampleCount;
|
message.sample_count = sampleCount;
|
||||||
message.stack_depth = stackDepth;
|
message.stack_depth = stackDepth;
|
||||||
|
message.image_event = imageEvent;
|
||||||
message.stopped = true;
|
message.stopped = true;
|
||||||
debugger_write(debuggerPort, B_DEBUGGER_MESSAGE_PROFILER_UPDATE,
|
debugger_write(debuggerPort, B_DEBUGGER_MESSAGE_PROFILER_UPDATE,
|
||||||
&message, sizeof(message), false);
|
&message, sizeof(message), false);
|
||||||
@@ -1066,6 +1130,8 @@ user_debug_image_created(const image_info *imageInfo)
|
|||||||
// prepare the message
|
// prepare the message
|
||||||
debug_image_created message;
|
debug_image_created message;
|
||||||
memcpy(&message.info, imageInfo, sizeof(image_info));
|
memcpy(&message.info, imageInfo, sizeof(image_info));
|
||||||
|
message.image_event = atomic_add(&thread->team->debug_info.image_event, 1)
|
||||||
|
+ 1;
|
||||||
|
|
||||||
thread_hit_debug_event(B_DEBUGGER_MESSAGE_IMAGE_CREATED, &message,
|
thread_hit_debug_event(B_DEBUGGER_MESSAGE_IMAGE_CREATED, &message,
|
||||||
sizeof(message), true);
|
sizeof(message), true);
|
||||||
@@ -1086,6 +1152,8 @@ user_debug_image_deleted(const image_info *imageInfo)
|
|||||||
// prepare the message
|
// prepare the message
|
||||||
debug_image_deleted message;
|
debug_image_deleted message;
|
||||||
memcpy(&message.info, imageInfo, sizeof(image_info));
|
memcpy(&message.info, imageInfo, sizeof(image_info));
|
||||||
|
message.image_event = atomic_add(&thread->team->debug_info.image_event, 1)
|
||||||
|
+ 1;
|
||||||
|
|
||||||
thread_hit_debug_event(B_DEBUGGER_MESSAGE_IMAGE_CREATED, &message,
|
thread_hit_debug_event(B_DEBUGGER_MESSAGE_IMAGE_CREATED, &message,
|
||||||
sizeof(message), true);
|
sizeof(message), true);
|
||||||
@@ -1170,6 +1238,49 @@ schedule_profiling_timer(struct thread* thread, bigtime_t interval)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
profiling_do_sample(bool& flushBuffer)
|
||||||
|
{
|
||||||
|
struct thread* thread = thread_get_current_thread();
|
||||||
|
thread_debug_info& debugInfo = thread->debug_info;
|
||||||
|
|
||||||
|
if (debugInfo.profile.samples == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check, whether the buffer is full or an image event occurred since the
|
||||||
|
// last sample was taken.
|
||||||
|
int32 sampleCount = debugInfo.profile.sample_count;
|
||||||
|
int32 stackDepth = debugInfo.profile.stack_depth;
|
||||||
|
int32 imageEvent = thread->team->debug_info.image_event;
|
||||||
|
if (debugInfo.profile.sample_count > 0) {
|
||||||
|
if (debugInfo.profile.image_event < imageEvent
|
||||||
|
|| debugInfo.profile.max_samples - sampleCount < stackDepth) {
|
||||||
|
flushBuffer = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// first sample -- set the image event
|
||||||
|
debugInfo.profile.image_event = imageEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the samples
|
||||||
|
addr_t* returnAddresses = debugInfo.profile.samples
|
||||||
|
+ debugInfo.profile.sample_count;
|
||||||
|
if (stackDepth > 1) {
|
||||||
|
int32 count = arch_debug_get_stack_trace(returnAddresses, stackDepth, 1,
|
||||||
|
0, false);
|
||||||
|
|
||||||
|
for (int32 i = count; i < stackDepth; i++)
|
||||||
|
returnAddresses[i] = 0;
|
||||||
|
} else
|
||||||
|
*returnAddresses = (addr_t)arch_debug_get_interrupt_pc();
|
||||||
|
|
||||||
|
debugInfo.profile.sample_count += stackDepth;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
profiling_buffer_full(void*)
|
profiling_buffer_full(void*)
|
||||||
{
|
{
|
||||||
@@ -1181,8 +1292,9 @@ profiling_buffer_full(void*)
|
|||||||
if (debugInfo.profile.samples != NULL && debugInfo.profile.buffer_full) {
|
if (debugInfo.profile.samples != NULL && debugInfo.profile.buffer_full) {
|
||||||
int32 sampleCount = debugInfo.profile.sample_count;
|
int32 sampleCount = debugInfo.profile.sample_count;
|
||||||
int32 stackDepth = debugInfo.profile.stack_depth;
|
int32 stackDepth = debugInfo.profile.stack_depth;
|
||||||
if (debugInfo.profile.max_samples - sampleCount < stackDepth) {
|
int32 imageEvent = debugInfo.profile.image_event;
|
||||||
// The sample buffer is indeed full; notify the debugger.
|
|
||||||
|
// notify the debugger
|
||||||
debugInfo.profile.sample_count = 0;
|
debugInfo.profile.sample_count = 0;
|
||||||
|
|
||||||
RELEASE_THREAD_LOCK();
|
RELEASE_THREAD_LOCK();
|
||||||
@@ -1192,6 +1304,7 @@ profiling_buffer_full(void*)
|
|||||||
debug_profiler_update message;
|
debug_profiler_update message;
|
||||||
message.sample_count = sampleCount;
|
message.sample_count = sampleCount;
|
||||||
message.stack_depth = stackDepth;
|
message.stack_depth = stackDepth;
|
||||||
|
message.image_event = imageEvent;
|
||||||
message.stopped = false;
|
message.stopped = false;
|
||||||
|
|
||||||
thread_hit_debug_event(B_DEBUGGER_MESSAGE_PROFILER_UPDATE, &message,
|
thread_hit_debug_event(B_DEBUGGER_MESSAGE_PROFILER_UPDATE, &message,
|
||||||
@@ -1199,11 +1312,12 @@ profiling_buffer_full(void*)
|
|||||||
|
|
||||||
disable_interrupts();
|
disable_interrupts();
|
||||||
GRAB_THREAD_LOCK();
|
GRAB_THREAD_LOCK();
|
||||||
}
|
|
||||||
|
|
||||||
if (debugInfo.profile.samples != NULL) {
|
// do the sampling and reschedule timer, if still profiling this thread
|
||||||
schedule_profiling_timer(thread, debugInfo.profile.interval);
|
bool flushBuffer;
|
||||||
|
if (profiling_do_sample(flushBuffer)) {
|
||||||
debugInfo.profile.buffer_full = false;
|
debugInfo.profile.buffer_full = false;
|
||||||
|
schedule_profiling_timer(thread, debugInfo.profile.interval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1211,28 +1325,21 @@ profiling_buffer_full(void*)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! The thread spinlock is being held.
|
||||||
|
*/
|
||||||
static int32
|
static int32
|
||||||
profiling_event(timer* /*unused*/)
|
profiling_event(timer* /*unused*/)
|
||||||
{
|
{
|
||||||
struct thread* thread = thread_get_current_thread();
|
struct thread* thread = thread_get_current_thread();
|
||||||
thread_debug_info& debugInfo = thread->debug_info;
|
thread_debug_info& debugInfo = thread->debug_info;
|
||||||
|
|
||||||
if (debugInfo.profile.samples != NULL) {
|
bool flushBuffer;
|
||||||
int32 stackDepth = debugInfo.profile.stack_depth;
|
if (profiling_do_sample(flushBuffer)) {
|
||||||
addr_t* returnAddresses = debugInfo.profile.samples
|
if (flushBuffer) {
|
||||||
+ debugInfo.profile.sample_count;
|
// The sample buffer needs to be flushed; we'll have to notify the
|
||||||
int32 count = arch_debug_get_stack_trace(returnAddresses, stackDepth, 1,
|
// debugger. We can't do that right here. Instead we set a post
|
||||||
0, false);
|
// interrupt callback doing that for us, and don't reschedule the
|
||||||
|
// timer yet.
|
||||||
for (int32 i = count; i < stackDepth; i++)
|
|
||||||
returnAddresses[i] = 0;
|
|
||||||
|
|
||||||
debugInfo.profile.sample_count += stackDepth;
|
|
||||||
int32 sampleCount = debugInfo.profile.sample_count;
|
|
||||||
if (debugInfo.profile.max_samples - sampleCount < stackDepth) {
|
|
||||||
// The sample buffer is full; we'll have to notify the debugger.
|
|
||||||
// We can't do that right here. Instead we set a post interrupt
|
|
||||||
// callback doing that for us, and don't reschedule the timer yet.
|
|
||||||
thread->post_interrupt_callback = profiling_buffer_full;
|
thread->post_interrupt_callback = profiling_buffer_full;
|
||||||
debugInfo.profile.installed_timer = NULL;
|
debugInfo.profile.installed_timer = NULL;
|
||||||
debugInfo.profile.buffer_full = true;
|
debugInfo.profile.buffer_full = true;
|
||||||
@@ -1248,6 +1355,11 @@ profiling_event(timer* /*unused*/)
|
|||||||
void
|
void
|
||||||
user_debug_thread_unscheduled(struct thread* thread)
|
user_debug_thread_unscheduled(struct thread* thread)
|
||||||
{
|
{
|
||||||
|
if (thread->debug_info.profile.disabled > 0) {
|
||||||
|
ASSERT(thread->debug_info.profile.installed_timer == NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// if running, cancel the profiling timer
|
// if running, cancel the profiling timer
|
||||||
struct timer* timer = thread->debug_info.profile.installed_timer;
|
struct timer* timer = thread->debug_info.profile.installed_timer;
|
||||||
if (timer != NULL) {
|
if (timer != NULL) {
|
||||||
@@ -1265,6 +1377,9 @@ user_debug_thread_unscheduled(struct thread* thread)
|
|||||||
void
|
void
|
||||||
user_debug_thread_scheduled(struct thread* thread)
|
user_debug_thread_scheduled(struct thread* thread)
|
||||||
{
|
{
|
||||||
|
if (thread->debug_info.profile.disabled > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
if (thread->debug_info.profile.samples != NULL
|
if (thread->debug_info.profile.samples != NULL
|
||||||
&& !thread->debug_info.profile.buffer_full) {
|
&& !thread->debug_info.profile.buffer_full) {
|
||||||
// install profiling timer
|
// install profiling timer
|
||||||
@@ -2190,6 +2305,7 @@ debug_nub_thread(void *)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get the thread and set the profile info
|
// get the thread and set the profile info
|
||||||
|
int32 imageEvent = nubThread->team->debug_info.image_event;
|
||||||
if (result == B_OK) {
|
if (result == B_OK) {
|
||||||
cpu_status state = disable_interrupts();
|
cpu_status state = disable_interrupts();
|
||||||
GRAB_THREAD_LOCK();
|
GRAB_THREAD_LOCK();
|
||||||
@@ -2210,6 +2326,7 @@ debug_nub_thread(void *)
|
|||||||
threadDebugInfo.profile.buffer_full = false;
|
threadDebugInfo.profile.buffer_full = false;
|
||||||
threadDebugInfo.profile.interval_left = interval;
|
threadDebugInfo.profile.interval_left = interval;
|
||||||
threadDebugInfo.profile.installed_timer = NULL;
|
threadDebugInfo.profile.installed_timer = NULL;
|
||||||
|
threadDebugInfo.profile.image_event = imageEvent;
|
||||||
} else
|
} else
|
||||||
result = B_BAD_VALUE;
|
result = B_BAD_VALUE;
|
||||||
} else
|
} else
|
||||||
@@ -2228,9 +2345,9 @@ debug_nub_thread(void *)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// send a reply to the debugger
|
// send a reply to the debugger
|
||||||
// TODO: profile_event
|
|
||||||
reply.start_profiler.error = result;
|
reply.start_profiler.error = result;
|
||||||
reply.start_profiler.interval = interval;
|
reply.start_profiler.interval = interval;
|
||||||
|
reply.start_profiler.image_event = imageEvent;
|
||||||
sendReply = true;
|
sendReply = true;
|
||||||
replySize = sizeof(reply.start_profiler);
|
replySize = sizeof(reply.start_profiler);
|
||||||
|
|
||||||
@@ -2251,6 +2368,7 @@ debug_nub_thread(void *)
|
|||||||
addr_t* samples = NULL;
|
addr_t* samples = NULL;
|
||||||
int32 sampleCount = 0;
|
int32 sampleCount = 0;
|
||||||
int32 stackDepth = 0;
|
int32 stackDepth = 0;
|
||||||
|
int32 imageEvent = 0;
|
||||||
|
|
||||||
// get the thread and detach the profile info
|
// get the thread and detach the profile info
|
||||||
cpu_status state = disable_interrupts();
|
cpu_status state = disable_interrupts();
|
||||||
@@ -2265,6 +2383,7 @@ debug_nub_thread(void *)
|
|||||||
samples = threadDebugInfo.profile.samples;
|
samples = threadDebugInfo.profile.samples;
|
||||||
sampleCount = threadDebugInfo.profile.sample_count;
|
sampleCount = threadDebugInfo.profile.sample_count;
|
||||||
stackDepth = threadDebugInfo.profile.stack_depth;
|
stackDepth = threadDebugInfo.profile.stack_depth;
|
||||||
|
imageEvent = threadDebugInfo.profile.image_event;
|
||||||
threadDebugInfo.profile.sample_area = -1;
|
threadDebugInfo.profile.sample_area = -1;
|
||||||
threadDebugInfo.profile.samples = NULL;
|
threadDebugInfo.profile.samples = NULL;
|
||||||
threadDebugInfo.profile.buffer_full = false;
|
threadDebugInfo.profile.buffer_full = false;
|
||||||
@@ -2279,7 +2398,7 @@ debug_nub_thread(void *)
|
|||||||
// prepare the reply
|
// prepare the reply
|
||||||
if (result == B_OK) {
|
if (result == B_OK) {
|
||||||
reply.profiler_update.origin.thread = threadID;
|
reply.profiler_update.origin.thread = threadID;
|
||||||
// TODO: profile_event
|
reply.profiler_update.image_event = imageEvent;
|
||||||
reply.profiler_update.stack_depth = stackDepth;
|
reply.profiler_update.stack_depth = stackDepth;
|
||||||
reply.profiler_update.sample_count = sampleCount;
|
reply.profiler_update.sample_count = sampleCount;
|
||||||
reply.profiler_update.stopped = true;
|
reply.profiler_update.stopped = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user