diff --git a/src/apps/debuganalyzer/model/Model.cpp b/src/apps/debuganalyzer/model/Model.cpp index e129a81148..07467c30f0 100644 --- a/src/apps/debuganalyzer/model/Model.cpp +++ b/src/apps/debuganalyzer/model/Model.cpp @@ -13,6 +13,50 @@ #include +#include + + + +static const char* const kThreadStateNames[] = { + "running", + "still running", + "preempted", + "ready", + "waiting", + "unknown" +}; + + +const char* +thread_state_name(ThreadState state) +{ + return kThreadStateNames[state]; +} + + +const char* +wait_object_type_name(uint32 type) +{ + switch (type) { + case THREAD_BLOCK_TYPE_SEMAPHORE: + return "semaphore"; + case THREAD_BLOCK_TYPE_CONDITION_VARIABLE: + return "condition"; + case THREAD_BLOCK_TYPE_MUTEX: + return "mutex"; + case THREAD_BLOCK_TYPE_RW_LOCK: + return "rw lock"; + case THREAD_BLOCK_TYPE_OTHER: + return "other"; + case THREAD_BLOCK_TYPE_SNOOZE: + return "snooze"; + case THREAD_BLOCK_TYPE_SIGNAL: + return "signal"; + default: + return "unknown"; + } +} + // #pragma mark - CPU @@ -457,11 +501,14 @@ Model::CompactSchedulingState::Delete() // #pragma mark - Model -Model::Model(const char* dataSourceName, void* eventData, size_t eventDataSize) +Model::Model(const char* dataSourceName, void* eventData, size_t eventDataSize, + system_profiler_event_header** events, size_t eventCount) : fDataSourceName(dataSourceName), fEventData(eventData), + fEvents(events), fEventDataSize(eventDataSize), + fEventCount(eventCount), fCPUCount(1), fBaseTime(0), fLastEventTime(0), @@ -486,6 +533,50 @@ Model::~Model() } +size_t +Model::ClosestEventIndex(nanotime_t eventTime) const +{ + // The events themselves are unmodified and use an absolute time. + eventTime += fBaseTime; + + // Binary search the event. Since not all events have a timestamp, we have + // to do a bit of iteration, too. + size_t lower = 0; + size_t upper = CountEvents(); + while (lower < upper) { + size_t mid = (lower + upper) / 2; + while (mid < upper) { + system_profiler_event_header* header = fEvents[mid]; + switch (header->event) { + case B_SYSTEM_PROFILER_THREAD_SCHEDULED: + case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE: + case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE: + break; + default: + mid++; + continue; + } + + break; + } + + if (mid == upper) { + lower = mid; + break; + } + + system_profiler_thread_scheduling_event* event + = (system_profiler_thread_scheduling_event*)(fEvents[mid] + 1); + if (event->time < eventTime) + lower = mid + 1; + else + upper = mid; + } + + return lower; +} + + void Model::LoadingFinished() { diff --git a/src/apps/debuganalyzer/model/Model.h b/src/apps/debuganalyzer/model/Model.h index 1a68b16c1e..fe26d53dee 100644 --- a/src/apps/debuganalyzer/model/Model.h +++ b/src/apps/debuganalyzer/model/Model.h @@ -28,6 +28,9 @@ enum ThreadState { UNKNOWN }; +const char* thread_state_name(ThreadState state); +const char* wait_object_type_name(uint32 type); + class Model : public Referenceable { public: @@ -50,12 +53,20 @@ public: public: Model(const char* dataSourceName, - void* eventData, size_t eventDataSize); + void* eventData, size_t eventDataSize, + system_profiler_event_header** events, + size_t eventCount); ~Model(); inline const char* DataSourceName() const; inline void* EventData() const; inline size_t EventDataSize() const; + inline system_profiler_event_header** Events() const; + inline size_t CountEvents() const; + size_t ClosestEventIndex(nanotime_t eventTime) const; + // finds the greatest event with event + // time >= eventTime; may return + // CountEvents() void LoadingFinished(); @@ -119,13 +130,16 @@ private: typedef BObjectList SchedulingStateList; private: - static int _CompareEventTimeSchedulingState(const nanotime_t* time, - const CompactSchedulingState* state); + static int _CompareEventTimeSchedulingState( + const nanotime_t* time, + const CompactSchedulingState* state); private: BString fDataSourceName; void* fEventData; + system_profiler_event_header** fEvents; size_t fEventDataSize; + size_t fEventCount; int32 fCPUCount; nanotime_t fBaseTime; nanotime_t fLastEventTime; @@ -262,6 +276,10 @@ public: ThreadWaitObject* threadWaitObject); ~ThreadWaitObjectGroup(); + inline uint32 Type() const; + inline addr_t Object() const; + inline const char* Name() const; + inline ThreadWaitObject* MostRecentThreadWaitObject() const; inline WaitObject* MostRecentWaitObject() const; @@ -529,6 +547,20 @@ Model::EventDataSize() const } +system_profiler_event_header** +Model::Events() const +{ + return fEvents; +} + + +size_t +Model::CountEvents() const +{ + return fEventCount; +} + + nanotime_t Model::BaseTime() const { @@ -769,6 +801,27 @@ Model::ThreadWaitObject::TotalWaitTime() const // #pragma mark - ThreadWaitObjectGroup +uint32 +Model::ThreadWaitObjectGroup::Type() const +{ + return MostRecentThreadWaitObject()->Type(); +} + + +addr_t +Model::ThreadWaitObjectGroup::Object() const +{ + return MostRecentThreadWaitObject()->Object(); +} + + +const char* +Model::ThreadWaitObjectGroup::Name() const +{ + return MostRecentThreadWaitObject()->Name(); +} + + Model::ThreadWaitObject* Model::ThreadWaitObjectGroup::MostRecentThreadWaitObject() const { diff --git a/src/apps/debuganalyzer/model_loader/ModelLoader.cpp b/src/apps/debuganalyzer/model_loader/ModelLoader.cpp index c41d9ad4f1..a9ce3c48ea 100644 --- a/src/apps/debuganalyzer/model_loader/ModelLoader.cpp +++ b/src/apps/debuganalyzer/model_loader/ModelLoader.cpp @@ -160,6 +160,16 @@ ModelLoader::_Load() status_t error = _ReadDebugEvents(&eventData, &eventDataSize); if (error != B_OK) return error; + MemoryDeleter eventDataDeleter(eventData); + + // create a debug event array + system_profiler_event_header** events; + size_t eventCount; + error = _CreateDebugEventArray(eventData, eventDataSize, events, + eventCount); + if (error != B_OK) + return error; + ArrayDeleter eventsDeleter(events); // get the data source name BString dataSourceName; @@ -167,19 +177,15 @@ ModelLoader::_Load() // create a model fModel = new(std::nothrow) Model(dataSourceName.String(), eventData, - eventDataSize); - if (fModel == NULL) { - free(eventData); + eventDataSize, events, eventCount); + if (fModel == NULL) return B_NO_MEMORY; - } + eventDataDeleter.Detach(); + eventsDeleter.Detach(); // create a debug input stream - BDebugEventInputStream* input = new(std::nothrow) BDebugEventInputStream; - if (input == NULL) - return B_NO_MEMORY; - ObjectDeleter inputDeleter(input); - - error = input->SetTo(eventData, eventDataSize, false); + BDebugEventInputStream input; + error = input.SetTo(eventData, eventDataSize, false); if (error != B_OK) return error; @@ -201,7 +207,7 @@ ModelLoader::_Load() uint32 cpu; const void* buffer; off_t offset; - ssize_t bufferSize = input->ReadNextEvent(&event, &cpu, &buffer, + ssize_t bufferSize = input.ReadNextEvent(&event, &cpu, &buffer, &offset); if (bufferSize < 0) return bufferSize; @@ -320,6 +326,65 @@ ModelLoader::_ReadDebugEvents(void** _eventData, size_t* _size) } +status_t +ModelLoader::_CreateDebugEventArray(void* eventData, size_t eventDataSize, + system_profiler_event_header**& _events, size_t& _eventCount) +{ + // count the events + BDebugEventInputStream input; + status_t error = input.SetTo(eventData, eventDataSize, false); + if (error != B_OK) + return error; + + size_t eventCount = 0; + while (true) { + // get next event + uint32 event; + uint32 cpu; + const void* buffer; + ssize_t bufferSize = input.ReadNextEvent(&event, &cpu, &buffer, NULL); + if (bufferSize < 0) + return bufferSize; + if (buffer == NULL) + break; + + eventCount++; + } + + // create the array + system_profiler_event_header** events = new(std::nothrow) + system_profiler_event_header*[eventCount]; + if (events == NULL) + return B_NO_MEMORY; + + // populate the array + error = input.SetTo(eventData, eventDataSize, false); + if (error != B_OK) { + delete[] events; + return error; + } + + size_t eventIndex = 0; + while (true) { + // get next event + uint32 event; + uint32 cpu; + const void* buffer; + off_t offset; + input.ReadNextEvent(&event, &cpu, &buffer, &offset); + if (buffer == NULL) + break; + + events[eventIndex++] + = (system_profiler_event_header*)((uint8*)eventData + offset); + } + + _events = events; + _eventCount = eventCount; + return B_OK; +} + + status_t ModelLoader::_ProcessEvent(uint32 event, uint32 cpu, const void* buffer, size_t size) diff --git a/src/apps/debuganalyzer/model_loader/ModelLoader.h b/src/apps/debuganalyzer/model_loader/ModelLoader.h index c638d7e4c5..313f8963d8 100644 --- a/src/apps/debuganalyzer/model_loader/ModelLoader.h +++ b/src/apps/debuganalyzer/model_loader/ModelLoader.h @@ -46,6 +46,10 @@ private: status_t _Load(); status_t _ReadDebugEvents(void** _eventData, size_t* _size); + status_t _CreateDebugEventArray(void* eventData, + size_t eventDataSize, + system_profiler_event_header**& _events, + size_t& _eventCount); status_t _ProcessEvent(uint32 event, uint32 cpu, const void* buffer, size_t size);