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