* Changed the interface of _kern_system_profiler_start(). The parameters are
passed in a structure now, so it is easier to extend it and ignore unused parameters. * One can now select which system profiling events one is interested in. * Added scheduling events to the system profiling interface. Those are pretty much the ones recorded when scheduler tracing is enabled. Still missing are the "wait object" events that allow to interpret what a thread is waiting for. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30243 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
79257a4ad6
commit
5b2f0f33f9
@ -10,10 +10,13 @@
|
|||||||
#include <OS.h>
|
#include <OS.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct system_profiler_parameters;
|
||||||
|
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
status_t _user_system_profiler_start(area_id bufferArea,
|
status_t _user_system_profiler_start(
|
||||||
bigtime_t interval, int32 stackDepth);
|
struct system_profiler_parameters* parameters);
|
||||||
status_t _user_system_profiler_next_buffer(size_t bytesRead);
|
status_t _user_system_profiler_next_buffer(size_t bytesRead);
|
||||||
status_t _user_system_profiler_stop();
|
status_t _user_system_profiler_stop();
|
||||||
|
|
||||||
|
@ -30,11 +30,12 @@ struct net_stat;
|
|||||||
struct pollfd;
|
struct pollfd;
|
||||||
struct rlimit;
|
struct rlimit;
|
||||||
struct scheduling_analysis;
|
struct scheduling_analysis;
|
||||||
struct sigaction;
|
|
||||||
struct stat;
|
|
||||||
struct _sem_t;
|
struct _sem_t;
|
||||||
struct sembuf;
|
struct sembuf;
|
||||||
union semun;
|
union semun;
|
||||||
|
struct sigaction;
|
||||||
|
struct stat;
|
||||||
|
struct system_profiler_parameters;
|
||||||
|
|
||||||
struct disk_device_job_progress_info;
|
struct disk_device_job_progress_info;
|
||||||
struct partitionable_space_data;
|
struct partitionable_space_data;
|
||||||
@ -390,8 +391,8 @@ extern status_t _kern_set_debugger_breakpoint(void *address, uint32 type,
|
|||||||
extern status_t _kern_clear_debugger_breakpoint(void *address,
|
extern status_t _kern_clear_debugger_breakpoint(void *address,
|
||||||
bool watchpoint);
|
bool watchpoint);
|
||||||
|
|
||||||
extern status_t _kern_system_profiler_start(area_id bufferArea,
|
extern status_t _kern_system_profiler_start(
|
||||||
bigtime_t interval, int32 stackDepth);
|
struct system_profiler_parameters* parameters);
|
||||||
extern status_t _kern_system_profiler_next_buffer(size_t bytesRead);
|
extern status_t _kern_system_profiler_next_buffer(size_t bytesRead);
|
||||||
extern status_t _kern_system_profiler_stop();
|
extern status_t _kern_system_profiler_stop();
|
||||||
|
|
||||||
|
@ -8,17 +8,60 @@
|
|||||||
#include <image.h>
|
#include <image.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct system_profiler_parameters {
|
||||||
|
// general
|
||||||
|
area_id buffer_area; // area the events will be written to
|
||||||
|
uint32 flags; // flags selecting the events to receive
|
||||||
|
|
||||||
|
// scheduling
|
||||||
|
size_t locking_lookup_size; // size of the lookup table used for
|
||||||
|
// caching the locking primitive infos
|
||||||
|
|
||||||
|
// sampling
|
||||||
|
bigtime_t interval; // interval at which to take samples
|
||||||
|
uint32 stack_depth; // maximum stack depth to sample
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 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
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// events
|
// events
|
||||||
enum {
|
enum {
|
||||||
B_SYSTEM_PROFILER_TEAM_ADDED = 0,
|
// reserved for the user application
|
||||||
|
B_SYSTEM_PROFILER_USER_EVENT = 0,
|
||||||
|
|
||||||
|
// ring buffer wrap-around marker
|
||||||
|
B_SYSTEM_PROFILER_BUFFER_END,
|
||||||
|
|
||||||
|
// team
|
||||||
|
B_SYSTEM_PROFILER_TEAM_ADDED,
|
||||||
B_SYSTEM_PROFILER_TEAM_REMOVED,
|
B_SYSTEM_PROFILER_TEAM_REMOVED,
|
||||||
B_SYSTEM_PROFILER_TEAM_EXEC,
|
B_SYSTEM_PROFILER_TEAM_EXEC,
|
||||||
|
|
||||||
|
// thread
|
||||||
B_SYSTEM_PROFILER_THREAD_ADDED,
|
B_SYSTEM_PROFILER_THREAD_ADDED,
|
||||||
B_SYSTEM_PROFILER_THREAD_REMOVED,
|
B_SYSTEM_PROFILER_THREAD_REMOVED,
|
||||||
|
|
||||||
|
// image
|
||||||
B_SYSTEM_PROFILER_IMAGE_ADDED,
|
B_SYSTEM_PROFILER_IMAGE_ADDED,
|
||||||
B_SYSTEM_PROFILER_IMAGE_REMOVED,
|
B_SYSTEM_PROFILER_IMAGE_REMOVED,
|
||||||
|
|
||||||
|
// profiling samples
|
||||||
B_SYSTEM_PROFILER_SAMPLES,
|
B_SYSTEM_PROFILER_SAMPLES,
|
||||||
B_SYSTEM_PROFILER_SAMPLES_END
|
|
||||||
|
// scheduling
|
||||||
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -84,5 +127,36 @@ struct system_profiler_samples {
|
|||||||
addr_t samples[0];
|
addr_t samples[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// B_SYSTEM_PROFILER_THREAD_SCHEDULED,
|
||||||
|
struct system_profiler_thread_scheduled {
|
||||||
|
bigtime_t time;
|
||||||
|
thread_id thread;
|
||||||
|
thread_id previous_thread;
|
||||||
|
uint16 previous_thread_state;
|
||||||
|
uint16 previous_thread_wait_object_type;
|
||||||
|
addr_t previous_thread_wait_object;
|
||||||
|
};
|
||||||
|
|
||||||
|
// B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE,
|
||||||
|
struct system_profiler_thread_enqueued_in_run_queue {
|
||||||
|
bigtime_t time;
|
||||||
|
thread_id thread;
|
||||||
|
uint8 priority;
|
||||||
|
};
|
||||||
|
|
||||||
|
// B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE,
|
||||||
|
struct system_profiler_thread_removed_from_run_queue {
|
||||||
|
bigtime_t time;
|
||||||
|
thread_id thread;
|
||||||
|
};
|
||||||
|
|
||||||
|
// B_SYSTEM_PROFILER_WAIT_OBJECT_INFO
|
||||||
|
struct system_profiler_wait_object_info {
|
||||||
|
uint32 type;
|
||||||
|
addr_t object;
|
||||||
|
addr_t referenced_object;
|
||||||
|
char name[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif /* _SYSTEM_SYSTEM_PROFILER_DEFS_H */
|
#endif /* _SYSTEM_SYSTEM_PROFILER_DEFS_H */
|
||||||
|
@ -525,7 +525,7 @@ process_event_buffer(ThreadManager& threadManager, uint8* buffer,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case B_SYSTEM_PROFILER_SAMPLES_END:
|
case B_SYSTEM_PROFILER_BUFFER_END:
|
||||||
{
|
{
|
||||||
// Marks the end of the ring buffer -- we need to ignore the
|
// Marks the end of the ring buffer -- we need to ignore the
|
||||||
// remaining bytes.
|
// remaining bytes.
|
||||||
@ -575,7 +575,7 @@ profile_all(const char* const* programArgs, int programArgCount)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create and area for the sample buffer
|
// create an area for the sample buffer
|
||||||
system_profiler_buffer_header* bufferHeader;
|
system_profiler_buffer_header* bufferHeader;
|
||||||
area_id area = create_area("profiling buffer", (void**)&bufferHeader,
|
area_id area = create_area("profiling buffer", (void**)&bufferHeader,
|
||||||
B_ANY_ADDRESS, PROFILE_ALL_SAMPLE_AREA_SIZE, B_NO_LOCK,
|
B_ANY_ADDRESS, PROFILE_ALL_SAMPLE_AREA_SIZE, B_NO_LOCK,
|
||||||
@ -594,8 +594,15 @@ profile_all(const char* const* programArgs, int programArgCount)
|
|||||||
ThreadManager threadManager(-1); // TODO: We don't need a debugger port!
|
ThreadManager threadManager(-1); // TODO: We don't need a debugger port!
|
||||||
|
|
||||||
// start profiling
|
// start profiling
|
||||||
status_t error = _kern_system_profiler_start(area, gOptions.interval,
|
system_profiler_parameters profilerParameters;
|
||||||
gOptions.stack_depth);
|
profilerParameters.buffer_area = area;
|
||||||
|
profilerParameters.flags = B_SYSTEM_PROFILER_TEAM_EVENTS
|
||||||
|
| B_SYSTEM_PROFILER_THREAD_EVENTS | B_SYSTEM_PROFILER_IMAGE_EVENTS
|
||||||
|
| B_SYSTEM_PROFILER_SAMPLING_EVENTS;
|
||||||
|
profilerParameters.interval = gOptions.interval;
|
||||||
|
profilerParameters.stack_depth = gOptions.stack_depth;
|
||||||
|
|
||||||
|
status_t error = _kern_system_profiler_start(&profilerParameters);
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
fprintf(stderr, "%s: Failed to start profiling: %s\n", kCommandName,
|
fprintf(stderr, "%s: Failed to start profiling: %s\n", kCommandName,
|
||||||
strerror(error));
|
strerror(error));
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
#include <kimage.h>
|
#include <kimage.h>
|
||||||
|
#include <kscheduler.h>
|
||||||
#include <Notifications.h>
|
#include <Notifications.h>
|
||||||
#include <team.h>
|
#include <team.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
@ -35,11 +36,13 @@ static spinlock sProfilerLock = B_SPINLOCK_INITIALIZER;
|
|||||||
static SystemProfiler* sProfiler = NULL;
|
static SystemProfiler* sProfiler = NULL;
|
||||||
|
|
||||||
|
|
||||||
class SystemProfiler : public Referenceable, private NotificationListener {
|
class SystemProfiler : public Referenceable, private NotificationListener,
|
||||||
|
private SchedulerListener {
|
||||||
public:
|
public:
|
||||||
SystemProfiler(team_id team,
|
SystemProfiler(team_id team,
|
||||||
const area_info& userAreaInfo,
|
const area_info& userAreaInfo,
|
||||||
bigtime_t interval, int32 stackDepth);
|
const system_profiler_parameters&
|
||||||
|
parameters);
|
||||||
~SystemProfiler();
|
~SystemProfiler();
|
||||||
|
|
||||||
team_id Team() const { return fTeam; }
|
team_id Team() const { return fTeam; }
|
||||||
@ -51,6 +54,12 @@ private:
|
|||||||
virtual void EventOccured(NotificationService& service,
|
virtual void EventOccured(NotificationService& service,
|
||||||
const KMessage* event);
|
const KMessage* event);
|
||||||
|
|
||||||
|
virtual void ThreadEnqueuedInRunQueue(struct thread* thread);
|
||||||
|
virtual void ThreadRemovedFromRunQueue(
|
||||||
|
struct thread* thread);
|
||||||
|
virtual void ThreadScheduled(struct thread* oldThread,
|
||||||
|
struct thread* newThread);
|
||||||
|
|
||||||
bool _TeamAdded(struct team* team);
|
bool _TeamAdded(struct team* team);
|
||||||
bool _TeamRemoved(struct team* team);
|
bool _TeamRemoved(struct team* team);
|
||||||
bool _TeamExec(struct team* team);
|
bool _TeamExec(struct team* team);
|
||||||
@ -69,7 +78,7 @@ private:
|
|||||||
void* cookie);
|
void* cookie);
|
||||||
|
|
||||||
void* _AllocateBuffer(size_t size, int event, int cpu,
|
void* _AllocateBuffer(size_t size, int event, int cpu,
|
||||||
int count);
|
int count, bool threadsLocked = false);
|
||||||
|
|
||||||
static void _InitTimers(void* cookie, int cpu);
|
static void _InitTimers(void* cookie, int cpu);
|
||||||
static void _UninitTimers(void* cookie, int cpu);
|
static void _UninitTimers(void* cookie, int cpu);
|
||||||
@ -93,7 +102,8 @@ private:
|
|||||||
area_id fUserArea;
|
area_id fUserArea;
|
||||||
area_id fKernelArea;
|
area_id fKernelArea;
|
||||||
size_t fAreaSize;
|
size_t fAreaSize;
|
||||||
int32 fStackDepth;
|
uint32 fFlags;
|
||||||
|
uint32 fStackDepth;
|
||||||
bigtime_t fInterval;
|
bigtime_t fInterval;
|
||||||
system_profiler_buffer_header* fHeader;
|
system_profiler_buffer_header* fHeader;
|
||||||
uint8* fBufferBase;
|
uint8* fBufferBase;
|
||||||
@ -106,6 +116,7 @@ private:
|
|||||||
bool fThreadNotificationsEnabled;
|
bool fThreadNotificationsEnabled;
|
||||||
bool fImageNotificationsRequested;
|
bool fImageNotificationsRequested;
|
||||||
bool fImageNotificationsEnabled;
|
bool fImageNotificationsEnabled;
|
||||||
|
bool fSchedulerNotificationsRequested;
|
||||||
ConditionVariable fProfilerWaitCondition;
|
ConditionVariable fProfilerWaitCondition;
|
||||||
bool fProfilerWaiting;
|
bool fProfilerWaiting;
|
||||||
bool fProfilingActive;
|
bool fProfilingActive;
|
||||||
@ -114,14 +125,20 @@ private:
|
|||||||
|
|
||||||
|
|
||||||
SystemProfiler::SystemProfiler(team_id team, const area_info& userAreaInfo,
|
SystemProfiler::SystemProfiler(team_id team, const area_info& userAreaInfo,
|
||||||
bigtime_t interval, int32 stackDepth)
|
const system_profiler_parameters& parameters)
|
||||||
|
#if 0
|
||||||
|
// scheduling
|
||||||
|
size_t locking_lookup_size; // size of the lookup table used for
|
||||||
|
// caching the locking primitive infos
|
||||||
|
#endif
|
||||||
:
|
:
|
||||||
fTeam(team),
|
fTeam(team),
|
||||||
fUserArea(userAreaInfo.area),
|
fUserArea(userAreaInfo.area),
|
||||||
fKernelArea(-1),
|
fKernelArea(-1),
|
||||||
fAreaSize(userAreaInfo.size),
|
fAreaSize(userAreaInfo.size),
|
||||||
fStackDepth(stackDepth),
|
fFlags(parameters.flags),
|
||||||
fInterval(interval),
|
fStackDepth(parameters.stack_depth),
|
||||||
|
fInterval(parameters.interval),
|
||||||
fHeader(NULL),
|
fHeader(NULL),
|
||||||
fBufferBase(NULL),
|
fBufferBase(NULL),
|
||||||
fBufferCapacity(0),
|
fBufferCapacity(0),
|
||||||
@ -133,6 +150,7 @@ SystemProfiler::SystemProfiler(team_id team, const area_info& userAreaInfo,
|
|||||||
fThreadNotificationsEnabled(false),
|
fThreadNotificationsEnabled(false),
|
||||||
fImageNotificationsRequested(false),
|
fImageNotificationsRequested(false),
|
||||||
fImageNotificationsEnabled(false),
|
fImageNotificationsEnabled(false),
|
||||||
|
fSchedulerNotificationsRequested(false),
|
||||||
fProfilerWaiting(false)
|
fProfilerWaiting(false)
|
||||||
{
|
{
|
||||||
B_INITIALIZE_SPINLOCK(&fLock);
|
B_INITIALIZE_SPINLOCK(&fLock);
|
||||||
@ -152,8 +170,15 @@ SystemProfiler::~SystemProfiler()
|
|||||||
fProfilingActive = false;
|
fProfilingActive = false;
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
|
// stop scheduler listening
|
||||||
|
if (fSchedulerNotificationsRequested) {
|
||||||
|
InterruptsSpinLocker threadsLocker(gThreadSpinlock);
|
||||||
|
scheduler_remove_listener(this);
|
||||||
|
}
|
||||||
|
|
||||||
// deactivate the profiling timers on all CPUs
|
// deactivate the profiling timers on all CPUs
|
||||||
call_all_cpus(_UninitTimers, this);
|
if ((fFlags & B_SYSTEM_PROFILER_SAMPLING_EVENTS) != 0)
|
||||||
|
call_all_cpus(_UninitTimers, this);
|
||||||
|
|
||||||
// cancel notifications
|
// cancel notifications
|
||||||
NotificationManager& notificationManager
|
NotificationManager& notificationManager
|
||||||
@ -217,53 +242,73 @@ SystemProfiler::Init()
|
|||||||
// teams
|
// teams
|
||||||
NotificationManager& notificationManager
|
NotificationManager& notificationManager
|
||||||
= NotificationManager::Manager();
|
= NotificationManager::Manager();
|
||||||
error = notificationManager.AddListener("teams",
|
if ((fFlags & B_SYSTEM_PROFILER_TEAM_EVENTS) != 0) {
|
||||||
TEAM_ADDED | TEAM_REMOVED | TEAM_EXEC, *this);
|
error = notificationManager.AddListener("teams",
|
||||||
if (error != B_OK)
|
TEAM_ADDED | TEAM_REMOVED | TEAM_EXEC, *this);
|
||||||
return error;
|
if (error != B_OK)
|
||||||
fTeamNotificationsRequested = true;
|
return error;
|
||||||
|
fTeamNotificationsRequested = true;
|
||||||
|
}
|
||||||
|
|
||||||
// threads
|
// threads
|
||||||
error = notificationManager.AddListener("threads",
|
if ((fFlags & B_SYSTEM_PROFILER_THREAD_EVENTS) != 0) {
|
||||||
THREAD_ADDED | THREAD_REMOVED, *this);
|
error = notificationManager.AddListener("threads",
|
||||||
if (error != B_OK)
|
THREAD_ADDED | THREAD_REMOVED, *this);
|
||||||
return error;
|
if (error != B_OK)
|
||||||
fThreadNotificationsRequested = true;
|
return error;
|
||||||
|
fThreadNotificationsRequested = true;
|
||||||
|
}
|
||||||
|
|
||||||
// images
|
// images
|
||||||
error = notificationManager.AddListener("images",
|
if ((fFlags & B_SYSTEM_PROFILER_IMAGE_EVENTS) != 0) {
|
||||||
IMAGE_ADDED | IMAGE_REMOVED, *this);
|
error = notificationManager.AddListener("images",
|
||||||
if (error != B_OK)
|
IMAGE_ADDED | IMAGE_REMOVED, *this);
|
||||||
return error;
|
if (error != B_OK)
|
||||||
fImageNotificationsRequested = true;
|
return error;
|
||||||
|
fImageNotificationsRequested = true;
|
||||||
|
}
|
||||||
|
|
||||||
// We need to fill the buffer with the initial state of teams, threads,
|
// We need to fill the buffer with the initial state of teams, threads,
|
||||||
// and images.
|
// and images.
|
||||||
|
|
||||||
// teams
|
// teams
|
||||||
InterruptsSpinLocker teamsLocker(gTeamSpinlock);
|
if ((fFlags & B_SYSTEM_PROFILER_TEAM_EVENTS) != 0) {
|
||||||
if (team_iterate_through_teams(&_InitialTeamIterator, this) != NULL)
|
InterruptsSpinLocker teamsLocker(gTeamSpinlock);
|
||||||
return B_BUFFER_OVERFLOW;
|
if (team_iterate_through_teams(&_InitialTeamIterator, this) != NULL)
|
||||||
fTeamNotificationsEnabled = true;
|
return B_BUFFER_OVERFLOW;
|
||||||
teamsLocker.Unlock();
|
fTeamNotificationsEnabled = true;
|
||||||
|
teamsLocker.Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
// threads
|
// threads
|
||||||
InterruptsSpinLocker threadsLocker(gThreadSpinlock);
|
if ((fFlags & B_SYSTEM_PROFILER_THREAD_EVENTS) != 0) {
|
||||||
if (thread_iterate_through_threads(&_InitialThreadIterator, this)
|
InterruptsSpinLocker threadsLocker(gThreadSpinlock);
|
||||||
!= NULL) {
|
if (thread_iterate_through_threads(&_InitialThreadIterator, this)
|
||||||
return B_BUFFER_OVERFLOW;
|
!= NULL) {
|
||||||
|
return B_BUFFER_OVERFLOW;
|
||||||
|
}
|
||||||
|
fThreadNotificationsEnabled = true;
|
||||||
|
threadsLocker.Unlock();
|
||||||
}
|
}
|
||||||
fThreadNotificationsEnabled = true;
|
|
||||||
threadsLocker.Unlock();
|
|
||||||
|
|
||||||
// images
|
// images
|
||||||
if (image_iterate_through_images(&_InitialImageIterator, this) != NULL)
|
if ((fFlags & B_SYSTEM_PROFILER_IMAGE_EVENTS) != 0) {
|
||||||
return B_BUFFER_OVERFLOW;
|
if (image_iterate_through_images(&_InitialImageIterator, this) != NULL)
|
||||||
|
return B_BUFFER_OVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
fProfilingActive = true;
|
fProfilingActive = true;
|
||||||
|
|
||||||
|
// start scheduler listening
|
||||||
|
if ((fFlags & B_SYSTEM_PROFILER_SCHEDULING_EVENTS) != 0) {
|
||||||
|
InterruptsSpinLocker threadsLocker(gThreadSpinlock);
|
||||||
|
scheduler_add_listener(this);
|
||||||
|
fSchedulerNotificationsRequested = true;
|
||||||
|
}
|
||||||
|
|
||||||
// activate the profiling timers on all CPUs
|
// activate the profiling timers on all CPUs
|
||||||
call_all_cpus(_InitTimers, this);
|
if ((fFlags & B_SYSTEM_PROFILER_SAMPLING_EVENTS) != 0)
|
||||||
|
call_all_cpus(_InitTimers, this);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@ -399,6 +444,86 @@ SystemProfiler::EventOccured(NotificationService& service,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// B_SYSTEM_PROFILER_WAIT_OBJECT_INFO
|
||||||
|
struct system_profiler_wait_object_info {
|
||||||
|
uint32 type;
|
||||||
|
void* object;
|
||||||
|
void* referenced_object;
|
||||||
|
char name[1];
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
SystemProfiler::ThreadEnqueuedInRunQueue(struct thread* thread)
|
||||||
|
{
|
||||||
|
InterruptsSpinLocker locker(fLock);
|
||||||
|
|
||||||
|
system_profiler_thread_enqueued_in_run_queue* event
|
||||||
|
= (system_profiler_thread_enqueued_in_run_queue*)
|
||||||
|
_AllocateBuffer(
|
||||||
|
sizeof(system_profiler_thread_enqueued_in_run_queue),
|
||||||
|
B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE,
|
||||||
|
smp_get_current_cpu(), 0, true);
|
||||||
|
if (event == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
event->time = system_time();
|
||||||
|
event->thread = thread->id;
|
||||||
|
event->priority = thread->priority;
|
||||||
|
|
||||||
|
fHeader->size = fBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SystemProfiler::ThreadRemovedFromRunQueue(struct thread* thread)
|
||||||
|
{
|
||||||
|
InterruptsSpinLocker locker(fLock);
|
||||||
|
|
||||||
|
system_profiler_thread_removed_from_run_queue* event
|
||||||
|
= (system_profiler_thread_removed_from_run_queue*)
|
||||||
|
_AllocateBuffer(
|
||||||
|
sizeof(system_profiler_thread_removed_from_run_queue),
|
||||||
|
B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE,
|
||||||
|
smp_get_current_cpu(), 0, true);
|
||||||
|
if (event == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
event->time = system_time();
|
||||||
|
event->thread = thread->id;
|
||||||
|
|
||||||
|
fHeader->size = fBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SystemProfiler::ThreadScheduled(struct thread* oldThread,
|
||||||
|
struct thread* newThread)
|
||||||
|
{
|
||||||
|
InterruptsSpinLocker locker(fLock);
|
||||||
|
|
||||||
|
// TODO: Deal with the wait object!
|
||||||
|
|
||||||
|
system_profiler_thread_scheduled* event
|
||||||
|
= (system_profiler_thread_scheduled*)
|
||||||
|
_AllocateBuffer(sizeof(system_profiler_thread_scheduled),
|
||||||
|
B_SYSTEM_PROFILER_THREAD_SCHEDULED, smp_get_current_cpu(), 0,
|
||||||
|
true);
|
||||||
|
if (event == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
event->time = system_time();
|
||||||
|
event->thread = newThread->id;
|
||||||
|
event->previous_thread = oldThread->id;
|
||||||
|
event->previous_thread_state = oldThread->state;
|
||||||
|
event->previous_thread_wait_object_type = oldThread->wait.type;
|
||||||
|
event->previous_thread_wait_object = (addr_t)oldThread->wait.object;
|
||||||
|
|
||||||
|
fHeader->size = fBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SystemProfiler::_TeamAdded(struct team* team)
|
SystemProfiler::_TeamAdded(struct team* team)
|
||||||
{
|
{
|
||||||
@ -573,7 +698,8 @@ SystemProfiler::_InitialImageIterator(struct image* image, void* cookie)
|
|||||||
|
|
||||||
|
|
||||||
void*
|
void*
|
||||||
SystemProfiler::_AllocateBuffer(size_t size, int event, int cpu, int count)
|
SystemProfiler::_AllocateBuffer(size_t size, int event, int cpu, int count,
|
||||||
|
bool threadsLocked)
|
||||||
{
|
{
|
||||||
size += sizeof(system_profiler_event_header);
|
size += sizeof(system_profiler_event_header);
|
||||||
|
|
||||||
@ -584,7 +710,7 @@ SystemProfiler::_AllocateBuffer(size_t size, int event, int cpu, int count)
|
|||||||
// not wrapped yet, but needed
|
// not wrapped yet, but needed
|
||||||
system_profiler_event_header* header
|
system_profiler_event_header* header
|
||||||
= (system_profiler_event_header*)(fBufferBase + end);
|
= (system_profiler_event_header*)(fBufferBase + end);
|
||||||
header->event = B_SYSTEM_PROFILER_SAMPLES_END;
|
header->event = B_SYSTEM_PROFILER_BUFFER_END;
|
||||||
fBufferSize = fBufferCapacity - fBufferStart;
|
fBufferSize = fBufferCapacity - fBufferStart;
|
||||||
end = 0;
|
end = 0;
|
||||||
} else
|
} else
|
||||||
@ -605,7 +731,7 @@ SystemProfiler::_AllocateBuffer(size_t size, int event, int cpu, int count)
|
|||||||
// If the buffer is full enough notify the profiler.
|
// If the buffer is full enough notify the profiler.
|
||||||
if (fProfilerWaiting && fBufferSize > fBufferCapacity / 2) {
|
if (fProfilerWaiting && fBufferSize > fBufferCapacity / 2) {
|
||||||
fProfilerWaiting = false;
|
fProfilerWaiting = false;
|
||||||
fProfilerWaitCondition.NotifyOne();
|
fProfilerWaitCondition.NotifyOne(threadsLocked);
|
||||||
}
|
}
|
||||||
|
|
||||||
return header + 1;
|
return header + 1;
|
||||||
@ -688,25 +814,32 @@ SystemProfiler::_ProfilingEvent(struct timer* timer)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
_user_system_profiler_start(area_id bufferArea, bigtime_t interval,
|
_user_system_profiler_start(struct system_profiler_parameters* userParameters)
|
||||||
int32 stackDepth)
|
|
||||||
{
|
{
|
||||||
|
// copy params to the kernel
|
||||||
|
struct system_profiler_parameters parameters;
|
||||||
|
if (userParameters == NULL
|
||||||
|
|| user_memcpy(¶meters, userParameters, sizeof(parameters))
|
||||||
|
!= B_OK) {
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
// check the parameters
|
// check the parameters
|
||||||
team_id team = thread_get_current_thread()->team->id;
|
team_id team = thread_get_current_thread()->team->id;
|
||||||
|
|
||||||
area_info areaInfo;
|
area_info areaInfo;
|
||||||
status_t error = get_area_info(bufferArea, &areaInfo);
|
status_t error = get_area_info(parameters.buffer_area, &areaInfo);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if (areaInfo.team != team || stackDepth < 1)
|
if (areaInfo.team != team || parameters.stack_depth < 1)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
if (interval < B_DEBUG_MIN_PROFILE_INTERVAL)
|
if (parameters.interval < B_DEBUG_MIN_PROFILE_INTERVAL)
|
||||||
interval = B_DEBUG_MIN_PROFILE_INTERVAL;
|
parameters.interval = B_DEBUG_MIN_PROFILE_INTERVAL;
|
||||||
|
|
||||||
if (stackDepth > B_DEBUG_STACK_TRACE_DEPTH)
|
if (parameters.stack_depth > B_DEBUG_STACK_TRACE_DEPTH)
|
||||||
stackDepth = B_DEBUG_STACK_TRACE_DEPTH;
|
parameters.stack_depth = B_DEBUG_STACK_TRACE_DEPTH;
|
||||||
|
|
||||||
// quick check to see whether we do already have a profiler installed
|
// quick check to see whether we do already have a profiler installed
|
||||||
InterruptsSpinLocker locker(sProfilerLock);
|
InterruptsSpinLocker locker(sProfilerLock);
|
||||||
@ -716,7 +849,7 @@ _user_system_profiler_start(area_id bufferArea, bigtime_t interval,
|
|||||||
|
|
||||||
// initialize the profiler
|
// initialize the profiler
|
||||||
SystemProfiler* profiler = new(std::nothrow) SystemProfiler(team, areaInfo,
|
SystemProfiler* profiler = new(std::nothrow) SystemProfiler(team, areaInfo,
|
||||||
interval, stackDepth);
|
parameters);
|
||||||
if (profiler == NULL)
|
if (profiler == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
ObjectDeleter<SystemProfiler> profilerDeleter(profiler);
|
ObjectDeleter<SystemProfiler> profilerDeleter(profiler);
|
||||||
|
Loading…
Reference in New Issue
Block a user