* Model: Added classes IOOperation and IORequest, and extended Thread to own a

list of IORequests.
* ModelLoader: Process the I/O request and operation related events and create
  the per-thread list of requests.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34732 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-12-21 16:53:38 +00:00
parent 9c1a9b926a
commit c235444841
4 changed files with 507 additions and 2 deletions
+66
View File
@@ -75,6 +75,45 @@ Model::CPU::SetIdleTime(nanotime_t time)
}
// #pragma mark - IORequest
/*static*/ Model::IORequest*
Model::IORequest::Create(system_profiler_io_request_scheduled* scheduledEvent,
system_profiler_io_request_finished* finishedEvent, size_t operationCount)
{
void* memory = malloc(
sizeof(IORequest) + operationCount * sizeof(IOOperation));
if (memory == NULL)
return NULL;
return new(memory) IORequest(scheduledEvent, finishedEvent, operationCount);
}
void
Model::IORequest::Delete()
{
free(this);
}
Model::IORequest::IORequest(
system_profiler_io_request_scheduled* scheduledEvent,
system_profiler_io_request_finished* finishedEvent, size_t operationCount)
:
scheduledEvent(scheduledEvent),
finishedEvent(finishedEvent),
operationCount(operationCount)
{
}
Model::IORequest::~IORequest()
{
}
// #pragma mark - WaitObject
@@ -241,6 +280,8 @@ Model::Thread::Thread(Team* team, const system_profiler_thread_added* event,
:
fEvents(NULL),
fEventCount(0),
fIORequests(NULL),
fIORequestCount(0),
fTeam(team),
fCreationEvent(event),
fCreationTime(time),
@@ -260,6 +301,8 @@ Model::Thread::Thread(Team* team, const system_profiler_thread_added* event,
fWaits(0),
fTotalWaitTime(0),
fUnspecifiedWaitTime(0),
fIOCount(0),
fIOTime(0),
fPreemptions(0),
fIndex(-1),
fWaitObjectGroups(20, true)
@@ -269,6 +312,13 @@ Model::Thread::Thread(Team* team, const system_profiler_thread_added* event,
Model::Thread::~Thread()
{
if (fIORequests != NULL) {
for (size_t i = 0; i < fIORequestCount; i++)
fIORequests[i]->Delete();
delete[] fIORequests;
}
delete[] fEvents;
}
@@ -282,6 +332,14 @@ Model::Thread::SetEvents(system_profiler_event_header** events,
}
void
Model::Thread::SetIORequests(IORequest** requests, size_t requestCount)
{
fIORequests = requests;
fIORequestCount = requestCount;
}
Model::ThreadWaitObjectGroup*
Model::Thread::ThreadWaitObjectGroupFor(uint32 type, addr_t object) const
{
@@ -395,6 +453,14 @@ Model::Thread::AddThreadWaitObject(WaitObject* waitObject,
}
void
Model::Thread::SetIOs(int64 count, nanotime_t time)
{
fIOCount = count;
fIOTime = time;
}
// #pragma mark - SchedulingState
+94
View File
@@ -37,6 +37,8 @@ public:
struct creation_time_id;
struct type_and_object;
class CPU;
struct IOOperation;
struct IORequest;
class WaitObjectGroup;
class WaitObject;
class ThreadWaitObject;
@@ -176,6 +178,40 @@ private:
};
struct Model::IOOperation {
system_profiler_io_operation_started* startedEvent;
system_profiler_io_operation_finished* finishedEvent;
};
struct Model::IORequest {
system_profiler_io_request_scheduled* scheduledEvent;
system_profiler_io_request_finished* finishedEvent;
size_t operationCount;
IOOperation operations[0];
static IORequest* Create(
system_profiler_io_request_scheduled*
scheduledEvent,
system_profiler_io_request_finished*
finishedEvent,
size_t operationCount);
void Delete();
static inline bool SchedulerTimeLess(const IORequest* a,
const IORequest* b);
private:
IORequest(
system_profiler_io_request_scheduled*
scheduledEvent,
system_profiler_io_request_finished*
finishedEvent,
size_t operationCount);
~IORequest();
};
class Model::WaitObject {
public:
WaitObject(
@@ -354,6 +390,11 @@ public:
void SetEvents(system_profiler_event_header** events,
size_t eventCount);
inline IORequest** IORequests() const;
inline size_t CountIORequests() const;
void SetIORequests(IORequest** requests,
size_t requestCount);
inline nanotime_t CreationTime() const;
inline nanotime_t DeletionTime() const;
@@ -368,6 +409,9 @@ public:
inline nanotime_t TotalWaitTime() const;
inline nanotime_t UnspecifiedWaitTime() const;
inline int64 IOCount() const;
inline nanotime_t IOTime() const;
ThreadWaitObjectGroup* ThreadWaitObjectGroupFor(uint32 type,
addr_t object) const;
inline int32 CountThreadWaitObjectGroups() const;
@@ -386,6 +430,8 @@ public:
ThreadWaitObjectGroup**
_threadWaitObjectGroup);
void SetIOs(int64 count, nanotime_t time);
static inline int CompareByID(const Thread* a, const Thread* b);
static inline int CompareWithID(const thread_id* id,
const Thread* thread);
@@ -404,6 +450,9 @@ private:
system_profiler_event_header** fEvents;
size_t fEventCount;
IORequest** fIORequests;
size_t fIORequestCount;
Team* fTeam;
const system_profiler_thread_added* fCreationEvent;
nanotime_t fCreationTime;
@@ -428,6 +477,9 @@ private:
nanotime_t fTotalWaitTime;
nanotime_t fUnspecifiedWaitTime;
int64 fIOCount;
nanotime_t fIOTime;
int64 fPreemptions;
int32 fIndex;
@@ -620,6 +672,20 @@ Model::CPU::IdleTime() const
// #pragma mark - WaitObject
/*static*/ bool
Model::IORequest::SchedulerTimeLess(const IORequest* a, const IORequest* b)
{
int32 cmp = a->scheduledEvent->scheduler - b->scheduledEvent->scheduler;
if (cmp != 0)
return cmp < 0;
return a->scheduledEvent->time < b->scheduledEvent->time;
}
// #pragma mark - WaitObject
uint32
Model::WaitObject::Type() const
{
@@ -991,6 +1057,20 @@ Model::Thread::CountEvents() const
}
Model::IORequest**
Model::Thread::IORequests() const
{
return fIORequests;
}
size_t
Model::Thread::CountIORequests() const
{
return fIORequestCount;
}
int64
Model::Thread::Runs() const
{
@@ -1061,6 +1141,20 @@ Model::Thread::UnspecifiedWaitTime() const
}
int64
Model::Thread::IOCount() const
{
return fIOCount;
}
nanotime_t
Model::Thread::IOTime() const
{
return fIOTime;
}
int32
Model::Thread::CountThreadWaitObjectGroups() const
{
@@ -9,6 +9,7 @@
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <new>
#include <AutoDeleter.h>
@@ -60,6 +61,108 @@ struct ModelLoader::CPUInfo {
};
// #pragma mark - IOOperation
struct ModelLoader::IOOperation : DoublyLinkedListLinkImpl<IOOperation> {
io_operation_started* startedEvent;
io_operation_finished* finishedEvent;
IOOperation(io_operation_started* startedEvent)
:
startedEvent(startedEvent),
finishedEvent(NULL)
{
}
};
// #pragma mark - IORequest
struct ModelLoader::IORequest : DoublyLinkedListLinkImpl<IORequest> {
io_request_scheduled* scheduledEvent;
io_request_finished* finishedEvent;
IOOperationList operations;
size_t operationCount;
IORequest* hashNext;
IORequest(io_request_scheduled* scheduledEvent)
:
scheduledEvent(scheduledEvent),
finishedEvent(NULL),
operationCount(0)
{
}
~IORequest()
{
while (IOOperation* operation = operations.RemoveHead())
delete operation;
}
void AddOperation(IOOperation* operation)
{
operations.Add(operation);
operationCount++;
}
IOOperation* FindOperation(void* address) const
{
for (IOOperationList::ConstReverseIterator it
= operations.GetReverseIterator();
IOOperation* operation = it.Next();) {
if (operation->startedEvent->operation == address)
return operation;
}
return NULL;
}
Model::IORequest* CreateModelRequest() const
{
size_t operationCount = operations.Count();
Model::IORequest* modelRequest = Model::IORequest::Create(
scheduledEvent, finishedEvent, operationCount);
if (modelRequest == NULL)
return NULL;
size_t index = 0;
for (IOOperationList::ConstIterator it = operations.GetIterator();
IOOperation* operation = it.Next();) {
Model::IOOperation& modelOperation
= modelRequest->operations[index++];
modelOperation.startedEvent = operation->startedEvent;
modelOperation.finishedEvent = operation->finishedEvent;
}
return modelRequest;
}
};
// #pragma mark - IORequestHashDefinition
struct ModelLoader::IORequestHashDefinition {
typedef void* KeyType;
typedef IORequest ValueType;
size_t HashKey(KeyType key) const
{ return (size_t)key; }
size_t Hash(const IORequest* value) const
{ return HashKey(value->scheduledEvent->request); }
bool Compare(KeyType key, const IORequest* value) const
{ return key == value->scheduledEvent->request; }
IORequest*& GetLink(IORequest* value) const
{ return value->hashNext; }
};
// #pragma mark - ExtendedThreadSchedulingState
@@ -78,6 +181,11 @@ struct ModelLoader::ExtendedThreadSchedulingState
~ExtendedThreadSchedulingState()
{
delete[] fEvents;
while (IORequest* request = fIORequests.RemoveHead())
delete request;
while (IORequest* request = fPendingIORequests.RemoveHead())
delete request;
}
system_profiler_event_header** Events() const
@@ -119,10 +227,59 @@ struct ModelLoader::ExtendedThreadSchedulingState
return true;
}
void AddIORequest(IORequest* request)
{
fPendingIORequests.Add(request);
}
void IORequestFinished(IORequest* request)
{
fPendingIORequests.Remove(request);
fIORequests.Add(request);
}
bool PrepareThreadIORequests(Model::IORequest**& _requests,
size_t& _requestCount)
{
fIORequests.MoveFrom(&fPendingIORequests);
size_t requestCount = fIORequests.Count();
if (requestCount == 0) {
_requests = NULL;
_requestCount = 0;
return true;
}
Model::IORequest** requests
= new(std::nothrow) Model::IORequest*[requestCount];
if (requests == NULL)
return false;
size_t index = 0;
while (IORequest* request = fIORequests.RemoveHead()) {
ObjectDeleter<IORequest> requestDeleter(request);
Model::IORequest* modelRequest = request->CreateModelRequest();
if (modelRequest == NULL) {
for (size_t i = 0; i < index; i++)
requests[i]->Delete();
return false;
}
requests[index++] = modelRequest;
}
_requests = requests;
_requestCount = requestCount;
return true;
}
private:
system_profiler_event_header** fEvents;
size_t fEventIndex;
size_t fEventCount;
IORequestList fIORequests;
IORequestList fPendingIORequests;
};
@@ -168,7 +325,9 @@ ModelLoader::ModelLoader(DataSource* dataSource,
AbstractModelLoader(target, targetCookie),
fModel(NULL),
fDataSource(dataSource),
fCPUInfos(NULL)
fCPUInfos(NULL),
fState(NULL),
fIORequests(NULL)
{
}
@@ -178,6 +337,8 @@ ModelLoader::~ModelLoader()
delete[] fCPUInfos;
delete fDataSource;
delete fModel;
delete fState;
delete fIORequests;
}
@@ -211,10 +372,16 @@ ModelLoader::PrepareForLoading()
if (error != B_OK)
return error;
// create CPU info array
fCPUInfos = new(std::nothrow) CPUInfo[kMaxCPUCount];
if (fCPUInfos == NULL)
return B_NO_MEMORY;
// create IORequest hash table
fIORequests = new(std::nothrow) IORequestTable;
if (fIORequests == NULL || fIORequests->Init() != B_OK)
return B_NO_MEMORY;
return B_OK;
}
@@ -243,6 +410,18 @@ ModelLoader::FinishLoading(bool success)
delete[] fCPUInfos;
fCPUInfos = NULL;
if (fIORequests != NULL) {
IORequest* request = fIORequests->Clear(true);
while (request != NULL) {
IORequest* next = request->hashNext;
delete request;
request = next;
}
delete fIORequests;
fIORequests = NULL;
}
}
@@ -340,7 +519,7 @@ ModelLoader::_Load()
fModel->SetLastEventTime(fState->LastEventTime());
if (!_SetThreadEvents())
if (!_SetThreadEvents() || !_SetThreadIORequests())
return B_NO_MEMORY;
fModel->LoadingFinished();
@@ -530,10 +709,20 @@ ModelLoader::_ProcessEvent(uint32 event, uint32 cpu, const void* buffer,
case B_SYSTEM_PROFILER_IO_SCHEDULER_ADDED:
case B_SYSTEM_PROFILER_IO_SCHEDULER_REMOVED:
// TODO: Handle!
break;
case B_SYSTEM_PROFILER_IO_REQUEST_SCHEDULED:
_HandleIORequestScheduled((io_request_scheduled*)buffer);
break;
case B_SYSTEM_PROFILER_IO_REQUEST_FINISHED:
_HandleIORequestFinished((io_request_finished*)buffer);
break;
case B_SYSTEM_PROFILER_IO_OPERATION_STARTED:
_HandleIOOperationStarted((io_operation_started*)buffer);
break;
case B_SYSTEM_PROFILER_IO_OPERATION_FINISHED:
_HandleIOOperationFinished((io_operation_finished*)buffer);
break;
default:
@@ -628,6 +817,67 @@ ModelLoader::_SetThreadEvents()
}
bool
ModelLoader::_SetThreadIORequests()
{
for (int32 i = 0; Model::Thread* thread = fModel->ThreadAt(i); i++) {
ExtendedThreadSchedulingState* state
= fState->LookupThread(thread->ID());
Model::IORequest** requests;
size_t requestCount;
if (!state->PrepareThreadIORequests(requests, requestCount))
return false;
if (requestCount > 0)
_SetThreadIORequests(thread, requests, requestCount);
}
return true;
}
void
ModelLoader::_SetThreadIORequests(Model::Thread* thread,
Model::IORequest** requests, size_t requestCount)
{
// compute some totals
int64 ioCount = 0;
nanotime_t ioTime = 0;
// sort requests by scheduler and start time
std::sort(requests, requests + requestCount,
Model::IORequest::SchedulerTimeLess);
nanotime_t endTime = fBaseTime + fModel->LastEventTime();
// compute the summed up I/O times
nanotime_t ioStart = requests[0]->scheduledEvent->time;
nanotime_t previousEnd = requests[0]->finishedEvent != NULL
? requests[0]->finishedEvent->time : endTime;
int32 scheduler = requests[0]->scheduledEvent->scheduler;
for (size_t i = 1; i < requestCount; i++) {
system_profiler_io_request_scheduled* scheduledEvent
= requests[i]->scheduledEvent;
if (scheduledEvent->scheduler != scheduler
|| scheduledEvent->time >= previousEnd) {
ioCount++;
ioTime += previousEnd - ioStart;
ioStart = scheduledEvent->time;
}
previousEnd = requests[i]->finishedEvent != NULL
? requests[i]->finishedEvent->time : endTime;
}
ioCount++;
ioTime += previousEnd - ioStart;
// set the computed values
thread->SetIORequests(requests, requestCount);
thread->SetIOs(ioCount, ioTime);
}
void
ModelLoader::_HandleTeamAdded(system_profiler_team_added* event)
{
@@ -858,6 +1108,75 @@ ModelLoader::_HandleWaitObjectInfo(system_profiler_wait_object_info* event)
}
void
ModelLoader::_HandleIORequestScheduled(io_request_scheduled* event)
{
IORequest* request = fIORequests->Lookup(event->request);
if (request != NULL) {
printf("Duplicate schedule event for I/O request %p\n", event->request);
return;
}
ExtendedThreadSchedulingState* thread = fState->LookupThread(event->thread);
if (thread == NULL) {
printf("I/O request for unknown thread %ld\n", event->thread);
return;
}
request = new(std::nothrow) IORequest(event);
if (request == NULL)
throw std::bad_alloc();
fIORequests->Insert(request);
thread->AddIORequest(request);
}
void
ModelLoader::_HandleIORequestFinished(io_request_finished* event)
{
IORequest* request = fIORequests->Lookup(event->request);
if (request == NULL)
return;
request->finishedEvent = event;
fIORequests->Remove(request);
fState->LookupThread(request->scheduledEvent->thread)
->IORequestFinished(request);
}
void
ModelLoader::_HandleIOOperationStarted(io_operation_started* event)
{
IORequest* request = fIORequests->Lookup(event->request);
if (request == NULL)
return;
IOOperation* operation = new(std::nothrow) IOOperation(event);
if (operation == NULL)
throw std::bad_alloc();
request->AddOperation(operation);
}
void
ModelLoader::_HandleIOOperationFinished(io_operation_finished* event)
{
IORequest* request = fIORequests->Lookup(event->request);
if (request == NULL)
return;
IOOperation* operation = request->FindOperation(event->operation);
if (operation == NULL)
return;
operation->finishedEvent = event;
}
ModelLoader::ExtendedThreadSchedulingState*
ModelLoader::_AddThread(system_profiler_thread_added* event)
{
@@ -6,6 +6,8 @@
#define MAIN_MODEL_LOADER_H
#include <util/DoublyLinkedList.h>
#include "AbstractModelLoader.h"
#include "Model.h"
@@ -39,11 +41,22 @@ private:
thread_enqueued_in_run_queue;
typedef system_profiler_thread_removed_from_run_queue
thread_removed_from_run_queue;
typedef system_profiler_io_request_scheduled io_request_scheduled;
typedef system_profiler_io_request_finished io_request_finished;
typedef system_profiler_io_operation_started io_operation_started;
typedef system_profiler_io_operation_finished io_operation_finished;
struct CPUInfo;
struct IOOperation;
struct IORequest;
struct IORequestHashDefinition;
struct ExtendedThreadSchedulingState;
struct ExtendedSchedulingState;
typedef DoublyLinkedList<ModelLoader::IOOperation> IOOperationList;
typedef DoublyLinkedList<ModelLoader::IORequest> IORequestList;
typedef BOpenHashTable<IORequestHashDefinition> IORequestTable;
private:
status_t _Load();
status_t _ReadDebugEvents(void** _eventData,
@@ -55,6 +68,10 @@ private:
status_t _ProcessEvent(uint32 event, uint32 cpu,
const void* buffer, size_t size);
bool _SetThreadEvents();
bool _SetThreadIORequests();
void _SetThreadIORequests(Model::Thread* thread,
Model::IORequest** requests,
size_t requestCount);
inline void _UpdateLastEventTime(nanotime_t time);
@@ -76,6 +93,14 @@ private:
thread_removed_from_run_queue* event);
void _HandleWaitObjectInfo(
system_profiler_wait_object_info* event);
void _HandleIORequestScheduled(
io_request_scheduled* event);
void _HandleIORequestFinished(
io_request_finished* event);
void _HandleIOOperationStarted(
io_operation_started* event);
void _HandleIOOperationFinished(
io_operation_finished* event);
ExtendedThreadSchedulingState* _AddThread(
system_profiler_thread_added* event);
@@ -91,6 +116,7 @@ private:
CPUInfo* fCPUInfos;
nanotime_t fBaseTime;
ExtendedSchedulingState* fState;
IORequestTable* fIORequests;
uint32 fMaxCPUIndex;
};