Do an actual analysis of the scheduling data -- basically equivalent to what

the kernel scheduling analysis does.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30386 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-04-24 22:53:28 +00:00
parent 3355e888b1
commit 1e336eba17
5 changed files with 1058 additions and 66 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
SubDir HAIKU_TOP src apps debuganalyzer ;
UsePrivateHeaders debug interface shared ;
UsePrivateHeaders debug interface kernel shared ;
UsePrivateSystemHeaders ;
Application DebugAnalyzer
+265 -2
View File
@@ -13,6 +13,75 @@
#include <AutoDeleter.h>
// #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);
}
+388
View File
@@ -9,11 +9,17 @@
#include <OS.h>
#include <system_profiler_defs.h>
#include <util/SinglyLinkedList.h>
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<Team> TeamList;
typedef BObjectList<Thread> ThreadList;
typedef BObjectList<WaitObjectGroup> 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<WaitObject> {
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<WaitObject> WaitObjectList;
private:
WaitObjectList fWaitObjects;
};
class Model::ThreadWaitObject
: public SinglyLinkedListLinkImpl<ThreadWaitObject> {
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<ThreadWaitObject> 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<ThreadWaitObjectGroup>
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)
{
+329 -61
View File
@@ -15,12 +15,46 @@
#include <DebugEventStream.h>
#include <system_profiler_defs.h>
#include <thread_defs.h>
#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<BLocker> 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();
}
+75 -2
View File
@@ -8,12 +8,15 @@
#include <Locker.h>
#include <Messenger.h>
#include <util/OpenHashTable.h>
#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<ThreadInfo> {
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<ThreadInfo>* GetLink(ThreadInfo* value) const
{ return value; }
};
typedef OpenHashTable<ThreadTableDefinition> 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;
};