* Also compute the number of CPUs and the idle time of each CPU.

* Show the CPU count and the total idle time in the "General" page.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34585 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-12-09 12:02:44 +00:00
parent 94a6d7ada8
commit bea40bcd49
6 changed files with 200 additions and 11 deletions
@@ -15,12 +15,16 @@ MainWindow::GeneralPage::GeneralPage()
AbstractGeneralPage(), AbstractGeneralPage(),
fModel(NULL), fModel(NULL),
fDataSourceView(NULL), fDataSourceView(NULL),
fCPUCountView(NULL),
fRunTimeView(NULL), fRunTimeView(NULL),
fIdleTimeView(NULL),
fTeamCountView(NULL), fTeamCountView(NULL),
fThreadCountView(NULL) fThreadCountView(NULL)
{ {
fDataSourceView = AddDataView("Data Source:"); fDataSourceView = AddDataView("Data Source:");
fRunTimeView = AddDataView("Run Time:"); fCPUCountView = AddDataView("Number of CPUs:");
fRunTimeView = AddDataView("Total Time:");
fIdleTimeView = AddDataView("Idle Time:");
fTeamCountView = AddDataView("Teams:"); fTeamCountView = AddDataView("Teams:");
fThreadCountView = AddDataView("Threads:"); fThreadCountView = AddDataView("Threads:");
} }
@@ -43,10 +47,25 @@ MainWindow::GeneralPage::SetModel(Model* model)
// data source // data source
fDataSourceView->SetText(fModel->DataSourceName()); fDataSourceView->SetText(fModel->DataSourceName());
// run time // cpu count
char buffer[128]; char buffer[128];
fRunTimeView->SetText(format_nanotime(fModel->LastEventTime(), buffer, snprintf(buffer, sizeof(buffer), "%" B_PRId32, fModel->CountCPUs());
sizeof(buffer))); 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 // team count
snprintf(buffer, sizeof(buffer), "%ld", fModel->CountTeams()); snprintf(buffer, sizeof(buffer), "%ld", fModel->CountTeams());
@@ -57,7 +76,9 @@ MainWindow::GeneralPage::SetModel(Model* model)
fThreadCountView->SetText(buffer); fThreadCountView->SetText(buffer);
} else { } else {
fDataSourceView->SetText(""); fDataSourceView->SetText("");
fCPUCountView->SetText("");
fRunTimeView->SetText(""); fRunTimeView->SetText("");
fIdleTimeView->SetText("");
fTeamCountView->SetText(""); fTeamCountView->SetText("");
fThreadCountView->SetText(""); fThreadCountView->SetText("");
} }
@@ -22,7 +22,9 @@ public:
private: private:
Model* fModel; Model* fModel;
TextDataView* fDataSourceView; TextDataView* fDataSourceView;
TextDataView* fCPUCountView;
TextDataView* fRunTimeView; TextDataView* fRunTimeView;
TextDataView* fIdleTimeView;
TextDataView* fTeamCountView; TextDataView* fTeamCountView;
TextDataView* fThreadCountView; TextDataView* fThreadCountView;
}; };
+45
View File
@@ -14,6 +14,23 @@
#include <AutoDeleter.h> #include <AutoDeleter.h>
// #pragma mark - CPU
Model::CPU::CPU()
:
fIdleTime(0)
{
}
void
Model::CPU::SetIdleTime(nanotime_t time)
{
fIdleTime = time;
}
// #pragma mark - WaitObject // #pragma mark - WaitObject
@@ -445,8 +462,11 @@ Model::Model(const char* dataSourceName, void* eventData, size_t eventDataSize)
fDataSourceName(dataSourceName), fDataSourceName(dataSourceName),
fEventData(eventData), fEventData(eventData),
fEventDataSize(eventDataSize), fEventDataSize(eventDataSize),
fCPUCount(1),
fBaseTime(0), fBaseTime(0),
fLastEventTime(0), fLastEventTime(0),
fIdleTime(0),
fCPUs(20, true),
fTeams(20, true), fTeams(20, true),
fThreads(20, true), fThreads(20, true),
fWaitObjectGroups(20, true), fWaitObjectGroups(20, true),
@@ -469,8 +489,14 @@ Model::~Model()
void void
Model::LoadingFinished() Model::LoadingFinished()
{ {
// set the thread indices
for (int32 i = 0; Thread* thread = fThreads.ItemAt(i); i++) for (int32 i = 0; Thread* thread = fThreads.ItemAt(i); i++)
thread->SetIndex(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 int32
Model::CountTeams() const Model::CountTeams() const
{ {
+56
View File
@@ -33,6 +33,7 @@ class Model : public Referenceable {
public: public:
struct creation_time_id; struct creation_time_id;
struct type_and_object; struct type_and_object;
class CPU;
class WaitObjectGroup; class WaitObjectGroup;
class WaitObject; class WaitObject;
class ThreadWaitObject; class ThreadWaitObject;
@@ -64,6 +65,12 @@ public:
inline nanotime_t LastEventTime() const; inline nanotime_t LastEventTime() const;
void SetLastEventTime(nanotime_t time); 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; int32 CountTeams() const;
Team* TeamAt(int32 index) const; Team* TeamAt(int32 index) const;
Team* TeamByID(team_id id) const; Team* TeamByID(team_id id) const;
@@ -105,6 +112,7 @@ public:
// returns the closest previous state // returns the closest previous state
private: private:
typedef BObjectList<CPU> CPUList;
typedef BObjectList<Team> TeamList; typedef BObjectList<Team> TeamList;
typedef BObjectList<Thread> ThreadList; typedef BObjectList<Thread> ThreadList;
typedef BObjectList<WaitObjectGroup> WaitObjectGroupList; typedef BObjectList<WaitObjectGroup> WaitObjectGroupList;
@@ -118,8 +126,11 @@ private:
BString fDataSourceName; BString fDataSourceName;
void* fEventData; void* fEventData;
size_t fEventDataSize; size_t fEventDataSize;
int32 fCPUCount;
nanotime_t fBaseTime; nanotime_t fBaseTime;
nanotime_t fLastEventTime; nanotime_t fLastEventTime;
nanotime_t fIdleTime;
CPUList fCPUs;
TeamList fTeams; // sorted by ID TeamList fTeams; // sorted by ID
ThreadList fThreads; // sorted by ID ThreadList fThreads; // sorted by ID
WaitObjectGroupList fWaitObjectGroups; 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 { class Model::WaitObject {
public: public:
WaitObject( WaitObject(
@@ -392,6 +415,7 @@ struct Model::CompactThreadSchedulingState {
Model::Thread* thread; Model::Thread* thread;
ThreadWaitObject* waitObject; ThreadWaitObject* waitObject;
ThreadState state; ThreadState state;
uint8 priority;
public: public:
thread_id ID() const { return thread->ID(); } 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 // #pragma mark - WaitObject
@@ -995,6 +1050,7 @@ Model::CompactThreadSchedulingState::operator=(
thread = other.thread; thread = other.thread;
waitObject = other.waitObject; waitObject = other.waitObject;
state = other.state; state = other.state;
priority = other.priority;
return *this; return *this;
} }
@@ -26,6 +26,8 @@
// add a scheduling state snapshot every x events // add a scheduling state snapshot every x events
static const uint32 kSchedulingSnapshotInterval = 1024; static const uint32 kSchedulingSnapshotInterval = 1024;
static const uint32 kMaxCPUCount = 1024;
struct SimpleWaitObjectInfo : system_profiler_wait_object_info { struct SimpleWaitObjectInfo : system_profiler_wait_object_info {
SimpleWaitObjectInfo(uint32 type) SimpleWaitObjectInfo(uint32 type)
@@ -44,6 +46,17 @@ static const SimpleWaitObjectInfo kSignalWaitObjectInfo(
THREAD_BLOCK_TYPE_SIGNAL); THREAD_BLOCK_TYPE_SIGNAL);
struct ModelLoader::CPUInfo {
nanotime_t idleTime;
CPUInfo()
:
idleTime(0)
{
}
};
// #pragma mark - // #pragma mark -
@@ -64,13 +77,15 @@ ModelLoader::ModelLoader(DataSource* dataSource,
: :
AbstractModelLoader(target, targetCookie), AbstractModelLoader(target, targetCookie),
fModel(NULL), fModel(NULL),
fDataSource(dataSource) fDataSource(dataSource),
fCPUInfos(NULL)
{ {
} }
ModelLoader::~ModelLoader() ModelLoader::~ModelLoader()
{ {
delete[] fCPUInfos;
delete fDataSource; delete fDataSource;
delete fModel; delete fModel;
} }
@@ -102,6 +117,10 @@ ModelLoader::PrepareForLoading()
if (error != B_OK) if (error != B_OK)
return error; return error;
fCPUInfos = new(std::nothrow) CPUInfo[kMaxCPUCount];
if (fCPUInfos == NULL)
return B_NO_MEMORY;
return B_OK; return B_OK;
} }
@@ -126,6 +145,9 @@ ModelLoader::FinishLoading(bool success)
delete fModel; delete fModel;
fModel = NULL; fModel = NULL;
} }
delete[] fCPUInfos;
fCPUInfos = NULL;
} }
@@ -168,6 +190,7 @@ ModelLoader::_Load()
} }
// process the events // process the events
fMaxCPUIndex = 0;
fState.Clear(); fState.Clear();
fBaseTime = -1; fBaseTime = -1;
uint64 count = 0; uint64 count = 0;
@@ -190,6 +213,12 @@ ModelLoader::_Load()
if (error != B_OK) if (error != B_OK)
return error; return error;
if (cpu > fMaxCPUIndex) {
if (cpu + 1 > kMaxCPUCount)
return B_BAD_DATA;
fMaxCPUIndex = cpu;
}
// periodically check whether we're supposed to abort // periodically check whether we're supposed to abort
if (++count % 32 == 0) { if (++count % 32 == 0) {
AutoLocker<BLocker> locker(fLock); AutoLocker<BLocker> locker(fLock);
@@ -202,6 +231,12 @@ ModelLoader::_Load()
fModel->AddSchedulingStateSnapshot(fState, offset); 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->SetLastEventTime(fState.LastEventTime());
fModel->LoadingFinished(); fModel->LoadingFinished();
@@ -311,7 +346,8 @@ ModelLoader::_ProcessEvent(uint32 event, uint32 cpu, const void* buffer,
break; break;
case B_SYSTEM_PROFILER_THREAD_SCHEDULED: case B_SYSTEM_PROFILER_THREAD_SCHEDULED:
_HandleThreadScheduled((system_profiler_thread_scheduled*)buffer); _HandleThreadScheduled(cpu,
(system_profiler_thread_scheduled*)buffer);
break; break;
case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE: case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE:
@@ -320,7 +356,7 @@ ModelLoader::_ProcessEvent(uint32 event, uint32 cpu, const void* buffer,
break; break;
case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE: case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE:
_HandleThreadRemovedFromRunQueue( _HandleThreadRemovedFromRunQueue(cpu,
(thread_removed_from_run_queue*)buffer); (thread_removed_from_run_queue*)buffer);
break; break;
@@ -382,7 +418,8 @@ ModelLoader::_HandleThreadRemoved(system_profiler_thread_removed* event)
void void
ModelLoader::_HandleThreadScheduled(system_profiler_thread_scheduled* event) ModelLoader::_HandleThreadScheduled(uint32 cpu,
system_profiler_thread_scheduled* event)
{ {
_UpdateLastEventTime(event->time); _UpdateLastEventTime(event->time);
@@ -430,6 +467,8 @@ ModelLoader::_HandleThreadScheduled(system_profiler_thread_scheduled* event)
// thread preempted // thread preempted
thread->thread->AddPreemption(diffTime); thread->thread->AddPreemption(diffTime);
thread->thread->AddRun(diffTime); thread->thread->AddRun(diffTime);
if (thread->priority == 0)
_AddIdleTime(cpu, diffTime);
thread->lastTime = fState.LastEventTime(); thread->lastTime = fState.LastEventTime();
thread->state = PREEMPTED; 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 // thread starts waiting (it hadn't been added to the run
// queue before being unscheduled) // queue before being unscheduled)
thread->thread->AddRun(diffTime); thread->thread->AddRun(diffTime);
if (thread->priority == 0)
_AddIdleTime(cpu, diffTime);
if (event->previous_thread_state == B_THREAD_WAITING) { if (event->previous_thread_state == B_THREAD_WAITING) {
addr_t waitObject = event->previous_thread_wait_object; addr_t waitObject = event->previous_thread_wait_object;
@@ -504,11 +545,13 @@ ModelLoader::_HandleThreadEnqueuedInRunQueue(
thread->lastTime = fState.LastEventTime(); thread->lastTime = fState.LastEventTime();
thread->state = READY; thread->state = READY;
} }
thread->priority = event->priority;
} }
void void
ModelLoader::_HandleThreadRemovedFromRunQueue( ModelLoader::_HandleThreadRemovedFromRunQueue(uint32 cpu,
thread_removed_from_run_queue* event) thread_removed_from_run_queue* event)
{ {
_UpdateLastEventTime(event->time); _UpdateLastEventTime(event->time);
@@ -527,6 +570,8 @@ ModelLoader::_HandleThreadRemovedFromRunQueue(
if (thread->state == RUNNING) { if (thread->state == RUNNING) {
// This should never happen. // This should never happen.
thread->thread->AddRun(diffTime); thread->thread->AddRun(diffTime);
if (thread->priority == 0)
_AddIdleTime(cpu, diffTime);
} else if (thread->state == READY || thread->state == PREEMPTED) { } else if (thread->state == READY || thread->state == PREEMPTED) {
// Not really correct, but the case is rare and we keep it // Not really correct, but the case is rare and we keep it
// simple. // simple.
@@ -566,6 +611,13 @@ ModelLoader::_AddThread(system_profiler_thread_added* event)
if (info == NULL) if (info == NULL)
return 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); fState.InsertThread(info);
return info; return info;
@@ -601,3 +653,10 @@ printf("ModelLoader::_AddThreadWaitObject(): Unknown wait object: type: %lu, "
thread->waitObject = threadWaitObjectGroup->MostRecentThreadWaitObject(); thread->waitObject = threadWaitObjectGroup->MostRecentThreadWaitObject();
} }
void
ModelLoader::_AddIdleTime(uint32 cpu, nanotime_t time)
{
fCPUInfos[cpu].idleTime += time;
}
@@ -40,6 +40,8 @@ private:
typedef system_profiler_thread_removed_from_run_queue typedef system_profiler_thread_removed_from_run_queue
thread_removed_from_run_queue; thread_removed_from_run_queue;
struct CPUInfo;
private: private:
status_t _Load(); status_t _Load();
status_t _ReadDebugEvents(void** _eventData, status_t _ReadDebugEvents(void** _eventData,
@@ -59,11 +61,11 @@ private:
system_profiler_thread_added* event); system_profiler_thread_added* event);
void _HandleThreadRemoved( void _HandleThreadRemoved(
system_profiler_thread_removed* event); system_profiler_thread_removed* event);
void _HandleThreadScheduled( void _HandleThreadScheduled(uint32 cpu,
system_profiler_thread_scheduled* event); system_profiler_thread_scheduled* event);
void _HandleThreadEnqueuedInRunQueue( void _HandleThreadEnqueuedInRunQueue(
thread_enqueued_in_run_queue* event); thread_enqueued_in_run_queue* event);
void _HandleThreadRemovedFromRunQueue( void _HandleThreadRemovedFromRunQueue(uint32 cpu,
thread_removed_from_run_queue* event); thread_removed_from_run_queue* event);
void _HandleWaitObjectInfo( void _HandleWaitObjectInfo(
system_profiler_wait_object_info* event); system_profiler_wait_object_info* event);
@@ -73,11 +75,15 @@ private:
void _AddThreadWaitObject(Model::ThreadSchedulingState* thread, void _AddThreadWaitObject(Model::ThreadSchedulingState* thread,
uint32 type, addr_t object); uint32 type, addr_t object);
void _AddIdleTime(uint32 cpu, nanotime_t time);
private: private:
Model* fModel; Model* fModel;
DataSource* fDataSource; DataSource* fDataSource;
CPUInfo* fCPUInfos;
nanotime_t fBaseTime; nanotime_t fBaseTime;
Model::SchedulingState fState; Model::SchedulingState fState;
uint32 fMaxCPUIndex;
}; };