Author: bonefish Date: 2009-12-19 15:33:29 +0100 (Sat, 19 Dec 2009) New Revision: 34703 Changeset: http://dev.haiku-os.org/changeset/34703/haiku Modified: haiku/trunk/headers/private/system/system_profiler_defs.h haiku/trunk/src/system/kernel/debug/system_profiler.cpp Log: Added support for I/O scheduling events to the system profiler interface. Modified: haiku/trunk/headers/private/system/system_profiler_defs.h =================================================================== --- haiku/trunk/headers/private/system/system_profiler_defs.h 2009-12-19 14:32:14 UTC (rev 34702) +++ haiku/trunk/headers/private/system/system_profiler_defs.h 2009-12-19 14:33:29 UTC (rev 34703) @@ -26,11 +26,12 @@ // event flags enum { - B_SYSTEM_PROFILER_TEAM_EVENTS = 0x01, - B_SYSTEM_PROFILER_THREAD_EVENTS = 0x02, - B_SYSTEM_PROFILER_IMAGE_EVENTS = 0x04, - B_SYSTEM_PROFILER_SAMPLING_EVENTS = 0x08, - B_SYSTEM_PROFILER_SCHEDULING_EVENTS = 0x10 + B_SYSTEM_PROFILER_TEAM_EVENTS = 0x01, + B_SYSTEM_PROFILER_THREAD_EVENTS = 0x02, + B_SYSTEM_PROFILER_IMAGE_EVENTS = 0x04, + B_SYSTEM_PROFILER_SAMPLING_EVENTS = 0x08, + B_SYSTEM_PROFILER_SCHEDULING_EVENTS = 0x10, + B_SYSTEM_PROFILER_IO_SCHEDULING_EVENTS = 0x20 }; @@ -62,7 +63,15 @@ B_SYSTEM_PROFILER_THREAD_SCHEDULED, B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE, B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE, - B_SYSTEM_PROFILER_WAIT_OBJECT_INFO + B_SYSTEM_PROFILER_WAIT_OBJECT_INFO, + + // I/O scheduling + B_SYSTEM_PROFILER_IO_SCHEDULER_ADDED, + B_SYSTEM_PROFILER_IO_SCHEDULER_REMOVED, + B_SYSTEM_PROFILER_IO_REQUEST_SCHEDULED, + B_SYSTEM_PROFILER_IO_REQUEST_FINISHED, + B_SYSTEM_PROFILER_IO_OPERATION_STARTED, + B_SYSTEM_PROFILER_IO_OPERATION_FINISHED }; @@ -166,5 +175,59 @@ char name[1]; }; +// B_SYSTEM_PROFILER_IO_SCHEDULER_ADDED +struct system_profiler_io_scheduler_added { + int32 scheduler; + char name[1]; +}; +// B_SYSTEM_PROFILER_IO_SCHEDULER_REMOVED +struct system_profiler_io_scheduler_removed { + int32 scheduler; +}; + +// B_SYSTEM_PROFILER_IO_REQUEST_SCHEDULED +struct system_profiler_io_request_scheduled { + nanotime_t time; + int32 scheduler; + team_id team; + thread_id thread; + void* request; + off_t offset; + size_t length; + bool write; + uint8 priority; +}; + +// B_SYSTEM_PROFILER_IO_REQUEST_FINISHED +struct system_profiler_io_request_finished { + nanotime_t time; + int32 scheduler; + void* request; + status_t status; + size_t transferred; +}; + +// B_SYSTEM_PROFILER_IO_OPERATION_STARTED +struct system_profiler_io_operation_started { + nanotime_t time; + int32 scheduler; + void* request; + void* operation; + off_t offset; + size_t length; + bool write; +}; + +// B_SYSTEM_PROFILER_IO_OPERATION_FINISHED +struct system_profiler_io_operation_finished { + nanotime_t time; + int32 scheduler; + void* request; + void* operation; + status_t status; + size_t transferred; +}; + + #endif /* _SYSTEM_SYSTEM_PROFILER_DEFS_H */ Modified: haiku/trunk/src/system/kernel/debug/system_profiler.cpp =================================================================== --- haiku/trunk/src/system/kernel/debug/system_profiler.cpp 2009-12-19 14:32:14 UTC (rev 34702) +++ haiku/trunk/src/system/kernel/debug/system_profiler.cpp 2009-12-19 14:33:29 UTC (rev 34703) @@ -27,11 +27,14 @@ #include <arch/debug.h> +#include "IOScheduler.h" + // This is the kernel-side implementation of the system profiling support. // A userland team can register as system profiler, providing an area as buffer -// for events. Those events are team, thread, and image changes (added/removed) -// and periodic sampling of the return address stack for each CPU. +// for events. Those events are team, thread, and image changes (added/removed), +// periodic sampling of the return address stack for each CPU, as well as +// scheduling and I/O scheduling events. class SystemProfiler; @@ -89,6 +92,17 @@ bool _ImageAdded(struct image* image); bool _ImageRemoved(struct image* image); + bool _IOSchedulerAdded(IOScheduler* scheduler); + bool _IOSchedulerRemoved(IOScheduler* scheduler); + bool _IORequestScheduled(IOScheduler* scheduler, + IORequest* request); + bool _IORequestFinished(IOScheduler* scheduler, + IORequest* request); + bool _IOOperationStarted(IOScheduler* scheduler, + IORequest* request, IOOperation* operation); + bool _IOOperationFinished(IOScheduler* scheduler, + IORequest* request, IOOperation* operation); + void _WaitObjectCreated(addr_t object, uint32 type); void _WaitObjectUsed(addr_t object, uint32 type); @@ -182,6 +196,8 @@ bool fThreadNotificationsEnabled; bool fImageNotificationsRequested; bool fImageNotificationsEnabled; + bool fIONotificationsRequested; + bool fIONotificationsEnabled; bool fSchedulerNotificationsRequested; bool fWaitObjectNotificationsRequested; ConditionVariable fProfilerWaitCondition; @@ -247,6 +263,8 @@ fThreadNotificationsEnabled(false), fImageNotificationsRequested(false), fImageNotificationsEnabled(false), + fIONotificationsRequested(false), + fIONotificationsEnabled(false), fSchedulerNotificationsRequested(false), fWaitObjectNotificationsRequested(false), fProfilerWaiting(false), @@ -323,6 +341,12 @@ notificationManager.RemoveListener("teams", NULL, *this); } + // I/O + if (fIONotificationsRequested) { + fIONotificationsRequested = false; + notificationManager.RemoveListener("I/O", NULL, *this); + } + // delete wait object related allocations fWaitObjectTable.Clear(); delete[] fWaitObjectBuffer; @@ -407,6 +431,19 @@ fImageNotificationsRequested = true; } + // I/O events + if ((fFlags & B_SYSTEM_PROFILER_IO_SCHEDULING_EVENTS) != 0) { + error = notificationManager.AddListener("I/O", + IO_SCHEDULER_ADDED | IO_SCHEDULER_REMOVED + | IO_SCHEDULER_REQUEST_SCHEDULED | IO_SCHEDULER_REQUEST_FINISHED + | IO_SCHEDULER_OPERATION_STARTED + | IO_SCHEDULER_OPERATION_FINISHED, + *this); + if (error != B_OK) + return error; + fIONotificationsRequested = true; + } + // We need to fill the buffer with the initial state of teams, threads, // and images. @@ -463,6 +500,20 @@ threadsLocker.Unlock(); + // I/O scheduling + if ((fFlags & B_SYSTEM_PROFILER_IO_SCHEDULING_EVENTS) != 0) { + IOSchedulerRoster* roster = IOSchedulerRoster::Default(); + AutoLocker<IOSchedulerRoster> rosterLocker(roster); + + for (IOSchedulerList::ConstIterator it + = roster->SchedulerList().GetIterator(); + IOScheduler* scheduler = it.Next();) { + _IOSchedulerAdded(scheduler); + } + + fIONotificationsEnabled = true; + } + // activate the profiling timers on all CPUs if ((fFlags & B_SYSTEM_PROFILER_SAMPLING_EVENTS) != 0) call_all_cpus(_InitTimers, this); @@ -606,6 +657,44 @@ _ImageRemoved(image); break; } + } else if (strcmp(service.Name(), "I/O") == 0) { + if (!fIONotificationsEnabled) + return; + + IOScheduler* scheduler = (IOScheduler*)event->GetPointer("scheduler", + NULL); + if (scheduler == NULL) + return; + + IORequest* request = (IORequest*)event->GetPointer("request", NULL); + IOOperation* operation = (IOOperation*)event->GetPointer("operation", + NULL); + + switch (eventCode) { + case IO_SCHEDULER_ADDED: + _IOSchedulerAdded(scheduler); + break; + + case IO_SCHEDULER_REMOVED: + _IOSchedulerRemoved(scheduler); + break; + + case IO_SCHEDULER_REQUEST_SCHEDULED: + _IORequestScheduled(scheduler, request); + break; + + case IO_SCHEDULER_REQUEST_FINISHED: + _IORequestFinished(scheduler, request); + break; + + case IO_SCHEDULER_OPERATION_STARTED: + _IOOperationStarted(scheduler, request, operation); + break; + + case IO_SCHEDULER_OPERATION_FINISHED: + _IOOperationFinished(scheduler, request, operation); + break; + } } _MaybeNotifyProfilerThread(); @@ -734,11 +823,11 @@ bool SystemProfiler::_TeamAdded(struct team* team) { - InterruptsSpinLocker locker(fLock); - size_t nameLen = strlen(team->name); size_t argsLen = strlen(team->args); + InterruptsSpinLocker locker(fLock); + system_profiler_team_added* event = (system_profiler_team_added*) _AllocateBuffer( sizeof(system_profiler_team_added) + nameLen + 1 + argsLen, @@ -779,10 +868,10 @@ bool SystemProfiler::_TeamExec(struct team* team) { + size_t argsLen = strlen(team->args); + InterruptsSpinLocker locker(fLock); - size_t argsLen = strlen(team->args); - system_profiler_team_exec* event = (system_profiler_team_exec*) _AllocateBuffer(sizeof(system_profiler_team_exec) + argsLen, B_SYSTEM_PROFILER_TEAM_EXEC, 0, 0); @@ -882,6 +971,156 @@ } +bool +SystemProfiler::_IOSchedulerAdded(IOScheduler* scheduler) +{ + size_t nameLen = strlen(scheduler->Name()); + + InterruptsSpinLocker locker(fLock); + + system_profiler_io_scheduler_added* event + = (system_profiler_io_scheduler_added*)_AllocateBuffer( + sizeof(system_profiler_io_scheduler_added) + nameLen, + B_SYSTEM_PROFILER_IO_SCHEDULER_ADDED, 0, 0); + if (event == NULL) + return false; + + event->scheduler = scheduler->ID(); + strcpy(event->name, scheduler->Name()); + + fHeader->size = fBufferSize; + + return true; +} + + +bool +SystemProfiler::_IOSchedulerRemoved(IOScheduler* scheduler) +{ + InterruptsSpinLocker locker(fLock); + + system_profiler_io_scheduler_removed* event + = (system_profiler_io_scheduler_removed*)_AllocateBuffer( + sizeof(system_profiler_io_scheduler_removed), + B_SYSTEM_PROFILER_IO_SCHEDULER_REMOVED, 0, 0); + if (event == NULL) + return false; + + event->scheduler = scheduler->ID(); + + fHeader->size = fBufferSize; + + return true; +} + + +bool +SystemProfiler::_IORequestScheduled(IOScheduler* scheduler, IORequest* request) +{ + InterruptsSpinLocker locker(fLock); + + system_profiler_io_request_scheduled* event + = (system_profiler_io_request_scheduled*)_AllocateBuffer( + sizeof(system_profiler_io_request_scheduled), + B_SYSTEM_PROFILER_IO_REQUEST_SCHEDULED, 0, 0); + if (event == NULL) + return false; + + IORequestOwner* owner = request->Owner(); + + event->time = system_time_nsecs(); + event->scheduler = scheduler->ID(); + event->team = owner->team; + event->thread = owner->thread; + event->request = request; + event->offset = request->Offset(); + event->length = request->Length(); + event->write = request->IsWrite(); + event->priority = owner->priority; + + fHeader->size = fBufferSize; + + return true; +} + + +bool +SystemProfiler::_IORequestFinished(IOScheduler* scheduler, IORequest* request) +{ + InterruptsSpinLocker locker(fLock); + + system_profiler_io_request_finished* event + = (system_profiler_io_request_finished*)_AllocateBuffer( + sizeof(system_profiler_io_request_finished), + B_SYSTEM_PROFILER_IO_REQUEST_FINISHED, 0, 0); + if (event == NULL) + return false; + + event->time = system_time_nsecs(); + event->scheduler = scheduler->ID(); + event->request = request; + event->status = request->Status(); + event->transferred = request->TransferredBytes(); + + fHeader->size = fBufferSize; + + return true; +} + + +bool +SystemProfiler::_IOOperationStarted(IOScheduler* scheduler, IORequest* request, + IOOperation* operation) +{ + InterruptsSpinLocker locker(fLock); + + system_profiler_io_operation_started* event + = (system_profiler_io_operation_started*)_AllocateBuffer( + sizeof(system_profiler_io_operation_started), + B_SYSTEM_PROFILER_IO_OPERATION_STARTED, 0, 0); + if (event == NULL) + return false; + + event->time = system_time_nsecs(); + event->scheduler = scheduler->ID(); + event->request = request; + event->operation = operation; + event->offset = request->Offset(); + event->length = request->Length(); + event->write = request->IsWrite(); + + fHeader->size = fBufferSize; + + return true; +} + + +bool +SystemProfiler::_IOOperationFinished(IOScheduler* scheduler, IORequest* request, + IOOperation* operation) +{ + InterruptsSpinLocker locker(fLock); + + system_profiler_io_operation_finished* event + = (system_profiler_io_operation_finished*)_AllocateBuffer( + sizeof(system_profiler_io_operation_finished), + B_SYSTEM_PROFILER_IO_OPERATION_FINISHED, 0, 0); + if (event == NULL) + return false; + + event->time = system_time_nsecs(); + event->scheduler = scheduler->ID(); + event->request = request; + event->operation = operation; + event->status = request->Status(); + event->transferred = request->TransferredBytes(); + + fHeader->size = fBufferSize; + + return true; +} + + void SystemProfiler::_WaitObjectCreated(addr_t object, uint32 type) { @@ -1188,6 +1427,7 @@ sRecordedParameters->buffer_area = area; sRecordedParameters->flags = B_SYSTEM_PROFILER_TEAM_EVENTS | B_SYSTEM_PROFILER_THREAD_EVENTS | B_SYSTEM_PROFILER_IMAGE_EVENTS + | B_SYSTEM_PROFILER_IO_SCHEDULING_EVENTS | B_SYSTEM_PROFILER_SAMPLING_EVENTS; sRecordedParameters->locking_lookup_size = 4096; sRecordedParameters->interval = interval;