* 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

View File

@ -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("");
}

View File

@ -22,7 +22,9 @@ public:
private:
Model* fModel;
TextDataView* fDataSourceView;
TextDataView* fCPUCountView;
TextDataView* fRunTimeView;
TextDataView* fIdleTimeView;
TextDataView* fTeamCountView;
TextDataView* fThreadCountView;
};

View File

@ -14,6 +14,23 @@
#include <AutoDeleter.h>
// #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
{

View File

@ -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<CPU> CPUList;
typedef BObjectList<Team> TeamList;
typedef BObjectList<Thread> ThreadList;
typedef BObjectList<WaitObjectGroup> 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;
}

View File

@ -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<BLocker> 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;
}

View File

@ -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;
};