* Work-in-progress on a kernel profile service that can be evaluated from
userland afterwards. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31621 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
f594f19bfb
commit
5fbad060b3
@ -15,11 +15,16 @@ struct system_profiler_parameters;
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
status_t start_system_profiler(size_t areaSize, uint32 flags);
|
||||
void stop_system_profiler();
|
||||
|
||||
status_t _user_system_profiler_start(
|
||||
struct system_profiler_parameters* parameters);
|
||||
status_t _user_system_profiler_next_buffer(size_t bytesRead,
|
||||
uint64* _droppedEvents);
|
||||
status_t _user_system_profiler_stop();
|
||||
status_t _user_system_profiler_recorded(
|
||||
struct system_profiler_parameters* parameters);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
@ -56,6 +56,8 @@ void forbid_page_faults(void);
|
||||
area_id create_area_etc(team_id team, const char *name, void **address,
|
||||
uint32 addressSpec, uint32 size, uint32 lock, uint32 protection,
|
||||
uint32 flags);
|
||||
area_id transfer_area(area_id id, void** _address, uint32 addressSpec,
|
||||
team_id target, bool kernel);
|
||||
|
||||
status_t vm_unreserve_address_range(team_id team, void *address, addr_t size);
|
||||
status_t vm_reserve_address_range(team_id team, void **_address,
|
||||
|
@ -436,6 +436,8 @@ extern status_t _kern_system_profiler_start(
|
||||
extern status_t _kern_system_profiler_next_buffer(size_t bytesRead,
|
||||
uint64* _droppedEvents);
|
||||
extern status_t _kern_system_profiler_stop();
|
||||
extern status_t _kern_system_profiler_recorded(
|
||||
struct system_profiler_parameters* parameters);
|
||||
|
||||
/* atomic_* ops (needed for CPUs that don't support them directly) */
|
||||
#ifdef ATOMIC_FUNCS_ARE_SYSCALLS
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <team.h>
|
||||
#include <thread.h>
|
||||
#include <user_debugger.h>
|
||||
#include <vm.h>
|
||||
|
||||
#include <arch/debug.h>
|
||||
|
||||
@ -42,6 +43,7 @@ class SystemProfiler;
|
||||
|
||||
static spinlock sProfilerLock = B_SPINLOCK_INITIALIZER;
|
||||
static SystemProfiler* sProfiler = NULL;
|
||||
static struct system_profiler_parameters* sRecordedParameters = NULL;
|
||||
|
||||
|
||||
class SystemProfiler : public Referenceable, private NotificationListener,
|
||||
@ -1135,6 +1137,103 @@ SystemProfiler::_ProfilingEvent(struct timer* timer)
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - private kernel API
|
||||
|
||||
|
||||
status_t
|
||||
start_system_profiler(size_t areaSize, uint32 flags)
|
||||
{
|
||||
struct ParameterDeleter {
|
||||
ParameterDeleter(area_id area)
|
||||
:
|
||||
fArea(area),
|
||||
fDetached(false)
|
||||
{
|
||||
}
|
||||
|
||||
~ParameterDeleter()
|
||||
{
|
||||
if (!fDetached) {
|
||||
delete_area(fArea);
|
||||
delete sRecordedParameters;
|
||||
sRecordedParameters = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Detach()
|
||||
{
|
||||
fDetached = true;
|
||||
}
|
||||
|
||||
private:
|
||||
area_id fArea;
|
||||
bool fDetached;
|
||||
};
|
||||
|
||||
void* address;
|
||||
area_id area = create_area("kernel profile data", &address,
|
||||
B_ANY_KERNEL_ADDRESS, areaSize, B_FULL_LOCK,
|
||||
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||
if (area < 0)
|
||||
return area;
|
||||
|
||||
ParameterDeleter parameterDeleter(area);
|
||||
|
||||
sRecordedParameters = new(std::nothrow) system_profiler_parameters;
|
||||
if (sRecordedParameters == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
sRecordedParameters->buffer_area = area;
|
||||
sRecordedParameters->flags
|
||||
= flags | B_SYSTEM_PROFILER_SAMPLING_EVENTS;
|
||||
sRecordedParameters->locking_lookup_size = 4096;
|
||||
sRecordedParameters->interval = 1000;
|
||||
sRecordedParameters->stack_depth = 5;
|
||||
|
||||
area_info areaInfo;
|
||||
get_area_info(area, &areaInfo);
|
||||
|
||||
// initialize the profiler
|
||||
SystemProfiler* profiler = new(std::nothrow) SystemProfiler(B_SYSTEM_TEAM,
|
||||
areaInfo, *sRecordedParameters);
|
||||
if (profiler == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
ObjectDeleter<SystemProfiler> profilerDeleter(profiler);
|
||||
|
||||
status_t error = profiler->Init();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// set the new profiler
|
||||
InterruptsSpinLocker locker(sProfilerLock);
|
||||
if (sProfiler != NULL)
|
||||
return B_BUSY;
|
||||
|
||||
parameterDeleter.Detach();
|
||||
profilerDeleter.Detach();
|
||||
sProfiler = profiler;
|
||||
locker.Unlock();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
stop_system_profiler()
|
||||
{
|
||||
InterruptsSpinLocker locker(sProfilerLock);
|
||||
if (sProfiler == NULL)
|
||||
return;
|
||||
|
||||
SystemProfiler* profiler = sProfiler;
|
||||
sProfiler = NULL;
|
||||
locker.Unlock();
|
||||
|
||||
profiler->RemoveReference();
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - syscalls
|
||||
|
||||
|
||||
@ -1245,3 +1344,33 @@ _user_system_profiler_stop()
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
_user_system_profiler_recorded(struct system_profiler_parameters* userParameters)
|
||||
{
|
||||
if (userParameters == NULL || !IS_USER_ADDRESS(userParameters))
|
||||
return B_BAD_ADDRESS;
|
||||
if (sRecordedParameters == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
// Transfer the area to the userland process
|
||||
|
||||
void* address;
|
||||
area_id newArea = transfer_area(sRecordedParameters->buffer_area, &address,
|
||||
B_ANY_ADDRESS, team_get_current_team_id(), true);
|
||||
if (newArea < 0)
|
||||
return newArea;
|
||||
|
||||
sRecordedParameters->buffer_area = newArea;
|
||||
|
||||
status_t status = user_memcpy(userParameters, sRecordedParameters,
|
||||
sizeof(system_profiler_parameters));
|
||||
if (status != B_OK)
|
||||
delete_area(newArea);
|
||||
|
||||
delete sRecordedParameters;
|
||||
sRecordedParameters = NULL;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -2621,7 +2621,7 @@ vm_delete_area(team_id team, area_id id, bool kernel)
|
||||
AddressSpaceWriteLocker locker;
|
||||
vm_area* area;
|
||||
status_t status = locker.SetFromArea(team, id, area);
|
||||
if (status < B_OK)
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
if (!kernel && (area->protection & B_KERNEL_AREA) != 0)
|
||||
@ -5817,25 +5817,23 @@ resize_area(area_id areaID, size_t newSize)
|
||||
|
||||
/*! Transfers the specified area to a new team. The caller must be the owner
|
||||
of the area (not yet enforced but probably should be).
|
||||
This function is currently not exported to the kernel namespace, but is
|
||||
only accessible using the _kern_transfer_area() syscall.
|
||||
*/
|
||||
static area_id
|
||||
area_id
|
||||
transfer_area(area_id id, void** _address, uint32 addressSpec, team_id target,
|
||||
bool kernel)
|
||||
{
|
||||
area_info info;
|
||||
status_t status = get_area_info(id, &info);
|
||||
if (status < B_OK)
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
area_id clonedArea = vm_clone_area(target, info.name, _address,
|
||||
addressSpec, info.protection, REGION_NO_PRIVATE_MAP, id, kernel);
|
||||
if (clonedArea < B_OK)
|
||||
if (clonedArea < 0)
|
||||
return clonedArea;
|
||||
|
||||
status = vm_delete_area(info.team, id, kernel);
|
||||
if (status < B_OK) {
|
||||
if (status != B_OK) {
|
||||
vm_delete_area(target, clonedArea, kernel);
|
||||
return status;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user