From f965a969b17376e47d9d2948ba4a5cfce2a785d0 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 29 Sep 2008 00:53:38 +0000 Subject: [PATCH] Extended the profiling API. When using the variable stack trace depth buffer format, the buffer can now also contain other events than just stack traces. ATM these are only references to the image events (created/deleted). Therefore we no longer have to flush the profiling buffer after such an event, since the debugger can exactly match the samples. Since we couldn't flush when the profiling timer hit while the thread was in the kernel, that wasn't working that well anyway. "profile -f" fails to translate stack trace addresses only very rarely, now. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27775 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/kernel/debugger.h | 12 +++++++ headers/private/kernel/user_debugger.h | 3 ++ src/bin/debug/profile.cpp | 39 ++++++++++++++++++++--- src/system/kernel/debug/user_debugger.cpp | 21 ++++++++++-- 4 files changed, 68 insertions(+), 7 deletions(-) diff --git a/headers/os/kernel/debugger.h b/headers/os/kernel/debugger.h index eb51a2531b..32978857f3 100644 --- a/headers/os/kernel/debugger.h +++ b/headers/os/kernel/debugger.h @@ -180,6 +180,18 @@ typedef enum { } debug_debugger_message; +// profile events -- when the buffer is in variable stack depth format, a sample +// count entry >= B_DEBUG_PROFILE_EVENT_BASE indicates a profile event +enum { + B_DEBUG_PROFILE_EVENT_BASE = 0x80000000, + B_DEBUG_PROFILE_EVENT_PARAMETER_MASK = 0x0000ffff, + // & with to get the event's parameter count + + B_DEBUG_PROFILE_IMAGE_EVENT = 0x80010001 + // single parameter: the respective image event counter +}; + + // #pragma mark - // #pragma mark ----- messages to the debug nub thread ----- diff --git a/headers/private/kernel/user_debugger.h b/headers/private/kernel/user_debugger.h index 7b1c997c04..8d1e9d5108 100644 --- a/headers/private/kernel/user_debugger.h +++ b/headers/private/kernel/user_debugger.h @@ -96,6 +96,9 @@ struct thread_debug_info { int32 image_event; // number of the image event when the first sample was written into // the buffer + int32 last_image_event; + // number of the image event when the last sample was written into + // the buffer bool variable_stack_depth; // record a variable number of samples per hit bool buffer_full; diff --git a/src/bin/debug/profile.cpp b/src/bin/debug/profile.cpp index 6666220226..4f8b300b2a 100644 --- a/src/bin/debug/profile.cpp +++ b/src/bin/debug/profile.cpp @@ -495,8 +495,26 @@ public: int32 totalSampleCount = 0; int32 tickCount = 0; addr_t* samples = fSamples; + while (count > 0) { - int32 sampleCount = *(samples++); + addr_t sampleCount = *(samples++); + + if (sampleCount >= B_DEBUG_PROFILE_EVENT_BASE) { + int32 eventParameterCount + = sampleCount & B_DEBUG_PROFILE_EVENT_PARAMETER_MASK; + if (sampleCount == B_DEBUG_PROFILE_IMAGE_EVENT) { + int32 imageEvent = (int32)samples[0]; + _RemoveObsoleteImages(imageEvent); + _AddNewImages(newImages, imageEvent); + } else { + fprintf(stderr, "unknown profile event: %#lx\n", + sampleCount); + } + + samples += eventParameterCount; + count -= eventParameterCount + 1; + continue; + } // Sort the samples. This way hits of the same symbol are // successive and we can avoid incrementing the hit count of the @@ -507,7 +525,7 @@ public: ThreadImage* previousImage = NULL; int32 previousSymbol = -1; - for (int32 i = 0; i < sampleCount; i++) { + for (uint32 i = 0; i < sampleCount; i++) { addr_t address = samples[i]; ThreadImage* image = FindImage(address); int32 symbol = -1; @@ -527,7 +545,7 @@ public: previousSymbol = symbol; } - if (unknownSamples == sampleCount) + if (unknownSamples == (int32)sampleCount) fUnkownTicks++; samples += sampleCount; @@ -681,8 +699,21 @@ public: } private: + typedef DoublyLinkedList ImageList; + void _SynchronizeImages(); + void _AddNewImages(ImageList& newImages, int32 event) + { + ImageList::Iterator it = newImages.GetIterator(); + while (ThreadImage* image = it.Next()) { + if (image->GetImage()->CreationEvent() >= event) { + it.Remove(); + fImages.Add(image); + } + } + } + void _RemoveObsoleteImages(int32 event) { // remove obsolete images @@ -711,8 +742,6 @@ private: } private: - typedef DoublyLinkedList ImageList; - thread_info fInfo; ::Team* fTeam; area_id fSampleArea; diff --git a/src/system/kernel/debug/user_debugger.cpp b/src/system/kernel/debug/user_debugger.cpp index bd1bc665dd..483db22b26 100644 --- a/src/system/kernel/debug/user_debugger.cpp +++ b/src/system/kernel/debug/user_debugger.cpp @@ -1192,11 +1192,25 @@ profiling_do_sample(bool& flushBuffer) // Check, whether the buffer is full or an image event occurred since the // last sample was taken. + int32 maxSamples = debugInfo.profile.max_samples; 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 + if (debugInfo.profile.last_image_event < imageEvent + && debugInfo.profile.variable_stack_depth + && sampleCount + 2 <= maxSamples) { + // an image event occurred, but we use variable stack depth and + // have enough room in the buffer to indicate an image event + addr_t* event = debugInfo.profile.samples + sampleCount; + event[0] = B_DEBUG_PROFILE_IMAGE_EVENT; + event[1] = imageEvent; + sampleCount += 2; + debugInfo.profile.sample_count = sampleCount; + debugInfo.profile.last_image_event = imageEvent; + } + + if (debugInfo.profile.last_image_event < imageEvent || debugInfo.profile.flush_threshold - sampleCount < stackDepth) { if (!IS_KERNEL_ADDRESS(arch_debug_get_interrupt_pc())) { flushBuffer = true; @@ -1206,7 +1220,7 @@ profiling_do_sample(bool& flushBuffer) // We can't flush the buffer now, since we interrupted a kernel // function. If the buffer is not full yet, we add the samples, // otherwise we have to drop them. - if (debugInfo.profile.max_samples - sampleCount < stackDepth) { + if (maxSamples - sampleCount < stackDepth) { debugInfo.profile.dropped_ticks++; return true; } @@ -1214,6 +1228,7 @@ profiling_do_sample(bool& flushBuffer) } else { // first sample -- set the image event debugInfo.profile.image_event = imageEvent; + debugInfo.profile.last_image_event = imageEvent; } // get the samples @@ -2300,6 +2315,8 @@ debug_nub_thread(void *) threadDebugInfo.profile.interval_left = interval; threadDebugInfo.profile.installed_timer = NULL; threadDebugInfo.profile.image_event = imageEvent; + threadDebugInfo.profile.last_image_event + = imageEvent; } else result = B_BAD_VALUE; } else