* 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:
Axel Dörfler 2009-07-17 16:21:06 +00:00
parent f594f19bfb
commit 5fbad060b3
5 changed files with 143 additions and 7 deletions

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}