diff --git a/src/apps/debuganalyzer/Jamfile b/src/apps/debuganalyzer/Jamfile index 7b871af454..1e7cfc8471 100644 --- a/src/apps/debuganalyzer/Jamfile +++ b/src/apps/debuganalyzer/Jamfile @@ -1,6 +1,6 @@ SubDir HAIKU_TOP src apps debuganalyzer ; -UsePrivateHeaders debug interface shared ; +UsePrivateHeaders debug interface kernel shared ; UsePrivateSystemHeaders ; Application DebugAnalyzer diff --git a/src/apps/debuganalyzer/Model.cpp b/src/apps/debuganalyzer/Model.cpp index a7e009d83e..d22409278a 100644 --- a/src/apps/debuganalyzer/Model.cpp +++ b/src/apps/debuganalyzer/Model.cpp @@ -13,6 +13,75 @@ #include +// #pragma mark - WaitObject + + +Model::WaitObject::WaitObject(const system_profiler_wait_object_info* event) + : + fEvent(event) +{ +} + + +Model::WaitObject::~WaitObject() +{ +} + + +// #pragma mark - WaitObjectGroup + + +Model::WaitObjectGroup::WaitObjectGroup(WaitObject* waitObject) +{ + fWaitObjects.Add(waitObject); +} + + +Model::WaitObjectGroup::~WaitObjectGroup() +{ +} + + +// #pragma mark - ThreadWaitObject + + +Model::ThreadWaitObject::ThreadWaitObject(WaitObject* waitObject) + : + fWaitObject(waitObject), + fWaits(0), + fTotalWaitTime(0) +{ +} + + +Model::ThreadWaitObject::~ThreadWaitObject() +{ +} + + +void +Model::ThreadWaitObject::AddWait(bigtime_t waitTime) +{ + fWaits++; + fTotalWaitTime += waitTime; +} + + +// #pragma mark - ThreadWaitObjectGroup + + +Model::ThreadWaitObjectGroup::ThreadWaitObjectGroup( + ThreadWaitObject* threadWaitObject) +{ + fWaitObjects.Add(threadWaitObject); +} + + +Model::ThreadWaitObjectGroup::~ThreadWaitObjectGroup() +{ +} + + // #pragma mark - Team @@ -47,7 +116,22 @@ Model::Thread::Thread(Team* team, const system_profiler_thread_added* event, fTeam(team), fCreationEvent(event), fCreationTime(time), - fDeletionTime(-1) + fDeletionTime(-1), + fRuns(0), + fTotalRunTime(0), + fMinRunTime(-1), + fMaxRunTime(-1), + fLatencies(0), + fTotalLatency(0), + fMinLatency(-1), + fMaxLatency(-1), + fReruns(0), + fTotalRerunTime(0), + fMinRerunTime(-1), + fMaxRerunTime(-1), + fUnspecifiedWaitTime(0), + fPreemptions(0), + fWaitObjectGroups(20, true) { } @@ -57,6 +141,111 @@ Model::Thread::~Thread() } +Model::ThreadWaitObjectGroup* +Model::Thread::ThreadWaitObjectGroupFor(uint32 type, addr_t object) const +{ + type_and_object key; + key.type = type; + key.object = object; + + return fWaitObjectGroups.BinarySearchByKey(key, + &ThreadWaitObjectGroup::CompareWithTypeObject); +} + + +void +Model::Thread::AddRun(bigtime_t runTime) +{ + fRuns++; + fTotalRunTime += runTime; + + if (fMinRunTime < 0 || runTime < fMinRunTime) + fMinRunTime = runTime; + if (runTime > fMaxRunTime) + fMaxRunTime = runTime; +} + + +void +Model::Thread::AddRerun(bigtime_t runTime) +{ + fReruns++; + fTotalRerunTime += runTime; + + if (fMinRerunTime < 0 || runTime < fMinRerunTime) + fMinRerunTime = runTime; + if (runTime > fMaxRerunTime) + fMaxRerunTime = runTime; +} + + +void +Model::Thread::AddLatency(bigtime_t latency) +{ + fLatencies++; + fTotalLatency += latency; + + if (fMinLatency < 0 || latency < fMinLatency) + fMinLatency = latency; + if (latency > fMaxLatency) + fMaxLatency = latency; +} + + +void +Model::Thread::AddPreemption(bigtime_t runTime) +{ + fPreemptions++; +} + + +void +Model::Thread::AddUnspecifiedWait(bigtime_t waitTime) +{ + fUnspecifiedWaitTime += waitTime; +} + + +Model::ThreadWaitObject* +Model::Thread::AddThreadWaitObject(WaitObject* waitObject, + ThreadWaitObjectGroup** _threadWaitObjectGroup) +{ + // create a thread wait object + ThreadWaitObject* threadWaitObject + = new(std::nothrow) ThreadWaitObject(waitObject); + if (threadWaitObject == NULL) + return NULL; + + // find the thread wait object group + ThreadWaitObjectGroup* threadWaitObjectGroup + = ThreadWaitObjectGroupFor(waitObject->Type(), waitObject->Object()); + if (threadWaitObjectGroup == NULL) { + // doesn't exist yet -- create + threadWaitObjectGroup = new(std::nothrow) ThreadWaitObjectGroup( + threadWaitObject); + if (threadWaitObjectGroup == NULL) { + delete threadWaitObject; + return NULL; + } + + // add to the list + if (!fWaitObjectGroups.BinaryInsert(threadWaitObjectGroup, + &ThreadWaitObjectGroup::CompareByTypeObject)) { + delete threadWaitObjectGroup; + return NULL; + } + } else { + // exists -- just add the object + threadWaitObjectGroup->AddWaitObject(threadWaitObject); + } + + if (_threadWaitObjectGroup != NULL) + *_threadWaitObjectGroup = threadWaitObjectGroup; + + return threadWaitObject; +} + + // #pragma mark - Model @@ -65,7 +254,8 @@ Model::Model(void* eventData, size_t eventDataSize) fEventData(eventData), fEventDataSize(eventDataSize), fTeams(20, true), - fThreads(20, true) + fThreads(20, true), + fWaitObjectGroups(20, true) { } @@ -176,3 +366,76 @@ Model::AddThread(const system_profiler_thread_added* event, bigtime_t time) threadDeleter.Detach(); return thread; } + + +Model::WaitObject* +Model::AddWaitObject(const system_profiler_wait_object_info* event, + WaitObjectGroup** _waitObjectGroup) +{ + // create a wait object + WaitObject* waitObject = new(std::nothrow) WaitObject(event); + if (waitObject == NULL) + return NULL; + + // find the wait object group + WaitObjectGroup* waitObjectGroup + = WaitObjectGroupFor(waitObject->Type(), waitObject->Object()); + if (waitObjectGroup == NULL) { + // doesn't exist yet -- create + waitObjectGroup = new(std::nothrow) WaitObjectGroup(waitObject); + if (waitObjectGroup == NULL) { + delete waitObject; + return NULL; + } + + // add to the list + if (!fWaitObjectGroups.BinaryInsert(waitObjectGroup, + &WaitObjectGroup::CompareByTypeObject)) { + delete waitObjectGroup; + return NULL; + } + } else { + // exists -- just add the object + waitObjectGroup->AddWaitObject(waitObject); + } + + if (_waitObjectGroup != NULL) + *_waitObjectGroup = waitObjectGroup; + + return waitObject; +} + + +Model::WaitObjectGroup* +Model::WaitObjectGroupFor(uint32 type, addr_t object) const +{ + type_and_object key; + key.type = type; + key.object = object; + + return fWaitObjectGroups.BinarySearchByKey(key, + &WaitObjectGroup::CompareWithTypeObject); +} + + +Model::ThreadWaitObject* +Model::AddThreadWaitObject(thread_id threadID, WaitObject* waitObject, + ThreadWaitObjectGroup** _threadWaitObjectGroup) +{ + Thread* thread = ThreadByID(threadID); + if (thread == NULL) + return NULL; + + return thread->AddThreadWaitObject(waitObject, _threadWaitObjectGroup); +} + + +Model::ThreadWaitObjectGroup* +Model::ThreadWaitObjectGroupFor(thread_id threadID, uint32 type, addr_t object) const +{ + Thread* thread = ThreadByID(threadID); + if (thread == NULL) + return NULL; + + return thread->ThreadWaitObjectGroupFor(type, object); +} diff --git a/src/apps/debuganalyzer/Model.h b/src/apps/debuganalyzer/Model.h index 7df322c11f..0f8f9617fb 100644 --- a/src/apps/debuganalyzer/Model.h +++ b/src/apps/debuganalyzer/Model.h @@ -9,11 +9,17 @@ #include #include +#include class Model { public: struct creation_time_id; + struct type_and_object; + class WaitObjectGroup; + class WaitObject; + class ThreadWaitObject; + class ThreadWaitObjectGroup; class Team; class Thread; @@ -35,15 +41,32 @@ public: const system_profiler_thread_added* event, bigtime_t time); + WaitObject* AddWaitObject( + const system_profiler_wait_object_info* + event, + WaitObjectGroup** _waitObjectGroup); + WaitObjectGroup* WaitObjectGroupFor(uint32 type, + addr_t object) const; + + ThreadWaitObject* AddThreadWaitObject(thread_id threadID, + WaitObject* waitObject, + ThreadWaitObjectGroup** + _threadWaitObjectGroup); + ThreadWaitObjectGroup* ThreadWaitObjectGroupFor( + thread_id threadID, uint32 type, + addr_t object) const; + private: typedef BObjectList TeamList; typedef BObjectList ThreadList; + typedef BObjectList WaitObjectGroupList; private: void* fEventData; size_t fEventDataSize; TeamList fTeams; // sorted by ID ThreadList fThreads; // sorted by ID + WaitObjectGroupList fWaitObjectGroups; }; @@ -53,6 +76,106 @@ struct Model::creation_time_id { }; +struct Model::type_and_object { + uint32 type; + addr_t object; +}; + + +class Model::WaitObject : public SinglyLinkedListLinkImpl { +public: + WaitObject( + const system_profiler_wait_object_info* + event); + ~WaitObject(); + + inline uint32 Type() const; + inline addr_t Object() const; + inline const char* Name() const; + inline addr_t ReferencedObject(); + + static inline int CompareByTypeObject(const WaitObject* a, + const WaitObject* b); + static inline int CompareWithTypeObject( + const type_and_object* key, + const WaitObject* object); + +private: + const system_profiler_wait_object_info* fEvent; +}; + + +class Model::WaitObjectGroup { +public: + WaitObjectGroup(WaitObject* waitObject); + ~WaitObjectGroup(); + + inline uint32 Type() const; + inline addr_t Object() const; + inline const char* Name() const; + + inline WaitObject* MostRecentWaitObject() const; + + inline void AddWaitObject(WaitObject* waitObject); + + static inline int CompareByTypeObject(const WaitObjectGroup* a, + const WaitObjectGroup* b); + static inline int CompareWithTypeObject( + const type_and_object* key, + const WaitObjectGroup* group); + +private: + typedef SinglyLinkedList WaitObjectList; + +private: + WaitObjectList fWaitObjects; +}; + + +class Model::ThreadWaitObject + : public SinglyLinkedListLinkImpl { +public: + ThreadWaitObject(WaitObject* waitObject); + ~ThreadWaitObject(); + + inline WaitObject* GetWaitObject() const; + + void AddWait(bigtime_t waitTime); + +private: + WaitObject* fWaitObject; + int64 fWaits; + bigtime_t fTotalWaitTime; +}; + + +class Model::ThreadWaitObjectGroup { +public: + ThreadWaitObjectGroup( + ThreadWaitObject* threadWaitObject); + ~ThreadWaitObjectGroup(); + + inline ThreadWaitObject* MostRecentThreadWaitObject() const; + inline WaitObject* MostRecentWaitObject() const; + + inline void AddWaitObject( + ThreadWaitObject* threadWaitObject); + + static inline int CompareByTypeObject( + const ThreadWaitObjectGroup* a, + const ThreadWaitObjectGroup* b); + static inline int CompareWithTypeObject( + const type_and_object* key, + const ThreadWaitObjectGroup* group); + +private: + typedef SinglyLinkedList ThreadWaitObjectList; + +private: + ThreadWaitObjectList fWaitObjects; +}; + + class Model::Team { public: Team(const system_profiler_team_added* event, @@ -96,8 +219,29 @@ public: inline bigtime_t CreationTime() const; inline bigtime_t DeletionTime() const; + inline int64 Runs() const; + inline bigtime_t TotalRunTime() const; + inline int64 Reruns() const; + inline bigtime_t TotalRerunTime() const; + inline int64 Latencies() const; + inline bigtime_t TotalLatency() const; + inline int64 Preemptions() const; + + ThreadWaitObjectGroup* ThreadWaitObjectGroupFor(uint32 type, + addr_t object) const; + inline void SetDeletionTime(bigtime_t time); + void AddRun(bigtime_t runTime); + void AddRerun(bigtime_t runTime); + void AddLatency(bigtime_t latency); + void AddPreemption(bigtime_t runTime); + void AddUnspecifiedWait(bigtime_t waitTime); + + ThreadWaitObject* AddThreadWaitObject(WaitObject* waitObject, + ThreadWaitObjectGroup** + _threadWaitObjectGroup); + static inline int CompareByID(const Thread* a, const Thread* b); static inline int CompareWithID(const thread_id* id, const Thread* thread); @@ -108,14 +252,206 @@ public: const creation_time_id* key, const Thread* thread); +private: + typedef BObjectList + ThreadWaitObjectGroupList; + private: Team* fTeam; const system_profiler_thread_added* fCreationEvent; bigtime_t fCreationTime; bigtime_t fDeletionTime; + + int64 fRuns; + bigtime_t fTotalRunTime; + bigtime_t fMinRunTime; + bigtime_t fMaxRunTime; + + int64 fLatencies; + bigtime_t fTotalLatency; + bigtime_t fMinLatency; + bigtime_t fMaxLatency; + + int64 fReruns; + bigtime_t fTotalRerunTime; + bigtime_t fMinRerunTime; + bigtime_t fMaxRerunTime; + + bigtime_t fUnspecifiedWaitTime; + + int64 fPreemptions; + + ThreadWaitObjectGroupList fWaitObjectGroups; }; +// #pragma mark - WaitObject + + +uint32 +Model::WaitObject::Type() const +{ + return fEvent->type; +} + + +addr_t +Model::WaitObject::Object() const +{ + return fEvent->object; +} + + +const char* +Model::WaitObject::Name() const +{ + return fEvent->name; +} + + +addr_t +Model::WaitObject::ReferencedObject() +{ + return fEvent->referenced_object; +} + + +/*static*/ int +Model::WaitObject::CompareByTypeObject(const WaitObject* a, const WaitObject* b) +{ + type_and_object key; + key.type = a->Type(); + key.object = a->Object(); + + return CompareWithTypeObject(&key, b); +} + + +/*static*/ int +Model::WaitObject::CompareWithTypeObject(const type_and_object* key, + const WaitObject* object) +{ + if (key->type == object->Type()) { + if (key->object == object->Object()) + return 0; + return key->object < object->Object() ? -1 : 1; + } + + return key->type < object->Type() ? -1 : 1; +} + + +// #pragma mark - WaitObjectGroup + + +uint32 +Model::WaitObjectGroup::Type() const +{ + return MostRecentWaitObject()->Type(); +} + + +addr_t +Model::WaitObjectGroup::Object() const +{ + return MostRecentWaitObject()->Object(); +} + + +const char* +Model::WaitObjectGroup::Name() const +{ + return MostRecentWaitObject()->Name(); +} + + +Model::WaitObject* +Model::WaitObjectGroup::MostRecentWaitObject() const +{ + return fWaitObjects.Head(); +} + + +void +Model::WaitObjectGroup::AddWaitObject(WaitObject* waitObject) +{ + fWaitObjects.Add(waitObject); +} + + +/*static*/ int +Model::WaitObjectGroup::CompareByTypeObject( + const WaitObjectGroup* a, const WaitObjectGroup* b) +{ + return WaitObject::CompareByTypeObject(a->MostRecentWaitObject(), + b->MostRecentWaitObject()); +} + + +/*static*/ int +Model::WaitObjectGroup::CompareWithTypeObject(const type_and_object* key, + const WaitObjectGroup* group) +{ + return WaitObject::CompareWithTypeObject(key, + group->MostRecentWaitObject()); +} + + +// #pragma mark - ThreadWaitObject + + +Model::WaitObject* +Model::ThreadWaitObject::GetWaitObject() const +{ + return fWaitObject; +} + + +// #pragma mark - ThreadWaitObjectGroup + + +Model::ThreadWaitObject* +Model::ThreadWaitObjectGroup::MostRecentThreadWaitObject() const +{ + return fWaitObjects.Head(); +} + + +Model::WaitObject* +Model::ThreadWaitObjectGroup::MostRecentWaitObject() const +{ + return MostRecentThreadWaitObject()->GetWaitObject(); +} + + +void +Model::ThreadWaitObjectGroup::AddWaitObject(ThreadWaitObject* threadWaitObject) +{ + fWaitObjects.Add(threadWaitObject); +} + + +/*static*/ int +Model::ThreadWaitObjectGroup::CompareByTypeObject( + const ThreadWaitObjectGroup* a, const ThreadWaitObjectGroup* b) +{ + return WaitObject::CompareByTypeObject(a->MostRecentWaitObject(), + b->MostRecentWaitObject()); +} + + +/*static*/ int +Model::ThreadWaitObjectGroup::CompareWithTypeObject(const type_and_object* key, + const ThreadWaitObjectGroup* group) +{ + return WaitObject::CompareWithTypeObject(key, + group->MostRecentWaitObject()); +} + + +// #pragma mark - Team + + team_id Model::Team::ID() const { @@ -158,6 +494,9 @@ Model::Team::CompareWithID(const team_id* id, const Team* team) } +// #pragma mark - Thread + + thread_id Model::Thread::ID() const { @@ -186,6 +525,55 @@ Model::Thread::DeletionTime() const } +int64 +Model::Thread::Runs() const +{ + return fRuns; +} + + +bigtime_t +Model::Thread::TotalRunTime() const +{ + return fTotalRunTime; +} + + +int64 +Model::Thread::Reruns() const +{ + return fReruns; +} + + +bigtime_t +Model::Thread::TotalRerunTime() const +{ + return fTotalRerunTime; +} + + +int64 +Model::Thread::Latencies() const +{ + return fLatencies; +} + + +bigtime_t +Model::Thread::TotalLatency() const +{ + return fTotalLatency; +} + + +int64 +Model::Thread::Preemptions() const +{ + return fPreemptions; +} + + void Model::Thread::SetDeletionTime(bigtime_t time) { diff --git a/src/apps/debuganalyzer/ModelLoader.cpp b/src/apps/debuganalyzer/ModelLoader.cpp index e96daeb79b..9fb0498437 100644 --- a/src/apps/debuganalyzer/ModelLoader.cpp +++ b/src/apps/debuganalyzer/ModelLoader.cpp @@ -15,12 +15,46 @@ #include #include +#include #include "DataSource.h" #include "MessageCodes.h" #include "Model.h" +struct SimpleWaitObjectInfo : system_profiler_wait_object_info { + SimpleWaitObjectInfo(uint32 type) + { + this->type = type; + object = 0; + referenced_object = 0; + name[0] = '\0'; + } +}; + + +static const SimpleWaitObjectInfo kSnoozeWaitObjectInfo( + THREAD_BLOCK_TYPE_SNOOZE); +static const SimpleWaitObjectInfo kSignalWaitObjectInfo( + THREAD_BLOCK_TYPE_SIGNAL); + + +// #pragma mark - ThreadInfo + + +ModelLoader::ThreadInfo::ThreadInfo(Model::Thread* thread) + : + thread(thread), + state(UNKNOWN), + lastTime(0), + waitObject(NULL) +{ +} + + +// #pragma mark - + + inline void ModelLoader::_UpdateLastEventTime(bigtime_t time) { @@ -71,6 +105,11 @@ ModelLoader::StartLoading() if (fModel != NULL || fLoading || fDataSource == NULL) return B_BAD_VALUE; + // init the hash tables + error = fThreads.Init(); + if (error != B_OK) + return error; + // spawn the loader thread fLoaderThread = spawn_thread(&_LoaderEntry, "main model loader", B_NORMAL_PRIORITY, this); @@ -133,6 +172,13 @@ ModelLoader::_Loader() // clean up and notify the target AutoLocker locker(fLock); + ThreadInfo* threadInfo = fThreads.Clear(); + while (threadInfo != NULL) { + ThreadInfo* nextInfo = threadInfo->fNext; + delete threadInfo; + threadInfo = nextInfo; + } + BMessage message; if (error == B_OK) { message.what = MSG_MODEL_LOADED_SUCCESSFULLY; @@ -181,6 +227,12 @@ ModelLoader::_Load() if (error != B_OK) return error; + // add the snooze and signal wait objects to the model + if (fModel->AddWaitObject(&kSnoozeWaitObjectInfo, NULL) == NULL + || fModel->AddWaitObject(&kSignalWaitObjectInfo, NULL) == NULL) { + return B_NO_MEMORY; + } + // process the events fBaseTime = -1; fLastEventTime = -1; @@ -294,91 +346,43 @@ ModelLoader::_ProcessEvent(uint32 event, uint32 cpu, const void* buffer, { switch (event) { case B_SYSTEM_PROFILER_TEAM_ADDED: - { - system_profiler_team_added* event - = (system_profiler_team_added*)buffer; - - if (fModel->AddTeam(event, fLastEventTime) == NULL) - return B_NO_MEMORY; - return B_OK; - } + _HandleTeamAdded((system_profiler_team_added*)buffer); + break; case B_SYSTEM_PROFILER_TEAM_REMOVED: - { - system_profiler_team_removed* event - = (system_profiler_team_removed*)buffer; - - if (Model::Team* team = fModel->TeamByID(event->team)) { - team->SetDeletionTime(fLastEventTime); - } else { - printf("Removed event for unknown team: %ld\n", event->team); - } + _HandleTeamRemoved((system_profiler_team_removed*)buffer); break; - } case B_SYSTEM_PROFILER_TEAM_EXEC: + _HandleTeamExec((system_profiler_team_exec*)buffer); break; case B_SYSTEM_PROFILER_THREAD_ADDED: - { - system_profiler_thread_added* event - = (system_profiler_thread_added*)buffer; - - if (fModel->AddThread(event, fLastEventTime) == NULL) - return B_NO_MEMORY; - return B_OK; - + _HandleThreadAdded((system_profiler_thread_added*)buffer); break; - } case B_SYSTEM_PROFILER_THREAD_REMOVED: - { - system_profiler_thread_removed* event - = (system_profiler_thread_removed*)buffer; - - if (Model::Thread* thread = fModel->ThreadByID(event->thread)) { - thread->SetDeletionTime(fLastEventTime); - } else { - printf("Removed event for unknown team: %ld\n", event->thread); - } + _HandleThreadRemoved((system_profiler_thread_removed*)buffer); break; - } case B_SYSTEM_PROFILER_THREAD_SCHEDULED: - { - system_profiler_thread_scheduled* event - = (system_profiler_thread_scheduled*)buffer; - - _UpdateLastEventTime(event->time); - - // TODO:... + _HandleThreadScheduled((system_profiler_thread_scheduled*)buffer); break; - } case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE: - { - system_profiler_thread_enqueued_in_run_queue* event - = (system_profiler_thread_enqueued_in_run_queue*)buffer; - - _UpdateLastEventTime(event->time); - - // TODO:... + _HandleThreadEnqueuedInRunQueue( + (thread_enqueued_in_run_queue*)buffer); break; - } case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE: - { - system_profiler_thread_removed_from_run_queue* event - = (system_profiler_thread_removed_from_run_queue*)buffer; - - _UpdateLastEventTime(event->time); - - // TODO:... + _HandleThreadRemovedFromRunQueue( + (thread_removed_from_run_queue*)buffer); break; - } case B_SYSTEM_PROFILER_WAIT_OBJECT_INFO: + _HandleWaitObjectInfo((system_profiler_wait_object_info*)buffer); break; + default: printf("unsupported event type %lu, size: %lu\n", event, size); return B_BAD_DATA; @@ -387,3 +391,267 @@ return B_BAD_DATA; return B_OK; } + + +void +ModelLoader::_HandleTeamAdded(system_profiler_team_added* event) +{ + if (fModel->AddTeam(event, fLastEventTime) == NULL) + throw std::bad_alloc(); +} + + +void +ModelLoader::_HandleTeamRemoved(system_profiler_team_removed* event) +{ + if (Model::Team* team = fModel->TeamByID(event->team)) + team->SetDeletionTime(fLastEventTime); + else + printf("Removed event for unknown team: %ld\n", event->team); +} + + +void +ModelLoader::_HandleTeamExec(system_profiler_team_exec* event) +{ + // TODO:... +} + + +void +ModelLoader::_HandleThreadAdded(system_profiler_thread_added* event) +{ + if (_AddThread(event) == NULL) + throw std::bad_alloc(); +} + + +void +ModelLoader::_HandleThreadRemoved(system_profiler_thread_removed* event) +{ + if (Model::Thread* thread = fModel->ThreadByID(event->thread)) + thread->SetDeletionTime(fLastEventTime); + else + printf("Removed event for unknown team: %ld\n", event->thread); +} + + +void +ModelLoader::_HandleThreadScheduled(system_profiler_thread_scheduled* event) +{ + _UpdateLastEventTime(event->time); + + ThreadInfo* thread = fThreads.Lookup(event->thread); + if (thread == NULL) { + printf("Schedule event for unknown thread: %ld\n", event->thread); + return; + } + + bigtime_t diffTime = fLastEventTime - thread->lastTime; + + if (thread->state == READY) { + // thread scheduled after having been woken up + thread->thread->AddLatency(diffTime); + } else if (thread->state == PREEMPTED) { + // thread scheduled after having been preempted before + thread->thread->AddRerun(diffTime); + } + + if (thread->state == STILL_RUNNING) { + // Thread was running and continues to run. + thread->state = RUNNING; + } + + if (thread->state != RUNNING) { + thread->lastTime = fLastEventTime; + thread->state = RUNNING; + } + + // unscheduled thread + + if (event->thread == event->previous_thread) + return; + + thread = fThreads.Lookup(event->previous_thread); + if (thread == NULL) { + printf("Schedule event for unknown previous thread: %ld\n", + event->previous_thread); + return; + } + + diffTime = fLastEventTime - thread->lastTime; + + if (thread->state == STILL_RUNNING) { + // thread preempted + thread->thread->AddPreemption(diffTime); + thread->thread->AddRun(diffTime); + + thread->lastTime = fLastEventTime; + thread->state = PREEMPTED; + } else if (thread->state == RUNNING) { + // thread starts waiting (it hadn't been added to the run + // queue before being unscheduled) + thread->thread->AddRun(diffTime); + + if (event->previous_thread_state == B_THREAD_WAITING) { + addr_t waitObject = event->previous_thread_wait_object; + switch (event->previous_thread_wait_object_type) { + case THREAD_BLOCK_TYPE_SNOOZE: + case THREAD_BLOCK_TYPE_SIGNAL: + waitObject = 0; + break; + case THREAD_BLOCK_TYPE_SEMAPHORE: + case THREAD_BLOCK_TYPE_CONDITION_VARIABLE: + case THREAD_BLOCK_TYPE_MUTEX: + case THREAD_BLOCK_TYPE_RW_LOCK: + case THREAD_BLOCK_TYPE_OTHER: + default: + break; + } + + _AddThreadWaitObject(thread, + event->previous_thread_wait_object_type, waitObject); + } + + thread->lastTime = fLastEventTime; + thread->state = WAITING; + } else if (thread->state == UNKNOWN) { + uint32 threadState = event->previous_thread_state; + if (threadState == B_THREAD_WAITING + || threadState == B_THREAD_SUSPENDED) { + thread->lastTime = fLastEventTime; + thread->state = WAITING; + } else if (threadState == B_THREAD_READY) { + thread->lastTime = fLastEventTime; + thread->state = PREEMPTED; + } + } +} + + +void +ModelLoader::_HandleThreadEnqueuedInRunQueue( + thread_enqueued_in_run_queue* event) +{ + _UpdateLastEventTime(event->time); + + ThreadInfo* thread = fThreads.Lookup(event->thread); + if (thread == NULL) { + printf("Enqueued in run queue event for unknown thread: %ld\n", + event->thread); + return; + } + + if (thread->state == RUNNING || thread->state == STILL_RUNNING) { + // Thread was running and is reentered into the run queue. This + // is done by the scheduler, if the thread remains ready. + thread->state = STILL_RUNNING; + } else { + // Thread was waiting and is ready now. + bigtime_t diffTime = fLastEventTime - thread->lastTime; + if (thread->waitObject != NULL) { + thread->waitObject->AddWait(diffTime); + thread->waitObject = NULL; + } else if (thread->state != UNKNOWN) + thread->thread->AddUnspecifiedWait(diffTime); + + thread->lastTime = fLastEventTime; + thread->state = READY; + } +} + + +void +ModelLoader::_HandleThreadRemovedFromRunQueue( + thread_removed_from_run_queue* event) +{ + _UpdateLastEventTime(event->time); + + ThreadInfo* thread = fThreads.Lookup(event->thread); + if (thread == NULL) { + printf("Removed from run queue event for unknown thread: %ld\n", + event->thread); + return; + } + + // This really only happens when the thread priority is changed + // while the thread is ready. + + bigtime_t diffTime = fLastEventTime - thread->lastTime; + if (thread->state == RUNNING) { + // This should never happen. + thread->thread->AddRun(diffTime); + } else if (thread->state == READY || thread->state == PREEMPTED) { + // Not really correct, but the case is rare and we keep it + // simple. + thread->thread->AddUnspecifiedWait(diffTime); + } + + thread->lastTime = fLastEventTime; + thread->state = WAITING; +} + + +void +ModelLoader::_HandleWaitObjectInfo(system_profiler_wait_object_info* event) +{ + if (fModel->AddWaitObject(event, NULL) == NULL) + throw std::bad_alloc(); +} + + +ModelLoader::ThreadInfo* +ModelLoader::_AddThread(system_profiler_thread_added* event) +{ + // do we know the thread already? + ThreadInfo* info = fThreads.Lookup(event->thread); + if (info != NULL) { + // TODO: ? + return info; + } + + // add the thread to the model + Model::Thread* thread = fModel->AddThread(event, fLastEventTime); + if (thread == NULL) + return NULL; + + // create and add a ThreadInfo + info = new(std::nothrow) ThreadInfo(thread); + if (info == NULL) + return NULL; + + fThreads.Insert(info); + + return info; +} + + +void +ModelLoader::_AddThreadWaitObject(ThreadInfo* thread, uint32 type, + addr_t object) +{ + Model::WaitObjectGroup* waitObjectGroup + = fModel->WaitObjectGroupFor(type, object); + if (waitObjectGroup == NULL) { + // The algorithm should prevent this case. +printf("ModelLoader::_AddThreadWaitObject(): Unknown wait object: type: %lu, " +"object: %#lx\n", type, object); + return; + } + + Model::WaitObject* waitObject = waitObjectGroup->MostRecentWaitObject(); + + Model::ThreadWaitObjectGroup* threadWaitObjectGroup + = fModel->ThreadWaitObjectGroupFor(thread->ID(), type, object); + + if (threadWaitObjectGroup == NULL + || threadWaitObjectGroup->MostRecentWaitObject() != waitObject) { + Model::ThreadWaitObject* threadWaitObject + = fModel->AddThreadWaitObject(thread->ID(), waitObject, + &threadWaitObjectGroup); + if (threadWaitObject == NULL) + throw std::bad_alloc(); + } + + thread->waitObject = threadWaitObjectGroup->MostRecentThreadWaitObject(); +} diff --git a/src/apps/debuganalyzer/ModelLoader.h b/src/apps/debuganalyzer/ModelLoader.h index 2e56402d8f..17ee7ab386 100644 --- a/src/apps/debuganalyzer/ModelLoader.h +++ b/src/apps/debuganalyzer/ModelLoader.h @@ -8,12 +8,15 @@ #include #include +#include + +#include "Model.h" + class BDataIO; class BDebugEventInputStream; class DataSource; -class Model; -struct system_profiler_event_header; +struct system_profiler_thread_added; class ModelLoader { @@ -28,6 +31,52 @@ public: Model* DetachModel(); +private: + enum ScheduleState { + RUNNING, + STILL_RUNNING, + PREEMPTED, + READY, + WAITING, + UNKNOWN + }; + + struct ThreadInfo : HashTableLink { + Model::Thread* thread; + ScheduleState state; + bigtime_t lastTime; + Model::ThreadWaitObject* waitObject; + + ThreadInfo(Model::Thread* thread); + + thread_id ID() const { return thread->ID(); } + }; + + struct ThreadTableDefinition { + typedef thread_id KeyType; + typedef ThreadInfo ValueType; + + size_t HashKey(thread_id key) const + { return (size_t)key; } + + size_t Hash(const ThreadInfo* value) const + { return (size_t)value->ID(); } + + bool Compare(thread_id key, const ThreadInfo* value) const + { return key == value->ID(); } + + HashTableLink* GetLink(ThreadInfo* value) const + { return value; } + }; + + typedef OpenHashTable ThreadTable; + + // shorthands for the longish structure names + typedef system_profiler_thread_enqueued_in_run_queue + thread_enqueued_in_run_queue; + typedef system_profiler_thread_removed_from_run_queue + thread_removed_from_run_queue; + private: static status_t _LoaderEntry(void* data); status_t _Loader(); @@ -39,6 +88,29 @@ private: inline void _UpdateLastEventTime(bigtime_t time); + void _HandleTeamAdded( + system_profiler_team_added* event); + void _HandleTeamRemoved( + system_profiler_team_removed* event); + void _HandleTeamExec( + system_profiler_team_exec* event); + void _HandleThreadAdded( + system_profiler_thread_added* event); + void _HandleThreadRemoved( + system_profiler_thread_removed* event); + void _HandleThreadScheduled( + system_profiler_thread_scheduled* event); + void _HandleThreadEnqueuedInRunQueue( + thread_enqueued_in_run_queue* event); + void _HandleThreadRemovedFromRunQueue( + thread_removed_from_run_queue* event); + void _HandleWaitObjectInfo( + system_profiler_wait_object_info* event); + + ThreadInfo* _AddThread(system_profiler_thread_added* event); + void _AddThreadWaitObject(ThreadInfo* thread, + uint32 type, addr_t object); + private: BLocker fLock; Model* fModel; @@ -50,6 +122,7 @@ private: bool fAborted; bigtime_t fBaseTime; bigtime_t fLastEventTime; + ThreadTable fThreads; };