Added support for I/O scheduling events to the system profiler interface.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34703 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-12-19 14:33:29 +00:00
parent ca77afe75f
commit 189010cbc2
2 changed files with 315 additions and 12 deletions
+69 -6
View File
@@ -26,11 +26,12 @@ struct system_profiler_parameters {
// 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 @@ enum {
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 @@ struct system_profiler_wait_object_info {
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 */
+246 -6
View File
@@ -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 @@ private:
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 @@ private:
bool fThreadNotificationsEnabled;
bool fImageNotificationsRequested;
bool fImageNotificationsEnabled;
bool fIONotificationsRequested;
bool fIONotificationsEnabled;
bool fSchedulerNotificationsRequested;
bool fWaitObjectNotificationsRequested;
ConditionVariable fProfilerWaitCondition;
@@ -247,6 +263,8 @@ SystemProfiler::SystemProfiler(team_id team, const area_info& userAreaInfo,
fThreadNotificationsEnabled(false),
fImageNotificationsRequested(false),
fImageNotificationsEnabled(false),
fIONotificationsRequested(false),
fIONotificationsEnabled(false),
fSchedulerNotificationsRequested(false),
fWaitObjectNotificationsRequested(false),
fProfilerWaiting(false),
@@ -323,6 +341,12 @@ SystemProfiler::~SystemProfiler()
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 @@ SystemProfiler::Init()
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 @@ SystemProfiler::Init()
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 @@ SystemProfiler::EventOccurred(NotificationService& service,
_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 @@ SystemProfiler::RWLockInitialized(rw_lock* lock)
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 @@ SystemProfiler::_TeamRemoved(struct team* team)
bool
SystemProfiler::_TeamExec(struct team* team)
{
InterruptsSpinLocker locker(fLock);
size_t argsLen = strlen(team->args);
InterruptsSpinLocker locker(fLock);
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 @@ SystemProfiler::_ImageRemoved(struct image* image)
}
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 @@ start_system_profiler(size_t areaSize, uint32 stackDepth, bigtime_t interval)
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;