Also visualize I/O activity.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34739 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -44,6 +44,13 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
IO_SCHEDULING_STATE_IDLE,
|
||||||
|
IO_SCHEDULING_STATE_PENDING_REQUEST,
|
||||||
|
IO_SCHEDULING_STATE_PENDING_OPERATION
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct MainWindow::SchedulingPage::SchedulingEvent {
|
struct MainWindow::SchedulingPage::SchedulingEvent {
|
||||||
nanotime_t time;
|
nanotime_t time;
|
||||||
Model::ThreadWaitObjectGroup* waitObject;
|
Model::ThreadWaitObjectGroup* waitObject;
|
||||||
@@ -60,30 +67,50 @@ struct MainWindow::SchedulingPage::SchedulingEvent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct MainWindow::SchedulingPage::IOSchedulingEvent {
|
||||||
|
nanotime_t time;
|
||||||
|
uint32 state;
|
||||||
|
|
||||||
|
IOSchedulingEvent(nanotime_t time, uint32 state)
|
||||||
|
:
|
||||||
|
time(time),
|
||||||
|
state(state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class MainWindow::SchedulingPage::SchedulingData {
|
class MainWindow::SchedulingPage::SchedulingData {
|
||||||
public:
|
public:
|
||||||
SchedulingData()
|
SchedulingData()
|
||||||
:
|
:
|
||||||
fModel(NULL),
|
fModel(NULL),
|
||||||
fDataArrays(NULL),
|
fDataArrays(NULL),
|
||||||
|
fIODataArrays(NULL),
|
||||||
fRecordingEnabled(false)
|
fRecordingEnabled(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t InitCheck() const
|
status_t InitCheck() const
|
||||||
{
|
{
|
||||||
return fDataArrays != NULL ? B_OK : B_NO_MEMORY;
|
return fDataArrays != NULL && fIODataArrays != NULL
|
||||||
|
? B_OK : B_NO_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetModel(Model* model)
|
void SetModel(Model* model)
|
||||||
{
|
{
|
||||||
delete[] fDataArrays;
|
delete[] fDataArrays;
|
||||||
|
delete[] fIODataArrays;
|
||||||
|
|
||||||
fModel = model;
|
fModel = model;
|
||||||
fDataArrays = NULL;
|
fDataArrays = NULL;
|
||||||
|
fIODataArrays = NULL;
|
||||||
|
|
||||||
if (fModel != NULL)
|
if (fModel != NULL) {
|
||||||
fDataArrays = new(std::nothrow) DataArray[fModel->CountThreads()];
|
int32 threadCount = fModel->CountThreads();
|
||||||
|
fDataArrays = new(std::nothrow) DataArray[threadCount];
|
||||||
|
fIODataArrays = new(std::nothrow) IODataArray[threadCount];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetRecordingEnabled(bool enabled)
|
void SetRecordingEnabled(bool enabled)
|
||||||
@@ -93,19 +120,29 @@ public:
|
|||||||
|
|
||||||
void Clear()
|
void Clear()
|
||||||
{
|
{
|
||||||
if (fDataArrays == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int32 count = fModel->CountThreads();
|
int32 count = fModel->CountThreads();
|
||||||
|
|
||||||
|
if (fDataArrays != NULL) {
|
||||||
for (int32 i = 0; i < count; i++)
|
for (int32 i = 0; i < count; i++)
|
||||||
fDataArrays[i].Clear();
|
fDataArrays[i].Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fIODataArrays != NULL) {
|
||||||
|
for (int32 i = 0; i < count; i++)
|
||||||
|
fIODataArrays[i].Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const Array<SchedulingEvent>& EventsForThread(int32 index)
|
const Array<SchedulingEvent>& EventsForThread(int32 index)
|
||||||
{
|
{
|
||||||
return fDataArrays[index];
|
return fDataArrays[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Array<IOSchedulingEvent>& IOEventsForThread(int32 index)
|
||||||
|
{
|
||||||
|
return fIODataArrays[index];
|
||||||
|
}
|
||||||
|
|
||||||
void AddState(Model::Thread* thread, nanotime_t time, ThreadState state,
|
void AddState(Model::Thread* thread, nanotime_t time, ThreadState state,
|
||||||
Model::ThreadWaitObjectGroup* waitObject)
|
Model::ThreadWaitObjectGroup* waitObject)
|
||||||
{
|
{
|
||||||
@@ -128,6 +165,12 @@ public:
|
|||||||
array.Add(event);
|
array.Add(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddIOState(Model::Thread* thread, nanotime_t time, uint32 state)
|
||||||
|
{
|
||||||
|
IODataArray& array = fIODataArrays[thread->Index()];
|
||||||
|
array.Add(IOSchedulingEvent(time, state));
|
||||||
|
}
|
||||||
|
|
||||||
void AddRun(Model::Thread* thread, nanotime_t time)
|
void AddRun(Model::Thread* thread, nanotime_t time)
|
||||||
{
|
{
|
||||||
AddState(thread, time, RUNNING, NULL);
|
AddState(thread, time, RUNNING, NULL);
|
||||||
@@ -156,10 +199,12 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
typedef Array<SchedulingEvent> DataArray;
|
typedef Array<SchedulingEvent> DataArray;
|
||||||
|
typedef Array<IOSchedulingEvent> IODataArray;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Model* fModel;
|
Model* fModel;
|
||||||
DataArray* fDataArrays;
|
DataArray* fDataArrays;
|
||||||
|
IODataArray* fIODataArrays;
|
||||||
bool fRecordingEnabled;
|
bool fRecordingEnabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -587,6 +632,8 @@ private:
|
|||||||
COLOR_RUNNING = 0,
|
COLOR_RUNNING = 0,
|
||||||
COLOR_PREEMPTED,
|
COLOR_PREEMPTED,
|
||||||
COLOR_READY,
|
COLOR_READY,
|
||||||
|
COLOR_IO_REQUEST,
|
||||||
|
COLOR_IO_OPERATION,
|
||||||
ACTIVITY_COLOR_COUNT
|
ACTIVITY_COLOR_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -604,13 +651,19 @@ public:
|
|||||||
fActivityColors[COLOR_RUNNING].set_to(0, 255, 0);
|
fActivityColors[COLOR_RUNNING].set_to(0, 255, 0);
|
||||||
fActivityColors[COLOR_PREEMPTED].set_to(255, 127, 0);
|
fActivityColors[COLOR_PREEMPTED].set_to(255, 127, 0);
|
||||||
fActivityColors[COLOR_READY].set_to(255, 0, 0);
|
fActivityColors[COLOR_READY].set_to(255, 0, 0);
|
||||||
|
fActivityColors[COLOR_IO_REQUEST].set_to(127, 127, 255);
|
||||||
|
fActivityColors[COLOR_IO_OPERATION].set_to(0, 0, 200);
|
||||||
|
|
||||||
fActivitySelectedColors[COLOR_RUNNING] = tint_color(
|
fActivitySelectedColors[COLOR_RUNNING] = tint_color(
|
||||||
fActivityColors[COLOR_RUNNING], B_DARKEN_2_TINT);
|
fActivityColors[COLOR_RUNNING], B_DARKEN_2_TINT);
|
||||||
fActivitySelectedColors[COLOR_PREEMPTED] = tint_color(
|
fActivitySelectedColors[COLOR_PREEMPTED] = tint_color(
|
||||||
fActivityColors[COLOR_PREEMPTED], B_DARKEN_2_TINT);
|
fActivityColors[COLOR_PREEMPTED], B_DARKEN_2_TINT);
|
||||||
fActivitySelectedColors[COLOR_READY] = tint_color(
|
fActivitySelectedColors[COLOR_READY] = tint_color(
|
||||||
fActivityColors[COLOR_READY], B_DARKEN_2_TINT);
|
fActivityColors[COLOR_READY], B_DARKEN_2_TINT);
|
||||||
|
fActivitySelectedColors[COLOR_IO_REQUEST] = tint_color(
|
||||||
|
fActivityColors[COLOR_IO_REQUEST], B_DARKEN_2_TINT);
|
||||||
|
fActivitySelectedColors[COLOR_IO_OPERATION] = tint_color(
|
||||||
|
fActivityColors[COLOR_IO_OPERATION], B_DARKEN_2_TINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
~SchedulingView()
|
~SchedulingView()
|
||||||
@@ -845,6 +898,11 @@ public:
|
|||||||
if (thread == NULL)
|
if (thread == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
BRect schedulingLineRect = lineRect;
|
||||||
|
schedulingLineRect.bottom -= lineRect.IntegerHeight() / 2;
|
||||||
|
BRect ioLineRect = lineRect;
|
||||||
|
ioLineRect.top = schedulingLineRect.bottom + 1;
|
||||||
|
|
||||||
const Array<SchedulingEvent>& events
|
const Array<SchedulingEvent>& events
|
||||||
= fSchedulingData.EventsForThread(thread->Index());
|
= fSchedulingData.EventsForThread(thread->Index());
|
||||||
|
|
||||||
@@ -873,7 +931,35 @@ public:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
BRect rect = lineRect;
|
BRect rect = schedulingLineRect;
|
||||||
|
rect.left = startTime / fNSecsPerPixel;
|
||||||
|
rect.right = endTime / fNSecsPerPixel - 1;
|
||||||
|
FillRect(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Array<IOSchedulingEvent>& ioEvents
|
||||||
|
= fSchedulingData.IOEventsForThread(thread->Index());
|
||||||
|
eventCount = ioEvents.Size();
|
||||||
|
|
||||||
|
for (int32 k = 0; k < eventCount; k++) {
|
||||||
|
const IOSchedulingEvent& event = ioEvents[k];
|
||||||
|
nanotime_t startTime = std::max(event.time, fStartTime);
|
||||||
|
nanotime_t endTime = k + 1 < eventCount
|
||||||
|
? std::min(ioEvents[k + 1].time, fEndTime) : fEndTime;
|
||||||
|
|
||||||
|
switch (event.state) {
|
||||||
|
case IO_SCHEDULING_STATE_PENDING_REQUEST:
|
||||||
|
SetHighColor(activityColors[COLOR_IO_REQUEST]);
|
||||||
|
break;
|
||||||
|
case IO_SCHEDULING_STATE_PENDING_OPERATION:
|
||||||
|
SetHighColor(activityColors[COLOR_IO_OPERATION]);
|
||||||
|
break;
|
||||||
|
case IO_SCHEDULING_STATE_IDLE:
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BRect rect = ioLineRect;
|
||||||
rect.left = startTime / fNSecsPerPixel;
|
rect.left = startTime / fNSecsPerPixel;
|
||||||
rect.right = endTime / fNSecsPerPixel - 1;
|
rect.right = endTime / fNSecsPerPixel - 1;
|
||||||
FillRect(rect);
|
FillRect(rect);
|
||||||
@@ -995,6 +1081,109 @@ printf("failed to read event!\n");
|
|||||||
if (fState.LastEventTime() >= endTime)
|
if (fState.LastEventTime() >= endTime)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// process each thread's I/O events
|
||||||
|
nanotime_t lastEventTime = fModel->BaseTime() - fModel->LastEventTime();
|
||||||
|
int32 threadCount = fModel->CountThreads();
|
||||||
|
for (int32 i = 0; i < threadCount; i++) {
|
||||||
|
Model::Thread* thread = fModel->ThreadAt(i);
|
||||||
|
Model::IORequest** requests = thread->IORequests();
|
||||||
|
size_t requestCount = thread->CountIORequests();
|
||||||
|
if (requestCount == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// first request
|
||||||
|
nanotime_t clusterStart = requests[0]->scheduledEvent->time;
|
||||||
|
nanotime_t clusterEnd = requests[0]->finishedEvent != NULL
|
||||||
|
? requests[0]->finishedEvent->time : lastEventTime;
|
||||||
|
BObjectList<Model::IOOperation> operations;
|
||||||
|
|
||||||
|
// add first request operations
|
||||||
|
for (size_t l = 0; l < requests[0]->operationCount; l++)
|
||||||
|
operations.AddItem(&requests[0]->operations[l]);
|
||||||
|
|
||||||
|
for (size_t k = 1; k < requestCount; k++) {
|
||||||
|
nanotime_t requestStart = requests[k]->scheduledEvent->time;
|
||||||
|
nanotime_t requestEnd = requests[k]->finishedEvent != NULL
|
||||||
|
? requests[k]->finishedEvent->time : lastEventTime;
|
||||||
|
|
||||||
|
if (requestStart >= endTime)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (requestStart > clusterEnd) {
|
||||||
|
if (clusterEnd > startTime) {
|
||||||
|
_AddThreadIOData(thread, clusterStart, clusterEnd,
|
||||||
|
operations);
|
||||||
|
}
|
||||||
|
operations.MakeEmpty();
|
||||||
|
clusterStart = requestStart;
|
||||||
|
clusterEnd = requestEnd;
|
||||||
|
} else
|
||||||
|
clusterEnd = std::max(clusterEnd, requestEnd);
|
||||||
|
|
||||||
|
// add request operations
|
||||||
|
for (size_t l = 0; l < requests[k]->operationCount; l++)
|
||||||
|
operations.AddItem(&requests[k]->operations[l]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clusterEnd > startTime)
|
||||||
|
_AddThreadIOData(thread, clusterStart, clusterEnd, operations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _AddThreadIOData(Model::Thread* thread, nanotime_t startTime,
|
||||||
|
nanotime_t endTime, BObjectList<Model::IOOperation>& operations)
|
||||||
|
{
|
||||||
|
//printf(" IORequest cluster: %lld - %lld\n", startTime, endTime);
|
||||||
|
// start in pending request state
|
||||||
|
fSchedulingData.AddIOState(thread, startTime - fModel->BaseTime(),
|
||||||
|
IO_SCHEDULING_STATE_PENDING_REQUEST);
|
||||||
|
|
||||||
|
int32 operationCount = operations.CountItems();
|
||||||
|
if (operationCount == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// sort the operations
|
||||||
|
if (operationCount > 1)
|
||||||
|
operations.SortItems(Model::IOOperation::CompareByTime);
|
||||||
|
|
||||||
|
nanotime_t lastEventTime = fModel->BaseTime() + fModel->LastEventTime();
|
||||||
|
|
||||||
|
// process the operations
|
||||||
|
Model::IOOperation* operation = operations.ItemAt(0);
|
||||||
|
nanotime_t clusterStart = operation->startedEvent->time;
|
||||||
|
nanotime_t clusterEnd = operation->finishedEvent != NULL
|
||||||
|
? operation->finishedEvent->time : lastEventTime;
|
||||||
|
|
||||||
|
for (int32 i = 1; i < operationCount; i++) {
|
||||||
|
operation = operations.ItemAt(i);
|
||||||
|
nanotime_t operationStart = operation->startedEvent->time;
|
||||||
|
nanotime_t operationEnd = operation->finishedEvent != NULL
|
||||||
|
? operation->finishedEvent->time : lastEventTime;
|
||||||
|
|
||||||
|
if (operationStart > clusterEnd) {
|
||||||
|
fSchedulingData.AddIOState(thread,
|
||||||
|
clusterStart - fModel->BaseTime(),
|
||||||
|
IO_SCHEDULING_STATE_PENDING_OPERATION);
|
||||||
|
fSchedulingData.AddIOState(thread,
|
||||||
|
clusterEnd - fModel->BaseTime(),
|
||||||
|
IO_SCHEDULING_STATE_PENDING_REQUEST);
|
||||||
|
|
||||||
|
clusterStart = operationStart;
|
||||||
|
clusterEnd = operationEnd;
|
||||||
|
} else
|
||||||
|
clusterEnd = std::max(clusterEnd, operationEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the last cluster
|
||||||
|
fSchedulingData.AddIOState(thread, clusterStart - fModel->BaseTime(),
|
||||||
|
IO_SCHEDULING_STATE_PENDING_OPERATION);
|
||||||
|
fSchedulingData.AddIOState(thread, clusterEnd - fModel->BaseTime(),
|
||||||
|
IO_SCHEDULING_STATE_PENDING_REQUEST);
|
||||||
|
|
||||||
|
// after the end of the request cluster, state is idle again
|
||||||
|
fSchedulingData.AddIOState(thread, endTime - fModel->BaseTime(),
|
||||||
|
IO_SCHEDULING_STATE_IDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _GetEventTimeRange(nanotime_t& _startTime, nanotime_t& _endTime)
|
void _GetEventTimeRange(nanotime_t& _startTime, nanotime_t& _endTime)
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ public:
|
|||||||
void SetModel(Model* model);
|
void SetModel(Model* model);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct SelectionModel;
|
|
||||||
struct SchedulingEvent;
|
struct SchedulingEvent;
|
||||||
|
struct IOSchedulingEvent;
|
||||||
class SchedulingData;
|
class SchedulingData;
|
||||||
struct TimeRange;
|
struct TimeRange;
|
||||||
class TimelineHeaderRenderer;
|
class TimelineHeaderRenderer;
|
||||||
|
|||||||
Reference in New Issue
Block a user