* Moved ThreadInfo from ModelLoader to Model. And renamed it to

ThreadSchedulingState. Also moved the management of the thread scheduling
  states into a new model class SchedulingState, which is now used by
  ModelLoader.
* Added scheduling state snapshots to Model. The ModelLoader adds a complete
  snapshot every 1024 events, so that seeking to scheduling state at a time
  can be done quickly.
* [Featuring stippi] Added actual functionality to the scheduling page. It
  shows the scheduling activity of all threads and one can zoom in and out.
  Looks somewhat ugly and is work in progress.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31856 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2009-07-28 18:57:57 +00:00
parent 86e89f1207
commit d4d63490af
9 changed files with 1399 additions and 111 deletions

View File

@ -5,6 +5,8 @@ UsePrivateSystemHeaders ;
UseHeaders $(HAIKU_DEBUG_ANALYZER_HEADERS) ;
UseHeaders [ FDirName $(HAIKU_TOP) src apps debugger util ] ;
MergeObject DebugAnalyzer_gui_main_window.o
:

View File

@ -3,20 +3,876 @@
* Distributed under the terms of the MIT License.
*/
#include "main_window/SchedulingPage.h"
#include <stdio.h>
#include <algorithm>
#include <new>
#include <LayoutBuilder.h>
#include <LayoutUtils.h>
#include <ScrollView.h>
#include <SplitView.h>
#include <DebugEventStream.h>
#include <thread_defs.h>
#include "Array.h"
#include "Model.h"
static const float kThreadNameMargin = 3.0f;
static const float kViewSeparationMargin = 5.0f;
struct MainWindow::SchedulingPage::SchedulingEvent {
bigtime_t time;
Model::ThreadWaitObjectGroup* waitObject;
ThreadState state;
SchedulingEvent(bigtime_t time, ThreadState state,
Model::ThreadWaitObjectGroup* waitObject)
:
time(time),
waitObject(waitObject),
state(state)
{
}
};
class MainWindow::SchedulingPage::SchedulingData {
public:
SchedulingData()
:
fModel(NULL),
fDataArrays(NULL),
fRecordingEnabled(false)
{
}
status_t InitCheck() const
{
return fDataArrays != NULL ? B_OK : B_NO_MEMORY;
}
void SetModel(Model* model)
{
delete[] fDataArrays;
fModel = model;
fDataArrays = NULL;
if (fModel != NULL)
fDataArrays = new(std::nothrow) DataArray[fModel->CountThreads()];
}
void SetRecordingEnabled(bool enabled)
{
fRecordingEnabled = enabled;
}
void Clear()
{
if (fDataArrays == NULL)
return;
int32 count = fModel->CountThreads();
for (int32 i = 0; i < count; i++)
fDataArrays[i].Clear();
}
const Array<SchedulingEvent>& EventsForThread(int32 index)
{
return fDataArrays[index];
}
void AddState(Model::Thread* thread, bigtime_t time, ThreadState state,
Model::ThreadWaitObjectGroup* waitObject)
{
DataArray& array = fDataArrays[thread->Index()];
if (!array.IsEmpty()) {
SchedulingEvent& lastEvent = array[array.Size() - 1];
if (fRecordingEnabled) {
if (lastEvent.state == state
&& lastEvent.waitObject == waitObject) {
return;
}
} else {
// recording not enabled yet -- overwrite the last event
lastEvent = SchedulingEvent(time, state, waitObject);
return;
}
}
SchedulingEvent event(time, state, waitObject);
array.Add(event);
}
void AddRun(Model::Thread* thread, bigtime_t time)
{
AddState(thread, time, RUNNING, NULL);
}
void AddLatency(Model::Thread* thread, bigtime_t time)
{
AddState(thread, time, READY, NULL);
}
void AddPreemption(Model::Thread* thread, bigtime_t time)
{
AddState(thread, time, PREEMPTED, NULL);
}
void AddWait(Model::Thread* thread, bigtime_t time,
Model::ThreadWaitObjectGroup* waitObject)
{
AddState(thread, time, WAITING, waitObject);
}
void AddUnspecifiedWait(Model::Thread* thread, bigtime_t time)
{
AddState(thread, time, WAITING, NULL);
}
private:
typedef Array<SchedulingEvent> DataArray;
private:
Model* fModel;
DataArray* fDataArrays;
bool fRecordingEnabled;
};
class MainWindow::SchedulingPage::BaseView : public BView {
public:
BaseView(const char* name, FontInfo& fontInfo)
:
BView(name, B_WILL_DRAW),
fFontInfo(fontInfo)
{
}
virtual void SetModel(Model* model)
{
fModel = model;
InvalidateLayout();
}
protected:
int32 _CountLines() const
{
return fModel != NULL ? fModel->CountThreads() : 0;
}
float TotalHeight() const
{
return fFontInfo.lineHeight * _CountLines();
}
void GetLineRange(BRect rect, int32& minLine, int32& maxLine) const
{
int32 lineHeight = (int32)fFontInfo.lineHeight;
minLine = (int32)rect.top / lineHeight;
maxLine = ((int32)ceilf(rect.bottom) + lineHeight - 1) / lineHeight;
minLine = std::max(minLine, 0L);
maxLine = std::min(maxLine, _CountLines() - 1);
}
BRect LineRect(uint32 line) const
{
float y = (float)line * fFontInfo.lineHeight;
return BRect(0, y, Bounds().right, y + fFontInfo.lineHeight - 1);
}
protected:
Model* fModel;
FontInfo& fFontInfo;
};
class MainWindow::SchedulingPage::ThreadsView : public BaseView {
public:
ThreadsView(FontInfo& fontInfo)
:
BaseView("threads", fontInfo)
{
}
virtual void Draw(BRect updateRect)
{
if (fModel == NULL)
return;
// get the lines intersecting with the update rect
int32 minLine, maxLine;
GetLineRange(updateRect, minLine, maxLine);
for (int32 i = minLine; i <= maxLine; i++) {
float y = (float)(i + 1) * fFontInfo.lineHeight
- fFontInfo.fontHeight.descent;
DrawString(fModel->ThreadAt(i)->Name(),
BPoint(kThreadNameMargin, y));
}
}
virtual BSize MinSize()
{
return BSize(100, TotalHeight());
}
virtual BSize MaxSize()
{
return BSize(MinSize().width, B_SIZE_UNLIMITED);
}
};
class MainWindow::SchedulingPage::SchedulingView : public BaseView {
public:
SchedulingView(FontInfo& fontInfo)
:
BaseView("scheduling", fontInfo),
fStartTime(0),
fEndTime(0),
fUSecsPerPixel(1000),
fLastMousePos(-1, -1)
{
}
virtual void SetModel(Model* model)
{
BaseView::SetModel(model);
fSchedulingData.SetModel(model);
fStartTime = 0;
fEndTime = 0;
}
void UpdateScrollBar()
{
float width = Frame().Width();
float dataWidth = std::max(width, MinSize().width);
if (BScrollBar* scrollBar = ScrollBar(B_HORIZONTAL)) {
float range = dataWidth - width;
if (range > 0) {
scrollBar->SetRange(0, range);
scrollBar->SetProportion((width + 1) / (dataWidth + 1));
scrollBar->SetSteps(fFontInfo.lineHeight, width + 1);
} else {
scrollBar->SetRange(0, 0);
scrollBar->SetProportion(1);
}
}
}
virtual BSize MinSize()
{
bigtime_t timeSpan = fModel != NULL ? fModel->LastEventTime() : 0;
float width = std::max(float(timeSpan / fUSecsPerPixel), 100.0f);
return BSize(width, TotalHeight());
}
virtual BSize MaxSize()
{
return BSize(MinSize().width, B_SIZE_UNLIMITED);
}
virtual void ScrollTo(BPoint where)
{
BaseView::ScrollTo(where);
fStartTime = 0;
fEndTime = 0;
}
void MessageReceived(BMessage* message)
{
switch (message->what) {
case B_MOUSE_WHEEL_CHANGED:
{
// We're only interested in Shift + vertical wheel.
float deltaY;
if ((modifiers() & B_SHIFT_KEY) == 0
|| message->FindFloat("be:wheel_delta_y", &deltaY)
!= B_OK) {
break;
}
_Zoom(fLastMousePos.x, deltaY);
return;
}
}
BView::MessageReceived(message);
}
void MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
{
fLastMousePos = where - LeftTop();
// if (fDraggingStartPos.x < 0)
// return;
//
// ScrollBar(B_HORIZONTAL)->SetValue(fDraggingStartScrollValue
// + fDraggingStartPos.x - where.x);
}
virtual void Draw(BRect updateRect)
{
if (fModel == NULL || fSchedulingData.InitCheck() != B_OK)
return;
_UpdateData();
// draw the events
// TODO: Draw only the threads currently visible.
int32 threadCount = fModel->CountThreads();
for (int32 i = 0; i < threadCount; i++) {
Model::Thread* thread = fModel->ThreadAt(i);
const Array<SchedulingEvent>& events
= fSchedulingData.EventsForThread(thread->Index());
int32 eventCount = events.Size();
//printf("drawing events for thread %ld: %ld events\n", thread->Index(), eventCount);
for (int32 k = 0; k < eventCount; k++) {
const SchedulingEvent& event = events[k];
bigtime_t startTime = std::max(event.time, fStartTime);
bigtime_t endTime = k + 1 < eventCount
? std::min(events[k + 1].time, fEndTime) : fEndTime;
rgb_color color;
switch (event.state) {
case RUNNING:
case STILL_RUNNING:
color.set_to(0, 255, 0);
break;
case PREEMPTED:
color.set_to(255, 127, 0);
break;
case READY:
color.set_to(255, 0, 0);
break;
case WAITING:
case UNKNOWN:
default:
continue;
}
SetHighColor(color);
BRect rect = LineRect(i);
rect.left = startTime / fUSecsPerPixel;
rect.right = endTime / fUSecsPerPixel - 1;
FillRect(rect);
}
}
}
private:
// 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:
void _UpdateData()
{
// get the interesting event time range
bigtime_t startTime;
bigtime_t endTime;
_GetEventTimeRange(startTime, endTime);
if (startTime == fStartTime && endTime == fEndTime)
return;
fStartTime = startTime;
fEndTime = endTime;
fSchedulingData.Clear();
//printf("MainWindow::SchedulingPage::SchedulingView::_UpdateData()\n");
//printf(" time range: %lld - %lld\n", startTime, endTime);
// get a scheduling state close to our start time
const Model::CompactSchedulingState* compactState
= fModel->ClosestSchedulingState(startTime);
//printf(" compactState: %p\n", compactState);
fState.Clear();
status_t error = fState.Init(compactState);
if (error != B_OK)
return;
// init the event stream
BDebugEventInputStream input;
error = input.SetTo((uint8*)fModel->EventData(),
fModel->EventDataSize(), false);
if (error == B_OK && compactState != NULL)
error = input.Seek(compactState->EventOffset());
//printf(" event offset: %lld, input init error: %s\n", compactState != NULL ? compactState->EventOffset() : 0, strerror(error));
if (error != B_OK)
return;
fSchedulingData.SetRecordingEnabled(
fState.LastEventTime() >= startTime);
// add the initial thread states to the scheduling data
if (compactState != NULL) {
int32 threadStateCount = compactState->CountThreadsStates();
for (int32 i = 0; i < threadStateCount; i++) {
const Model::CompactThreadSchedulingState* threadState
= compactState->ThreadStateAt(i);
switch (threadState->state) {
case RUNNING:
case STILL_RUNNING:
fSchedulingData.AddRun(threadState->thread,
threadState->lastTime);
break;
case PREEMPTED:
fSchedulingData.AddPreemption(threadState->thread,
threadState->lastTime);
break;
case READY:
fSchedulingData.AddLatency(threadState->thread,
threadState->lastTime);
break;
case WAITING:
{
Model::ThreadWaitObjectGroup* group = NULL;
if (threadState->waitObject != NULL) {
group = fModel->ThreadWaitObjectGroupFor(
threadState->ID(),
threadState->waitObject->Type(),
threadState->waitObject->Object());
}
fSchedulingData.AddWait(threadState->thread,
threadState->lastTime, group);
break;
}
case UNKNOWN:
default:
break;
}
}
}
// process the events
while (true) {
// get next event
uint32 event;
uint32 cpu;
const void* buffer;
off_t offset;
ssize_t bufferSize = input.ReadNextEvent(&event, &cpu, &buffer,
&offset);
if (bufferSize < 0)
{
printf("failed to read event!\n");
return;
}
if (buffer == NULL)
break;
// process the event
error = _ProcessEvent(event, cpu, buffer, bufferSize);
if (error != B_OK)
return;
if (fState.LastEventTime() >= startTime)
fSchedulingData.SetRecordingEnabled(true);
if (fState.LastEventTime() >= endTime)
break;
}
}
void _GetEventTimeRange(bigtime_t& _startTime, bigtime_t& _endTime)
{
if (fModel != NULL) {
float scrollOffset = _ScrollOffset();
_startTime = (bigtime_t)scrollOffset * fUSecsPerPixel;
_endTime = (bigtime_t)(scrollOffset + Bounds().Width() + 1)
* fUSecsPerPixel;
} else {
_startTime = 0;
_endTime = 1;
}
}
float _ScrollOffset() const
{
if (BScrollBar* scrollBar = ScrollBar(B_HORIZONTAL))
return scrollBar->Value();
return 0;
}
void _Zoom(float x, float steps)
{
if (steps == 0 || fModel == NULL)
return;
// compute the domain point where to zoom in
float scrollOffset = _ScrollOffset();
double timeForX = (scrollOffset + x) * fUSecsPerPixel;
double factor = 4;
if (steps < 0) {
steps = -steps;
factor = 1;
}
uint32 oldUsecPerPixel = fUSecsPerPixel;
for (; steps > 0; steps--)
fUSecsPerPixel = fUSecsPerPixel * factor / 2;
if (fUSecsPerPixel < 1)
fUSecsPerPixel = 1;
else if (fUSecsPerPixel > 1000)
fUSecsPerPixel = 1000;
if (fUSecsPerPixel == oldUsecPerPixel)
return;
Invalidate();
UpdateScrollBar();
if (BScrollBar* scrollBar = ScrollBar(B_HORIZONTAL))
scrollBar->SetValue(timeForX / fUSecsPerPixel - x);
}
inline void _UpdateLastEventTime(bigtime_t time)
{
fState.SetLastEventTime(time - fModel->BaseTime());
}
status_t _ProcessEvent(uint32 event, uint32 cpu, const void* buffer,
size_t size)
{
switch (event) {
case B_SYSTEM_PROFILER_TEAM_ADDED:
case B_SYSTEM_PROFILER_TEAM_REMOVED:
case B_SYSTEM_PROFILER_TEAM_EXEC:
break;
case B_SYSTEM_PROFILER_THREAD_ADDED:
_HandleThreadAdded((system_profiler_thread_added*)buffer);
break;
case B_SYSTEM_PROFILER_THREAD_REMOVED:
_HandleThreadRemoved((system_profiler_thread_removed*)buffer);
break;
case B_SYSTEM_PROFILER_THREAD_SCHEDULED:
_HandleThreadScheduled(
(system_profiler_thread_scheduled*)buffer);
break;
case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE:
_HandleThreadEnqueuedInRunQueue(
(thread_enqueued_in_run_queue*)buffer);
break;
case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE:
_HandleThreadRemovedFromRunQueue(
(thread_removed_from_run_queue*)buffer);
break;
case B_SYSTEM_PROFILER_WAIT_OBJECT_INFO:
break;
default:
printf("unsupported event type %lu, size: %lu\n", event, size);
return B_BAD_DATA;
break;
}
return B_OK;
}
void _HandleThreadAdded(system_profiler_thread_added* event)
{
//printf(" thread added: %ld\n", event->thread);
// do we know the thread already?
Model::ThreadSchedulingState* info = fState.LookupThread(event->thread);
if (info != NULL) {
// TODO: ?
return;
}
Model::Thread* thread = fModel->ThreadByID(event->thread);
if (thread == NULL)
return;
// create and add a ThreadSchedulingState
info = new(std::nothrow) Model::ThreadSchedulingState(thread);
if (info == NULL)
return;
fState.InsertThread(info);
}
void _HandleThreadRemoved(system_profiler_thread_removed* event)
{
//printf(" thread removed: %ld\n", event->thread);
// Model::ThreadSchedulingState* thread = fState.LookupThread(
// event->thread);
// if (thread != NULL) {
// fState.RemoveThread(thread);
// delete thread;
//// TODO: The thread will be unscheduled in a moment and cause a warning! So
//// maybe keep it around in a separate hash table a bit longer?
// }
}
void _HandleThreadScheduled(system_profiler_thread_scheduled* event)
{
_UpdateLastEventTime(event->time);
Model::ThreadSchedulingState* thread = fState.LookupThread(
event->thread);
if (thread == NULL) {
printf("Schedule event for unknown thread: %ld\n", event->thread);
return;
}
thread->lastTime = fState.LastEventTime();
thread->state = RUNNING;
fSchedulingData.AddRun(thread->thread, fState.LastEventTime());
// unscheduled thread
if (event->thread == event->previous_thread)
return;
thread = fState.LookupThread(event->previous_thread);
if (thread == NULL) {
printf("Schedule event for unknown previous thread: %ld\n",
event->previous_thread);
return;
}
if (thread->state == STILL_RUNNING) {
// thread preempted
fSchedulingData.AddPreemption(thread->thread,
fState.LastEventTime());
thread->lastTime = fState.LastEventTime();
thread->state = PREEMPTED;
} else if (thread->state == RUNNING) {
// thread starts waiting (it hadn't been added to the run
// queue before being unscheduled)
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;
}
fSchedulingData.AddWait(thread->thread, fState.LastEventTime(),
fModel->ThreadWaitObjectGroupFor(thread->ID(),
event->previous_thread_wait_object_type, waitObject));
} else {
fSchedulingData.AddUnspecifiedWait(thread->thread,
fState.LastEventTime());
}
thread->lastTime = fState.LastEventTime();
thread->state = WAITING;
} else if (thread->state == UNKNOWN) {
uint32 threadState = event->previous_thread_state;
if (threadState == B_THREAD_WAITING
|| threadState == B_THREAD_SUSPENDED) {
fSchedulingData.AddWait(thread->thread, fState.LastEventTime(),
NULL);
thread->lastTime = fState.LastEventTime();
thread->state = WAITING;
} else if (threadState == B_THREAD_READY) {
thread->lastTime = fState.LastEventTime();
thread->state = PREEMPTED;
fSchedulingData.AddPreemption(thread->thread,
fState.LastEventTime());
}
}
}
void _HandleThreadEnqueuedInRunQueue(thread_enqueued_in_run_queue* event)
{
_UpdateLastEventTime(event->time);
Model::ThreadSchedulingState* thread = fState.LookupThread(
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 = fState.LastEventTime() - thread->lastTime;
if (thread->waitObject != NULL) {
thread->waitObject->AddWait(diffTime);
thread->waitObject = NULL;
}
fSchedulingData.AddLatency(thread->thread, fState.LastEventTime());
thread->lastTime = fState.LastEventTime();
thread->state = READY;
}
}
void _HandleThreadRemovedFromRunQueue(thread_removed_from_run_queue* event)
{
_UpdateLastEventTime(event->time);
Model::ThreadSchedulingState* thread = fState.LookupThread(
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.
fSchedulingData.AddUnspecifiedWait(thread->thread,
fState.LastEventTime());
thread->lastTime = fState.LastEventTime();
thread->state = WAITING;
}
private:
Model::SchedulingState fState;
SchedulingData fSchedulingData;
bigtime_t fStartTime;
bigtime_t fEndTime;
uint32 fUSecsPerPixel;
BPoint fLastMousePos;
};
class MainWindow::SchedulingPage::ViewPort : public BaseView {
public:
ViewPort(ThreadsView* threadsView, SchedulingView* schedulingView,
FontInfo& fontInfo)
:
BaseView("viewport", fontInfo),
fThreadsView(threadsView),
fSchedulingView(schedulingView)
{
AddChild(threadsView);
AddChild(schedulingView);
}
void TargetedByScrollView(BScrollView* scrollView)
{
_UpdateScrollBars();
}
virtual BSize MinSize()
{
return BSize(10, 10);
}
virtual BSize MaxSize()
{
return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
}
BSize PreferredSize()
{
BSize threadsViewSize(fThreadsView->PreferredSize());
BSize schedulingViewSize(fSchedulingView->PreferredSize());
return BSize(BLayoutUtils::AddDistances(
threadsViewSize.width + kViewSeparationMargin,
schedulingViewSize.width),
std::max(threadsViewSize.height, schedulingViewSize.height));
}
void DoLayout()
{
float width = Bounds().Width();
float height = fThreadsView->MinSize().Height();
float threadsViewWidth = fThreadsView->MinSize().width;
float schedulingViewLeft = threadsViewWidth + 1 + kViewSeparationMargin;
fThreadsView->MoveTo(0, 0);
fThreadsView->ResizeTo(threadsViewWidth, height);
fSchedulingView->MoveTo(schedulingViewLeft, 0);
fSchedulingView->ResizeTo(width - schedulingViewLeft, height);
_UpdateScrollBars();
}
private:
void _UpdateScrollBars()
{
float height = Frame().Height();
float dataHeight = std::max(height, fSchedulingView->MinSize().height);
fSchedulingView->UpdateScrollBar();
if (BScrollBar* scrollBar = ScrollBar(B_VERTICAL)) {
float range = dataHeight - height;
if (range > 0) {
scrollBar->SetRange(0, range);
scrollBar->SetProportion(
(height + 1) / (dataHeight + 1));
scrollBar->SetSteps(fFontInfo.lineHeight, height + 1);
} else {
scrollBar->SetRange(0, 0);
scrollBar->SetProportion(1);
}
}
}
private:
ThreadsView* fThreadsView;
SchedulingView* fSchedulingView;
};
MainWindow::SchedulingPage::SchedulingPage(MainWindow* parent)
:
BGroupView(B_VERTICAL),
fParent(parent),
fModel(NULL)
fModel(NULL),
fScrollView(NULL),
fViewPort(NULL),
fThreadsView(NULL),
fSchedulingView(NULL)
{
SetName("Scheduling");
be_plain_font->GetHeight(&fFontInfo.fontHeight);
fFontInfo.lineHeight = ceilf(fFontInfo.fontHeight.ascent)
+ ceilf(fFontInfo.fontHeight.descent);
fViewPort = new ViewPort(fThreadsView = new ThreadsView(fFontInfo),
fSchedulingView = new SchedulingView(fFontInfo), fFontInfo);
AddChild(fScrollView = new BScrollView("scroll", fViewPort, 0, true, true));
fScrollView->ScrollBar(B_HORIZONTAL)->SetTarget(fSchedulingView);
}
@ -38,12 +894,8 @@ MainWindow::SchedulingPage::SetModel(Model* model)
if (fModel != NULL) {
}
fViewPort->SetModel(fModel);
fThreadsView->SetModel(fModel);
fSchedulingView->SetModel(fModel);
}
void
MainWindow::SchedulingPage::TableRowInvoked(Table* table, int32 rowIndex)
{
// TODO: ...
}

View File

@ -5,6 +5,7 @@
#ifndef MAIN_SCHEDULING_PAGE_H
#define MAIN_SCHEDULING_PAGE_H
#include <GroupView.h>
#include "table/Table.h"
@ -12,6 +13,9 @@
#include "main_window/MainWindow.h"
class BScrollView;
class MainWindow::SchedulingPage : public BGroupView, private TableListener {
public:
SchedulingPage(MainWindow* parent);
@ -20,14 +24,27 @@ public:
void SetModel(Model* model);
private:
// TableListener
virtual void TableRowInvoked(Table* table, int32 rowIndex);
struct SchedulingEvent;
class SchedulingData;
class BaseView;
class ThreadsView;
class SchedulingView;
class ViewPort;
struct FontInfo {
font_height fontHeight;
float lineHeight;
};
private:
MainWindow* fParent;
Model* fModel;
BScrollView* fScrollView;
ViewPort* fViewPort;
ThreadsView* fThreadsView;
SchedulingView* fSchedulingView;
FontInfo fFontInfo;
};
#endif // MAIN_SCHEDULING_PAGE_H

View File

@ -247,6 +247,13 @@ TreeTableListener::TreeTableNodeInvoked(TreeTable* table,
}
void
TreeTableListener::TreeTableNodeExpandedChanged(TreeTable* table,
const TreeTablePath& path, bool expanded)
{
}
// #pragma mark - Column
@ -850,6 +857,27 @@ TreeTable::TableNodesChanged(TreeTableModel* model, const TreeTablePath& path,
}
void
TreeTable::ExpandOrCollapse(BRow* _row, bool expand)
{
TreeTableRow* row = dynamic_cast<TreeTableRow*>(_row);
if (row == NULL || row->IsExpanded() == expand)
return;
AbstractTable::ExpandOrCollapse(row, expand);
if (row->IsExpanded() != expand)
return;
TreeTablePath path;
_GetPathForNode(row->Node(), path);
int32 listenerCount = fListeners.CountItems();
for (int32 i = listenerCount - 1; i >= 0; i--)
fListeners.ItemAt(i)->TreeTableNodeExpandedChanged(this, path, expand);
}
void
TreeTable::ItemInvoked()
{

View File

@ -129,6 +129,8 @@ public:
virtual void TreeTableSelectionChanged(TreeTable* table);
virtual void TreeTableNodeInvoked(TreeTable* table,
const TreeTablePath& path);
virtual void TreeTableNodeExpandedChanged(TreeTable* table,
const TreeTablePath& path, bool expanded);
};
@ -189,6 +191,7 @@ private:
typedef BObjectList<TreeTableListener> ListenerList;
private:
virtual void ExpandOrCollapse(BRow* row, bool expand);
virtual void ItemInvoked();
bool _AddChildRows(TreeTableNode* parentNode,

View File

@ -147,6 +147,7 @@ Model::Thread::Thread(Team* team, const system_profiler_thread_added* event,
fTotalWaitTime(0),
fUnspecifiedWaitTime(0),
fPreemptions(0),
fIndex(-1),
fWaitObjectGroups(20, true)
{
}
@ -270,6 +271,121 @@ Model::Thread::AddThreadWaitObject(WaitObject* waitObject,
}
// #pragma mark - SchedulingState
Model::SchedulingState::~SchedulingState()
{
Clear();
}
status_t
Model::SchedulingState::Init()
{
status_t error = fThreadStates.Init();
if (error != B_OK)
return error;
return B_OK;
}
status_t
Model::SchedulingState::Init(const CompactSchedulingState* state)
{
status_t error = Init();
if (error != B_OK)
return error;
if (state == NULL)
return B_OK;
fLastEventTime = state->LastEventTime();
for (int32 i = 0; const CompactThreadSchedulingState* compactThreadState
= state->ThreadStateAt(i); i++) {
ThreadSchedulingState* threadState
= new(std::nothrow) ThreadSchedulingState(*compactThreadState);
if (threadState == NULL)
return B_NO_MEMORY;
fThreadStates.Insert(threadState);
}
return B_OK;
}
void
Model::SchedulingState::Clear()
{
ThreadSchedulingState* state = fThreadStates.Clear(true);
while (state != NULL) {
ThreadSchedulingState* next = state->next;
delete state;
state = next;
}
fLastEventTime = -1;
}
// #pragma mark - CompactSchedulingState
/*static*/ Model::CompactSchedulingState*
Model::CompactSchedulingState::Create(const SchedulingState& state,
off_t eventOffset)
{
bigtime_t lastEventTime = state.LastEventTime();
// count the active threads
int32 threadCount = 0;
for (ThreadSchedulingStateTable::Iterator it
= state.ThreadStates().GetIterator();
ThreadSchedulingState* threadState = it.Next();) {
Thread* thread = threadState->thread;
if (thread->CreationTime() <= lastEventTime
&& (thread->DeletionTime() == -1
|| thread->DeletionTime() >= lastEventTime)) {
threadCount++;
}
}
CompactSchedulingState* compactState = (CompactSchedulingState*)malloc(
sizeof(CompactSchedulingState)
+ threadCount * sizeof(CompactThreadSchedulingState));
if (compactState == NULL)
return NULL;
// copy the state info
compactState->fEventOffset = eventOffset;
compactState->fThreadCount = threadCount;
compactState->fLastEventTime = lastEventTime;
int32 threadIndex = 0;
for (ThreadSchedulingStateTable::Iterator it
= state.ThreadStates().GetIterator();
ThreadSchedulingState* threadState = it.Next();) {
Thread* thread = threadState->thread;
if (thread->CreationTime() <= lastEventTime
&& (thread->DeletionTime() == -1
|| thread->DeletionTime() >= lastEventTime)) {
compactState->fThreadStates[threadIndex++] = *threadState;
}
}
return compactState;
}
void
Model::CompactSchedulingState::Delete()
{
free(this);
}
// #pragma mark - Model
@ -282,22 +398,36 @@ Model::Model(const char* dataSourceName, void* eventData, size_t eventDataSize)
fLastEventTime(0),
fTeams(20, true),
fThreads(20, true),
fWaitObjectGroups(20, true)
fWaitObjectGroups(20, true),
fSchedulingStates(100)
{
}
Model::~Model()
{
for (int32 i = 0; CompactSchedulingState* state
= fSchedulingStates.ItemAt(i); i++) {
state->Delete();
}
free(fEventData);
}
void
Model::LoadingFinished()
{
for (int32 i = 0; Thread* thread = fThreads.ItemAt(i); i++)
thread->SetIndex(i);
}
void
Model::SetBaseTime(bigtime_t time)
{
fBaseTime = time;
}
}
void
@ -480,3 +610,46 @@ Model::ThreadWaitObjectGroupFor(thread_id threadID, uint32 type, addr_t object)
return thread->ThreadWaitObjectGroupFor(type, object);
}
bool
Model::AddSchedulingStateSnapshot(const SchedulingState& state,
off_t eventOffset)
{
CompactSchedulingState* compactState = CompactSchedulingState::Create(state,
eventOffset);
if (compactState == NULL)
return false;
if (!fSchedulingStates.AddItem(compactState)) {
compactState->Delete();
return false;
}
return true;
}
const Model::CompactSchedulingState*
Model::ClosestSchedulingState(bigtime_t eventTime) const
{
int32 index = fSchedulingStates.BinarySearchIndexByKey(eventTime,
&_CompareEventTimeSchedulingState);
if (index >= 0)
return fSchedulingStates.ItemAt(index);
// no exact match
index = -index - 1;
return index > 0 ? fSchedulingStates.ItemAt(index - 1) : NULL;
}
/*static*/ int
Model::_CompareEventTimeSchedulingState(const bigtime_t* time,
const CompactSchedulingState* state)
{
if (*time < state->LastEventTime())
return -1;
return *time == state->LastEventTime() ? 0 : 1;
}

View File

@ -5,16 +5,30 @@
#ifndef MODEL_H
#define MODEL_H
#include <stdlib.h>
#include <OS.h>
#include <String.h>
#include <ObjectList.h>
#include <Referenceable.h>
#include <util/OpenHashTable.h>
#include <system_profiler_defs.h>
#include <util/SinglyLinkedList.h>
enum ThreadState {
RUNNING,
STILL_RUNNING,
PREEMPTED,
READY,
WAITING,
UNKNOWN
};
class Model : public Referenceable {
public:
struct creation_time_id;
@ -25,6 +39,13 @@ public:
class ThreadWaitObjectGroup;
class Team;
class Thread;
struct CompactThreadSchedulingState;
struct ThreadSchedulingState;
struct ThreadSchedulingStateDefinition;
typedef BOpenHashTable<ThreadSchedulingStateDefinition>
ThreadSchedulingStateTable;
class SchedulingState;
class CompactSchedulingState;
public:
Model(const char* dataSourceName,
@ -35,6 +56,8 @@ public:
inline void* EventData() const;
inline size_t EventDataSize() const;
void LoadingFinished();
inline bigtime_t BaseTime() const;
void SetBaseTime(bigtime_t time);
@ -70,10 +93,23 @@ public:
thread_id threadID, uint32 type,
addr_t object) const;
bool AddSchedulingStateSnapshot(
const SchedulingState& state,
off_t eventOffset);
// must be added in order (of time)
const CompactSchedulingState* ClosestSchedulingState(
bigtime_t eventTime) const;
// returns the closest previous state
private:
typedef BObjectList<Team> TeamList;
typedef BObjectList<Thread> ThreadList;
typedef BObjectList<WaitObjectGroup> WaitObjectGroupList;
typedef BObjectList<CompactSchedulingState> SchedulingStateList;
private:
static int _CompareEventTimeSchedulingState(const bigtime_t* time,
const CompactSchedulingState* state);
private:
BString fDataSourceName;
@ -84,6 +120,7 @@ private:
TeamList fTeams; // sorted by ID
ThreadList fThreads; // sorted by ID
WaitObjectGroupList fWaitObjectGroups;
SchedulingStateList fSchedulingStates;
};
@ -246,6 +283,9 @@ public:
inline const char* Name() const;
inline Team* GetTeam() const;
inline int32 Index() const;
inline void SetIndex(int32 index);
inline bigtime_t CreationTime() const;
inline bigtime_t DeletionTime() const;
@ -319,10 +359,106 @@ private:
int64 fPreemptions;
int32 fIndex;
ThreadWaitObjectGroupList fWaitObjectGroups;
};
struct Model::CompactThreadSchedulingState {
bigtime_t lastTime;
Model::Thread* thread;
ThreadWaitObject* waitObject;
ThreadState state;
public:
thread_id ID() const { return thread->ID(); }
inline CompactThreadSchedulingState& operator=(
const CompactThreadSchedulingState& other);
};
struct Model::ThreadSchedulingState : CompactThreadSchedulingState {
ThreadSchedulingState* next;
public:
inline ThreadSchedulingState(
const CompactThreadSchedulingState& other);
inline ThreadSchedulingState(Thread* thread);
};
struct Model::ThreadSchedulingStateDefinition {
typedef thread_id KeyType;
typedef ThreadSchedulingState ValueType;
size_t HashKey(thread_id key) const
{ return (size_t)key; }
size_t Hash(const ThreadSchedulingState* value) const
{ return (size_t)value->ID(); }
bool Compare(thread_id key, const ThreadSchedulingState* value) const
{ return key == value->ID(); }
ThreadSchedulingState*& GetLink(ThreadSchedulingState* value) const
{ return value->next; }
};
class Model::SchedulingState {
public:
inline SchedulingState();
~SchedulingState();
status_t Init();
status_t Init(const CompactSchedulingState* state);
void Clear();
inline bigtime_t LastEventTime() const { return fLastEventTime; }
inline void SetLastEventTime(bigtime_t time);
inline ThreadSchedulingState* LookupThread(thread_id threadID) const;
inline void InsertThread(ThreadSchedulingState* thread);
inline void RemoveThread(ThreadSchedulingState* thread);
inline const ThreadSchedulingStateTable& ThreadStates() const;
private:
bigtime_t fLastEventTime;
ThreadSchedulingStateTable fThreadStates;
};
class Model::CompactSchedulingState {
public:
static CompactSchedulingState* Create(const SchedulingState& state,
off_t eventOffset);
void Delete();
inline off_t EventOffset() const;
inline bigtime_t LastEventTime() const;
inline int32 CountThreadsStates() const;
inline const CompactThreadSchedulingState* ThreadStateAt(int32 index)
const;
private:
friend class BObjectList<CompactSchedulingState>;
// work-around for our private destructor
private:
CompactSchedulingState();
inline ~CompactSchedulingState() {}
private:
bigtime_t fLastEventTime;
off_t fEventOffset;
int32 fThreadCount;
CompactThreadSchedulingState fThreadStates[0];
};
// #pragma mark - Model
@ -658,6 +794,20 @@ Model::Thread::DeletionTime() const
}
int32
Model::Thread::Index() const
{
return fIndex;
}
void
Model::Thread::SetIndex(int32 index)
{
fIndex = index;
}
int64
Model::Thread::Runs() const
{
@ -784,4 +934,114 @@ Model::Thread::CompareWithCreationTimeID(const creation_time_id* key,
}
// #pragma mark - CompactThreadSchedulingState
Model::CompactThreadSchedulingState&
Model::CompactThreadSchedulingState::operator=(
const CompactThreadSchedulingState& other)
{
lastTime = other.lastTime;
thread = other.thread;
waitObject = other.waitObject;
state = other.state;
return *this;
}
// #pragma mark - ThreadSchedulingState
Model::ThreadSchedulingState::ThreadSchedulingState(
const CompactThreadSchedulingState& other)
{
this->CompactThreadSchedulingState::operator=(other);
}
Model::ThreadSchedulingState::ThreadSchedulingState(Thread* thread)
{
lastTime = 0;
this->thread = thread;
waitObject = NULL;
state = UNKNOWN;
}
// #pragma mark - SchedulingState
Model::SchedulingState::SchedulingState()
:
fLastEventTime(-1)
{
}
void
Model::SchedulingState::SetLastEventTime(bigtime_t time)
{
fLastEventTime = time;
}
Model::ThreadSchedulingState*
Model::SchedulingState::LookupThread(thread_id threadID) const
{
return fThreadStates.Lookup(threadID);
}
void
Model::SchedulingState::InsertThread(ThreadSchedulingState* thread)
{
fThreadStates.Insert(thread);
}
void
Model::SchedulingState::RemoveThread(ThreadSchedulingState* thread)
{
fThreadStates.Remove(thread);
}
const Model::ThreadSchedulingStateTable&
Model::SchedulingState::ThreadStates() const
{
return fThreadStates;
}
// #pragma mark - CompactSchedulingState
off_t
Model::CompactSchedulingState::EventOffset() const
{
return fEventOffset;
}
bigtime_t
Model::CompactSchedulingState::LastEventTime() const
{
return fLastEventTime;
}
int32
Model::CompactSchedulingState::CountThreadsStates() const
{
return fThreadCount;
}
const Model::CompactThreadSchedulingState*
Model::CompactSchedulingState::ThreadStateAt(int32 index) const
{
return index >= 0 && index < fThreadCount ? &fThreadStates[index] : NULL;
}
#endif // MODEL_H

View File

@ -3,6 +3,7 @@
* Distributed under the terms of the MIT License.
*/
#include "ModelLoader.h"
#include <stdio.h>
@ -22,6 +23,10 @@
#include "Model.h"
// add a scheduling state snapshot every x events
static const uint32 kSchedulingSnapshotInterval = 1024;
struct SimpleWaitObjectInfo : system_profiler_wait_object_info {
SimpleWaitObjectInfo(uint32 type)
{
@ -39,19 +44,6 @@ 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 -
@ -63,7 +55,7 @@ ModelLoader::_UpdateLastEventTime(bigtime_t time)
fModel->SetBaseTime(time);
}
fLastEventTime = time - fBaseTime;
fState.SetLastEventTime(time - fBaseTime);
}
@ -105,8 +97,8 @@ ModelLoader::PrepareForLoading()
if (fModel != NULL || fDataSource == NULL)
return B_BAD_VALUE;
// init the hash tables
status_t error = fThreads.Init();
// init the state
status_t error = fState.Init();
if (error != B_OK)
return error;
@ -128,12 +120,7 @@ ModelLoader::Load()
void
ModelLoader::FinishLoading(bool success)
{
ThreadInfo* threadInfo = fThreads.Clear(true);
while (threadInfo != NULL) {
ThreadInfo* nextInfo = threadInfo->next;
delete threadInfo;
threadInfo = nextInfo;
}
fState.Clear();
if (!success) {
delete fModel;
@ -181,16 +168,18 @@ ModelLoader::_Load()
}
// process the events
fState.Clear();
fBaseTime = -1;
fLastEventTime = -1;
uint32 count = 0;
uint64 count = 0;
while (true) {
// get next event
uint32 event;
uint32 cpu;
const void* buffer;
ssize_t bufferSize = input->ReadNextEvent(&event, &cpu, &buffer);
off_t offset;
ssize_t bufferSize = input->ReadNextEvent(&event, &cpu, &buffer,
&offset);
if (bufferSize < 0)
return bufferSize;
if (buffer == NULL)
@ -207,9 +196,14 @@ ModelLoader::_Load()
if (fAborted)
return B_ERROR;
}
// periodically add scheduling snapshots
if (count % kSchedulingSnapshotInterval == 0)
fModel->AddSchedulingStateSnapshot(fState, offset);
}
fModel->SetLastEventTime(fLastEventTime);
fModel->SetLastEventTime(fState.LastEventTime());
fModel->LoadingFinished();
return B_OK;
}
@ -347,7 +341,7 @@ return B_BAD_DATA;
void
ModelLoader::_HandleTeamAdded(system_profiler_team_added* event)
{
if (fModel->AddTeam(event, fLastEventTime) == NULL)
if (fModel->AddTeam(event, fState.LastEventTime()) == NULL)
throw std::bad_alloc();
}
@ -356,7 +350,7 @@ void
ModelLoader::_HandleTeamRemoved(system_profiler_team_removed* event)
{
if (Model::Team* team = fModel->TeamByID(event->team))
team->SetDeletionTime(fLastEventTime);
team->SetDeletionTime(fState.LastEventTime());
else
printf("Removed event for unknown team: %ld\n", event->team);
}
@ -381,7 +375,7 @@ void
ModelLoader::_HandleThreadRemoved(system_profiler_thread_removed* event)
{
if (Model::Thread* thread = fModel->ThreadByID(event->thread))
thread->SetDeletionTime(fLastEventTime);
thread->SetDeletionTime(fState.LastEventTime());
else
printf("Removed event for unknown team: %ld\n", event->thread);
}
@ -392,13 +386,13 @@ ModelLoader::_HandleThreadScheduled(system_profiler_thread_scheduled* event)
{
_UpdateLastEventTime(event->time);
ThreadInfo* thread = fThreads.Lookup(event->thread);
Model::ThreadSchedulingState* thread = fState.LookupThread(event->thread);
if (thread == NULL) {
printf("Schedule event for unknown thread: %ld\n", event->thread);
return;
}
bigtime_t diffTime = fLastEventTime - thread->lastTime;
bigtime_t diffTime = fState.LastEventTime() - thread->lastTime;
if (thread->state == READY) {
// thread scheduled after having been woken up
@ -414,7 +408,7 @@ ModelLoader::_HandleThreadScheduled(system_profiler_thread_scheduled* event)
}
if (thread->state != RUNNING) {
thread->lastTime = fLastEventTime;
thread->lastTime = fState.LastEventTime();
thread->state = RUNNING;
}
@ -423,21 +417,21 @@ ModelLoader::_HandleThreadScheduled(system_profiler_thread_scheduled* event)
if (event->thread == event->previous_thread)
return;
thread = fThreads.Lookup(event->previous_thread);
thread = fState.LookupThread(event->previous_thread);
if (thread == NULL) {
printf("Schedule event for unknown previous thread: %ld\n",
event->previous_thread);
return;
}
diffTime = fLastEventTime - thread->lastTime;
diffTime = fState.LastEventTime() - thread->lastTime;
if (thread->state == STILL_RUNNING) {
// thread preempted
thread->thread->AddPreemption(diffTime);
thread->thread->AddRun(diffTime);
thread->lastTime = fLastEventTime;
thread->lastTime = fState.LastEventTime();
thread->state = PREEMPTED;
} else if (thread->state == RUNNING) {
// thread starts waiting (it hadn't been added to the run
@ -464,16 +458,16 @@ ModelLoader::_HandleThreadScheduled(system_profiler_thread_scheduled* event)
event->previous_thread_wait_object_type, waitObject);
}
thread->lastTime = fLastEventTime;
thread->lastTime = fState.LastEventTime();
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->lastTime = fState.LastEventTime();
thread->state = WAITING;
} else if (threadState == B_THREAD_READY) {
thread->lastTime = fLastEventTime;
thread->lastTime = fState.LastEventTime();
thread->state = PREEMPTED;
}
}
@ -486,7 +480,7 @@ ModelLoader::_HandleThreadEnqueuedInRunQueue(
{
_UpdateLastEventTime(event->time);
ThreadInfo* thread = fThreads.Lookup(event->thread);
Model::ThreadSchedulingState* thread = fState.LookupThread(event->thread);
if (thread == NULL) {
printf("Enqueued in run queue event for unknown thread: %ld\n",
event->thread);
@ -499,7 +493,7 @@ ModelLoader::_HandleThreadEnqueuedInRunQueue(
thread->state = STILL_RUNNING;
} else {
// Thread was waiting and is ready now.
bigtime_t diffTime = fLastEventTime - thread->lastTime;
bigtime_t diffTime = fState.LastEventTime() - thread->lastTime;
if (thread->waitObject != NULL) {
thread->waitObject->AddWait(diffTime);
thread->waitObject = NULL;
@ -507,7 +501,7 @@ ModelLoader::_HandleThreadEnqueuedInRunQueue(
} else if (thread->state != UNKNOWN)
thread->thread->AddUnspecifiedWait(diffTime);
thread->lastTime = fLastEventTime;
thread->lastTime = fState.LastEventTime();
thread->state = READY;
}
}
@ -519,7 +513,7 @@ ModelLoader::_HandleThreadRemovedFromRunQueue(
{
_UpdateLastEventTime(event->time);
ThreadInfo* thread = fThreads.Lookup(event->thread);
Model::ThreadSchedulingState* thread = fState.LookupThread(event->thread);
if (thread == NULL) {
printf("Removed from run queue event for unknown thread: %ld\n",
event->thread);
@ -529,7 +523,7 @@ ModelLoader::_HandleThreadRemovedFromRunQueue(
// This really only happens when the thread priority is changed
// while the thread is ready.
bigtime_t diffTime = fLastEventTime - thread->lastTime;
bigtime_t diffTime = fState.LastEventTime() - thread->lastTime;
if (thread->state == RUNNING) {
// This should never happen.
thread->thread->AddRun(diffTime);
@ -539,7 +533,7 @@ ModelLoader::_HandleThreadRemovedFromRunQueue(
thread->thread->AddUnspecifiedWait(diffTime);
}
thread->lastTime = fLastEventTime;
thread->lastTime = fState.LastEventTime();
thread->state = WAITING;
}
@ -552,35 +546,35 @@ ModelLoader::_HandleWaitObjectInfo(system_profiler_wait_object_info* event)
}
ModelLoader::ThreadInfo*
Model::ThreadSchedulingState*
ModelLoader::_AddThread(system_profiler_thread_added* event)
{
// do we know the thread already?
ThreadInfo* info = fThreads.Lookup(event->thread);
Model::ThreadSchedulingState* info = fState.LookupThread(event->thread);
if (info != NULL) {
// TODO: ?
return info;
}
// add the thread to the model
Model::Thread* thread = fModel->AddThread(event, fLastEventTime);
Model::Thread* thread = fModel->AddThread(event, fState.LastEventTime());
if (thread == NULL)
return NULL;
// create and add a ThreadInfo
info = new(std::nothrow) ThreadInfo(thread);
// create and add a ThreadSchedulingState
info = new(std::nothrow) Model::ThreadSchedulingState(thread);
if (info == NULL)
return NULL;
fThreads.Insert(info);
fState.InsertThread(info);
return info;
}
void
ModelLoader::_AddThreadWaitObject(ThreadInfo* thread, uint32 type,
addr_t object)
ModelLoader::_AddThreadWaitObject(Model::ThreadSchedulingState* thread,
uint32 type, addr_t object)
{
Model::WaitObjectGroup* waitObjectGroup
= fModel->WaitObjectGroupFor(type, object);

View File

@ -5,7 +5,6 @@
#ifndef MAIN_MODEL_LOADER_H
#define MAIN_MODEL_LOADER_H
#include <util/OpenHashTable.h>
#include "AbstractModelLoader.h"
#include "Model.h"
@ -35,46 +34,6 @@ protected:
virtual void FinishLoading(bool success);
private:
enum ScheduleState {
RUNNING,
STILL_RUNNING,
PREEMPTED,
READY,
WAITING,
UNKNOWN
};
struct ThreadInfo {
Model::Thread* thread;
ScheduleState state;
bigtime_t lastTime;
Model::ThreadWaitObject* waitObject;
ThreadInfo* next;
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(); }
ThreadInfo*& GetLink(ThreadInfo* value) const
{ return value->next; }
};
typedef BOpenHashTable<ThreadTableDefinition> ThreadTable;
// shorthands for the longish structure names
typedef system_profiler_thread_enqueued_in_run_queue
thread_enqueued_in_run_queue;
@ -109,16 +68,16 @@ private:
void _HandleWaitObjectInfo(
system_profiler_wait_object_info* event);
ThreadInfo* _AddThread(system_profiler_thread_added* event);
void _AddThreadWaitObject(ThreadInfo* thread,
Model::ThreadSchedulingState* _AddThread(
system_profiler_thread_added* event);
void _AddThreadWaitObject(Model::ThreadSchedulingState* thread,
uint32 type, addr_t object);
private:
Model* fModel;
DataSource* fDataSource;
bigtime_t fBaseTime;
bigtime_t fLastEventTime;
ThreadTable fThreads;
Model::SchedulingState fState;
};