diff --git a/src/apps/debuganalyzer/gui/main_window/GeneralPage.cpp b/src/apps/debuganalyzer/gui/main_window/GeneralPage.cpp index 449152cc18..d862a1c640 100644 --- a/src/apps/debuganalyzer/gui/main_window/GeneralPage.cpp +++ b/src/apps/debuganalyzer/gui/main_window/GeneralPage.cpp @@ -15,12 +15,16 @@ MainWindow::GeneralPage::GeneralPage() AbstractGeneralPage(), fModel(NULL), fDataSourceView(NULL), + fCPUCountView(NULL), fRunTimeView(NULL), + fIdleTimeView(NULL), fTeamCountView(NULL), fThreadCountView(NULL) { fDataSourceView = AddDataView("Data Source:"); - fRunTimeView = AddDataView("Run Time:"); + fCPUCountView = AddDataView("Number of CPUs:"); + fRunTimeView = AddDataView("Total Time:"); + fIdleTimeView = AddDataView("Idle Time:"); fTeamCountView = AddDataView("Teams:"); fThreadCountView = AddDataView("Threads:"); } @@ -43,10 +47,25 @@ MainWindow::GeneralPage::SetModel(Model* model) // data source fDataSourceView->SetText(fModel->DataSourceName()); - // run time + // cpu count char buffer[128]; - fRunTimeView->SetText(format_nanotime(fModel->LastEventTime(), buffer, - sizeof(buffer))); + snprintf(buffer, sizeof(buffer), "%" B_PRId32, fModel->CountCPUs()); + fCPUCountView->SetText(buffer); + + // run time + nanotime_t runtime = fModel->LastEventTime(); + fRunTimeView->SetText(format_nanotime(runtime, buffer, sizeof(buffer))); + + // idle time + if (runtime == 0) + runtime = 1; + double idlePercentage = (double)fModel->IdleTime() + / (runtime * fModel->CountCPUs()) * 100; + char timeBuffer[64]; + format_nanotime(fModel->IdleTime(), timeBuffer, sizeof(timeBuffer)); + snprintf(buffer, sizeof(buffer), "%s (%.2f %%)", timeBuffer, + idlePercentage); + fIdleTimeView->SetText(buffer); // team count snprintf(buffer, sizeof(buffer), "%ld", fModel->CountTeams()); @@ -57,7 +76,9 @@ MainWindow::GeneralPage::SetModel(Model* model) fThreadCountView->SetText(buffer); } else { fDataSourceView->SetText(""); + fCPUCountView->SetText(""); fRunTimeView->SetText(""); + fIdleTimeView->SetText(""); fTeamCountView->SetText(""); fThreadCountView->SetText(""); } diff --git a/src/apps/debuganalyzer/gui/main_window/GeneralPage.h b/src/apps/debuganalyzer/gui/main_window/GeneralPage.h index dc10646b60..317119a742 100644 --- a/src/apps/debuganalyzer/gui/main_window/GeneralPage.h +++ b/src/apps/debuganalyzer/gui/main_window/GeneralPage.h @@ -22,7 +22,9 @@ public: private: Model* fModel; TextDataView* fDataSourceView; + TextDataView* fCPUCountView; TextDataView* fRunTimeView; + TextDataView* fIdleTimeView; TextDataView* fTeamCountView; TextDataView* fThreadCountView; }; diff --git a/src/apps/debuganalyzer/model/Model.cpp b/src/apps/debuganalyzer/model/Model.cpp index 7bc0acb138..e129a81148 100644 --- a/src/apps/debuganalyzer/model/Model.cpp +++ b/src/apps/debuganalyzer/model/Model.cpp @@ -14,6 +14,23 @@ #include +// #pragma mark - CPU + + +Model::CPU::CPU() + : + fIdleTime(0) +{ +} + + +void +Model::CPU::SetIdleTime(nanotime_t time) +{ + fIdleTime = time; +} + + // #pragma mark - WaitObject @@ -445,8 +462,11 @@ Model::Model(const char* dataSourceName, void* eventData, size_t eventDataSize) fDataSourceName(dataSourceName), fEventData(eventData), fEventDataSize(eventDataSize), + fCPUCount(1), fBaseTime(0), fLastEventTime(0), + fIdleTime(0), + fCPUs(20, true), fTeams(20, true), fThreads(20, true), fWaitObjectGroups(20, true), @@ -469,8 +489,14 @@ Model::~Model() void Model::LoadingFinished() { + // set the thread indices for (int32 i = 0; Thread* thread = fThreads.ItemAt(i); i++) thread->SetIndex(i); + + // compute the total idle time + fIdleTime = 0; + for (int32 i = 0; CPU* cpu = CPUAt(i); i++) + fIdleTime += cpu->IdleTime(); } @@ -488,6 +514,25 @@ Model::SetLastEventTime(nanotime_t time) } +bool +Model::SetCPUCount(int32 count) +{ + fCPUCount = count; + + fCPUs.MakeEmpty(); + + for (int32 i = 0; i < fCPUCount; i++) { + CPU* cpu = new(std::nothrow) CPU; + if (cpu == NULL || !fCPUs.AddItem(cpu)) { + delete cpu; + return false; + } + } + + return true; +} + + int32 Model::CountTeams() const { diff --git a/src/apps/debuganalyzer/model/Model.h b/src/apps/debuganalyzer/model/Model.h index c8d8284b74..1a68b16c1e 100644 --- a/src/apps/debuganalyzer/model/Model.h +++ b/src/apps/debuganalyzer/model/Model.h @@ -33,6 +33,7 @@ class Model : public Referenceable { public: struct creation_time_id; struct type_and_object; + class CPU; class WaitObjectGroup; class WaitObject; class ThreadWaitObject; @@ -64,6 +65,12 @@ public: inline nanotime_t LastEventTime() const; void SetLastEventTime(nanotime_t time); + inline nanotime_t IdleTime() const; + + inline int32 CountCPUs() const; + bool SetCPUCount(int32 count); + inline CPU* CPUAt(int32 index) const; + int32 CountTeams() const; Team* TeamAt(int32 index) const; Team* TeamByID(team_id id) const; @@ -105,6 +112,7 @@ public: // returns the closest previous state private: + typedef BObjectList CPUList; typedef BObjectList TeamList; typedef BObjectList ThreadList; typedef BObjectList WaitObjectGroupList; @@ -118,8 +126,11 @@ private: BString fDataSourceName; void* fEventData; size_t fEventDataSize; + int32 fCPUCount; nanotime_t fBaseTime; nanotime_t fLastEventTime; + nanotime_t fIdleTime; + CPUList fCPUs; TeamList fTeams; // sorted by ID ThreadList fThreads; // sorted by ID WaitObjectGroupList fWaitObjectGroups; @@ -139,6 +150,18 @@ struct Model::type_and_object { }; +class Model::CPU { +public: + CPU(); + + inline nanotime_t IdleTime() const; + void SetIdleTime(nanotime_t time); + +private: + nanotime_t fIdleTime; +}; + + class Model::WaitObject { public: WaitObject( @@ -392,6 +415,7 @@ struct Model::CompactThreadSchedulingState { Model::Thread* thread; ThreadWaitObject* waitObject; ThreadState state; + uint8 priority; public: thread_id ID() const { return thread->ID(); } @@ -519,6 +543,37 @@ Model::LastEventTime() const } +nanotime_t +Model::IdleTime() const +{ + return fIdleTime; +} + + +int32 +Model::CountCPUs() const +{ + return fCPUCount; +} + + +Model::CPU* +Model::CPUAt(int32 index) const +{ + return fCPUs.ItemAt(index); +} + + +// #pragma mark - CPU + + +nanotime_t +Model::CPU::IdleTime() const +{ + return fIdleTime; +} + + // #pragma mark - WaitObject @@ -995,6 +1050,7 @@ Model::CompactThreadSchedulingState::operator=( thread = other.thread; waitObject = other.waitObject; state = other.state; + priority = other.priority; return *this; } diff --git a/src/apps/debuganalyzer/model_loader/ModelLoader.cpp b/src/apps/debuganalyzer/model_loader/ModelLoader.cpp index 1c544006cd..c41d9ad4f1 100644 --- a/src/apps/debuganalyzer/model_loader/ModelLoader.cpp +++ b/src/apps/debuganalyzer/model_loader/ModelLoader.cpp @@ -26,6 +26,8 @@ // add a scheduling state snapshot every x events static const uint32 kSchedulingSnapshotInterval = 1024; +static const uint32 kMaxCPUCount = 1024; + struct SimpleWaitObjectInfo : system_profiler_wait_object_info { SimpleWaitObjectInfo(uint32 type) @@ -44,6 +46,17 @@ static const SimpleWaitObjectInfo kSignalWaitObjectInfo( THREAD_BLOCK_TYPE_SIGNAL); +struct ModelLoader::CPUInfo { + nanotime_t idleTime; + + CPUInfo() + : + idleTime(0) + { + } +}; + + // #pragma mark - @@ -64,13 +77,15 @@ ModelLoader::ModelLoader(DataSource* dataSource, : AbstractModelLoader(target, targetCookie), fModel(NULL), - fDataSource(dataSource) + fDataSource(dataSource), + fCPUInfos(NULL) { } ModelLoader::~ModelLoader() { + delete[] fCPUInfos; delete fDataSource; delete fModel; } @@ -102,6 +117,10 @@ ModelLoader::PrepareForLoading() if (error != B_OK) return error; + fCPUInfos = new(std::nothrow) CPUInfo[kMaxCPUCount]; + if (fCPUInfos == NULL) + return B_NO_MEMORY; + return B_OK; } @@ -126,6 +145,9 @@ ModelLoader::FinishLoading(bool success) delete fModel; fModel = NULL; } + + delete[] fCPUInfos; + fCPUInfos = NULL; } @@ -168,6 +190,7 @@ ModelLoader::_Load() } // process the events + fMaxCPUIndex = 0; fState.Clear(); fBaseTime = -1; uint64 count = 0; @@ -190,6 +213,12 @@ ModelLoader::_Load() if (error != B_OK) return error; + if (cpu > fMaxCPUIndex) { + if (cpu + 1 > kMaxCPUCount) + return B_BAD_DATA; + fMaxCPUIndex = cpu; + } + // periodically check whether we're supposed to abort if (++count % 32 == 0) { AutoLocker locker(fLock); @@ -202,6 +231,12 @@ ModelLoader::_Load() fModel->AddSchedulingStateSnapshot(fState, offset); } + if (!fModel->SetCPUCount(fMaxCPUIndex + 1)) + return B_NO_MEMORY; + + for (uint32 i = 0; i <= fMaxCPUIndex; i++) + fModel->CPUAt(i)->SetIdleTime(fCPUInfos[i].idleTime); + fModel->SetLastEventTime(fState.LastEventTime()); fModel->LoadingFinished(); @@ -311,7 +346,8 @@ ModelLoader::_ProcessEvent(uint32 event, uint32 cpu, const void* buffer, break; case B_SYSTEM_PROFILER_THREAD_SCHEDULED: - _HandleThreadScheduled((system_profiler_thread_scheduled*)buffer); + _HandleThreadScheduled(cpu, + (system_profiler_thread_scheduled*)buffer); break; case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE: @@ -320,7 +356,7 @@ ModelLoader::_ProcessEvent(uint32 event, uint32 cpu, const void* buffer, break; case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE: - _HandleThreadRemovedFromRunQueue( + _HandleThreadRemovedFromRunQueue(cpu, (thread_removed_from_run_queue*)buffer); break; @@ -382,7 +418,8 @@ ModelLoader::_HandleThreadRemoved(system_profiler_thread_removed* event) void -ModelLoader::_HandleThreadScheduled(system_profiler_thread_scheduled* event) +ModelLoader::_HandleThreadScheduled(uint32 cpu, + system_profiler_thread_scheduled* event) { _UpdateLastEventTime(event->time); @@ -430,6 +467,8 @@ ModelLoader::_HandleThreadScheduled(system_profiler_thread_scheduled* event) // thread preempted thread->thread->AddPreemption(diffTime); thread->thread->AddRun(diffTime); + if (thread->priority == 0) + _AddIdleTime(cpu, diffTime); thread->lastTime = fState.LastEventTime(); thread->state = PREEMPTED; @@ -437,6 +476,8 @@ ModelLoader::_HandleThreadScheduled(system_profiler_thread_scheduled* event) // thread starts waiting (it hadn't been added to the run // queue before being unscheduled) thread->thread->AddRun(diffTime); + if (thread->priority == 0) + _AddIdleTime(cpu, diffTime); if (event->previous_thread_state == B_THREAD_WAITING) { addr_t waitObject = event->previous_thread_wait_object; @@ -504,11 +545,13 @@ ModelLoader::_HandleThreadEnqueuedInRunQueue( thread->lastTime = fState.LastEventTime(); thread->state = READY; } + + thread->priority = event->priority; } void -ModelLoader::_HandleThreadRemovedFromRunQueue( +ModelLoader::_HandleThreadRemovedFromRunQueue(uint32 cpu, thread_removed_from_run_queue* event) { _UpdateLastEventTime(event->time); @@ -527,6 +570,8 @@ ModelLoader::_HandleThreadRemovedFromRunQueue( if (thread->state == RUNNING) { // This should never happen. thread->thread->AddRun(diffTime); + if (thread->priority == 0) + _AddIdleTime(cpu, diffTime); } else if (thread->state == READY || thread->state == PREEMPTED) { // Not really correct, but the case is rare and we keep it // simple. @@ -566,6 +611,13 @@ ModelLoader::_AddThread(system_profiler_thread_added* event) if (info == NULL) return NULL; + // TODO: The priority is missing from the system_profiler_thread_added + // struct. For now guess at least whether this is an idle thread. + if (strncmp(event->name, "idle thread", strlen("idle thread")) == 0) + info->priority = 0; + else + info->priority = B_NORMAL_PRIORITY; + fState.InsertThread(info); return info; @@ -601,3 +653,10 @@ printf("ModelLoader::_AddThreadWaitObject(): Unknown wait object: type: %lu, " thread->waitObject = threadWaitObjectGroup->MostRecentThreadWaitObject(); } + + +void +ModelLoader::_AddIdleTime(uint32 cpu, nanotime_t time) +{ + fCPUInfos[cpu].idleTime += time; +} diff --git a/src/apps/debuganalyzer/model_loader/ModelLoader.h b/src/apps/debuganalyzer/model_loader/ModelLoader.h index d84e083965..c638d7e4c5 100644 --- a/src/apps/debuganalyzer/model_loader/ModelLoader.h +++ b/src/apps/debuganalyzer/model_loader/ModelLoader.h @@ -40,6 +40,8 @@ private: typedef system_profiler_thread_removed_from_run_queue thread_removed_from_run_queue; + struct CPUInfo; + private: status_t _Load(); status_t _ReadDebugEvents(void** _eventData, @@ -59,11 +61,11 @@ private: system_profiler_thread_added* event); void _HandleThreadRemoved( system_profiler_thread_removed* event); - void _HandleThreadScheduled( + void _HandleThreadScheduled(uint32 cpu, system_profiler_thread_scheduled* event); void _HandleThreadEnqueuedInRunQueue( thread_enqueued_in_run_queue* event); - void _HandleThreadRemovedFromRunQueue( + void _HandleThreadRemovedFromRunQueue(uint32 cpu, thread_removed_from_run_queue* event); void _HandleWaitObjectInfo( system_profiler_wait_object_info* event); @@ -73,11 +75,15 @@ private: void _AddThreadWaitObject(Model::ThreadSchedulingState* thread, uint32 type, addr_t object); + void _AddIdleTime(uint32 cpu, nanotime_t time); + private: Model* fModel; DataSource* fDataSource; + CPUInfo* fCPUInfos; nanotime_t fBaseTime; Model::SchedulingState fState; + uint32 fMaxCPUIndex; };