From c235444841d85e9b231ca58481979bcbbc98a5eb Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 21 Dec 2009 16:53:38 +0000 Subject: [PATCH] * 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 --- src/apps/debuganalyzer/model/Model.cpp | 66 ++++ src/apps/debuganalyzer/model/Model.h | 94 +++++ .../model_loader/ModelLoader.cpp | 323 +++++++++++++++++- .../debuganalyzer/model_loader/ModelLoader.h | 26 ++ 4 files changed, 507 insertions(+), 2 deletions(-) diff --git a/src/apps/debuganalyzer/model/Model.cpp b/src/apps/debuganalyzer/model/Model.cpp index 33b904386d..ee8750b4e2 100644 --- a/src/apps/debuganalyzer/model/Model.cpp +++ b/src/apps/debuganalyzer/model/Model.cpp @@ -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 diff --git a/src/apps/debuganalyzer/model/Model.h b/src/apps/debuganalyzer/model/Model.h index 523d85dc0c..d7c011d8e9 100644 --- a/src/apps/debuganalyzer/model/Model.h +++ b/src/apps/debuganalyzer/model/Model.h @@ -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 { diff --git a/src/apps/debuganalyzer/model_loader/ModelLoader.cpp b/src/apps/debuganalyzer/model_loader/ModelLoader.cpp index d8e9bd353d..131456a7af 100644 --- a/src/apps/debuganalyzer/model_loader/ModelLoader.cpp +++ b/src/apps/debuganalyzer/model_loader/ModelLoader.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -60,6 +61,108 @@ struct ModelLoader::CPUInfo { }; +// #pragma mark - IOOperation + + +struct ModelLoader::IOOperation : DoublyLinkedListLinkImpl { + io_operation_started* startedEvent; + io_operation_finished* finishedEvent; + + IOOperation(io_operation_started* startedEvent) + : + startedEvent(startedEvent), + finishedEvent(NULL) + { + } +}; + + +// #pragma mark - IORequest + + +struct ModelLoader::IORequest : DoublyLinkedListLinkImpl { + 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 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) { diff --git a/src/apps/debuganalyzer/model_loader/ModelLoader.h b/src/apps/debuganalyzer/model_loader/ModelLoader.h index 442ac692c1..ea33da4239 100644 --- a/src/apps/debuganalyzer/model_loader/ModelLoader.h +++ b/src/apps/debuganalyzer/model_loader/ModelLoader.h @@ -6,6 +6,8 @@ #define MAIN_MODEL_LOADER_H +#include + #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 IOOperationList; + typedef DoublyLinkedList IORequestList; + typedef BOpenHashTable 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; };