* Although it takes a bit of memory, the Model also stores an array with
pointers to all events now. This allows for backward iteration. * Model::ThreadWaitObjectGroup: Added a few convenience getters. * Added functions thread_state_name() and wait_object_type_name() to translate a ThreadState respectively a wait object type into a readable string. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34588 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -13,6 +13,50 @@
|
|||||||
|
|
||||||
#include <AutoDeleter.h>
|
#include <AutoDeleter.h>
|
||||||
|
|
||||||
|
#include <thread_defs.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static const char* const kThreadStateNames[] = {
|
||||||
|
"running",
|
||||||
|
"still running",
|
||||||
|
"preempted",
|
||||||
|
"ready",
|
||||||
|
"waiting",
|
||||||
|
"unknown"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
thread_state_name(ThreadState state)
|
||||||
|
{
|
||||||
|
return kThreadStateNames[state];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
wait_object_type_name(uint32 type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case THREAD_BLOCK_TYPE_SEMAPHORE:
|
||||||
|
return "semaphore";
|
||||||
|
case THREAD_BLOCK_TYPE_CONDITION_VARIABLE:
|
||||||
|
return "condition";
|
||||||
|
case THREAD_BLOCK_TYPE_MUTEX:
|
||||||
|
return "mutex";
|
||||||
|
case THREAD_BLOCK_TYPE_RW_LOCK:
|
||||||
|
return "rw lock";
|
||||||
|
case THREAD_BLOCK_TYPE_OTHER:
|
||||||
|
return "other";
|
||||||
|
case THREAD_BLOCK_TYPE_SNOOZE:
|
||||||
|
return "snooze";
|
||||||
|
case THREAD_BLOCK_TYPE_SIGNAL:
|
||||||
|
return "signal";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - CPU
|
// #pragma mark - CPU
|
||||||
|
|
||||||
@@ -457,11 +501,14 @@ Model::CompactSchedulingState::Delete()
|
|||||||
// #pragma mark - Model
|
// #pragma mark - Model
|
||||||
|
|
||||||
|
|
||||||
Model::Model(const char* dataSourceName, void* eventData, size_t eventDataSize)
|
Model::Model(const char* dataSourceName, void* eventData, size_t eventDataSize,
|
||||||
|
system_profiler_event_header** events, size_t eventCount)
|
||||||
:
|
:
|
||||||
fDataSourceName(dataSourceName),
|
fDataSourceName(dataSourceName),
|
||||||
fEventData(eventData),
|
fEventData(eventData),
|
||||||
|
fEvents(events),
|
||||||
fEventDataSize(eventDataSize),
|
fEventDataSize(eventDataSize),
|
||||||
|
fEventCount(eventCount),
|
||||||
fCPUCount(1),
|
fCPUCount(1),
|
||||||
fBaseTime(0),
|
fBaseTime(0),
|
||||||
fLastEventTime(0),
|
fLastEventTime(0),
|
||||||
@@ -486,6 +533,50 @@ Model::~Model()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t
|
||||||
|
Model::ClosestEventIndex(nanotime_t eventTime) const
|
||||||
|
{
|
||||||
|
// The events themselves are unmodified and use an absolute time.
|
||||||
|
eventTime += fBaseTime;
|
||||||
|
|
||||||
|
// Binary search the event. Since not all events have a timestamp, we have
|
||||||
|
// to do a bit of iteration, too.
|
||||||
|
size_t lower = 0;
|
||||||
|
size_t upper = CountEvents();
|
||||||
|
while (lower < upper) {
|
||||||
|
size_t mid = (lower + upper) / 2;
|
||||||
|
while (mid < upper) {
|
||||||
|
system_profiler_event_header* header = fEvents[mid];
|
||||||
|
switch (header->event) {
|
||||||
|
case B_SYSTEM_PROFILER_THREAD_SCHEDULED:
|
||||||
|
case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE:
|
||||||
|
case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mid++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mid == upper) {
|
||||||
|
lower = mid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
system_profiler_thread_scheduling_event* event
|
||||||
|
= (system_profiler_thread_scheduling_event*)(fEvents[mid] + 1);
|
||||||
|
if (event->time < eventTime)
|
||||||
|
lower = mid + 1;
|
||||||
|
else
|
||||||
|
upper = mid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lower;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Model::LoadingFinished()
|
Model::LoadingFinished()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ enum ThreadState {
|
|||||||
UNKNOWN
|
UNKNOWN
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char* thread_state_name(ThreadState state);
|
||||||
|
const char* wait_object_type_name(uint32 type);
|
||||||
|
|
||||||
|
|
||||||
class Model : public Referenceable {
|
class Model : public Referenceable {
|
||||||
public:
|
public:
|
||||||
@@ -50,12 +53,20 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Model(const char* dataSourceName,
|
Model(const char* dataSourceName,
|
||||||
void* eventData, size_t eventDataSize);
|
void* eventData, size_t eventDataSize,
|
||||||
|
system_profiler_event_header** events,
|
||||||
|
size_t eventCount);
|
||||||
~Model();
|
~Model();
|
||||||
|
|
||||||
inline const char* DataSourceName() const;
|
inline const char* DataSourceName() const;
|
||||||
inline void* EventData() const;
|
inline void* EventData() const;
|
||||||
inline size_t EventDataSize() const;
|
inline size_t EventDataSize() const;
|
||||||
|
inline system_profiler_event_header** Events() const;
|
||||||
|
inline size_t CountEvents() const;
|
||||||
|
size_t ClosestEventIndex(nanotime_t eventTime) const;
|
||||||
|
// finds the greatest event with event
|
||||||
|
// time >= eventTime; may return
|
||||||
|
// CountEvents()
|
||||||
|
|
||||||
void LoadingFinished();
|
void LoadingFinished();
|
||||||
|
|
||||||
@@ -119,13 +130,16 @@ private:
|
|||||||
typedef BObjectList<CompactSchedulingState> SchedulingStateList;
|
typedef BObjectList<CompactSchedulingState> SchedulingStateList;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int _CompareEventTimeSchedulingState(const nanotime_t* time,
|
static int _CompareEventTimeSchedulingState(
|
||||||
|
const nanotime_t* time,
|
||||||
const CompactSchedulingState* state);
|
const CompactSchedulingState* state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BString fDataSourceName;
|
BString fDataSourceName;
|
||||||
void* fEventData;
|
void* fEventData;
|
||||||
|
system_profiler_event_header** fEvents;
|
||||||
size_t fEventDataSize;
|
size_t fEventDataSize;
|
||||||
|
size_t fEventCount;
|
||||||
int32 fCPUCount;
|
int32 fCPUCount;
|
||||||
nanotime_t fBaseTime;
|
nanotime_t fBaseTime;
|
||||||
nanotime_t fLastEventTime;
|
nanotime_t fLastEventTime;
|
||||||
@@ -262,6 +276,10 @@ public:
|
|||||||
ThreadWaitObject* threadWaitObject);
|
ThreadWaitObject* threadWaitObject);
|
||||||
~ThreadWaitObjectGroup();
|
~ThreadWaitObjectGroup();
|
||||||
|
|
||||||
|
inline uint32 Type() const;
|
||||||
|
inline addr_t Object() const;
|
||||||
|
inline const char* Name() const;
|
||||||
|
|
||||||
inline ThreadWaitObject* MostRecentThreadWaitObject() const;
|
inline ThreadWaitObject* MostRecentThreadWaitObject() const;
|
||||||
inline WaitObject* MostRecentWaitObject() const;
|
inline WaitObject* MostRecentWaitObject() const;
|
||||||
|
|
||||||
@@ -529,6 +547,20 @@ Model::EventDataSize() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
system_profiler_event_header**
|
||||||
|
Model::Events() const
|
||||||
|
{
|
||||||
|
return fEvents;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t
|
||||||
|
Model::CountEvents() const
|
||||||
|
{
|
||||||
|
return fEventCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
nanotime_t
|
nanotime_t
|
||||||
Model::BaseTime() const
|
Model::BaseTime() const
|
||||||
{
|
{
|
||||||
@@ -769,6 +801,27 @@ Model::ThreadWaitObject::TotalWaitTime() const
|
|||||||
// #pragma mark - ThreadWaitObjectGroup
|
// #pragma mark - ThreadWaitObjectGroup
|
||||||
|
|
||||||
|
|
||||||
|
uint32
|
||||||
|
Model::ThreadWaitObjectGroup::Type() const
|
||||||
|
{
|
||||||
|
return MostRecentThreadWaitObject()->Type();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
addr_t
|
||||||
|
Model::ThreadWaitObjectGroup::Object() const
|
||||||
|
{
|
||||||
|
return MostRecentThreadWaitObject()->Object();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
Model::ThreadWaitObjectGroup::Name() const
|
||||||
|
{
|
||||||
|
return MostRecentThreadWaitObject()->Name();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Model::ThreadWaitObject*
|
Model::ThreadWaitObject*
|
||||||
Model::ThreadWaitObjectGroup::MostRecentThreadWaitObject() const
|
Model::ThreadWaitObjectGroup::MostRecentThreadWaitObject() const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -160,6 +160,16 @@ ModelLoader::_Load()
|
|||||||
status_t error = _ReadDebugEvents(&eventData, &eventDataSize);
|
status_t error = _ReadDebugEvents(&eventData, &eventDataSize);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
MemoryDeleter eventDataDeleter(eventData);
|
||||||
|
|
||||||
|
// create a debug event array
|
||||||
|
system_profiler_event_header** events;
|
||||||
|
size_t eventCount;
|
||||||
|
error = _CreateDebugEventArray(eventData, eventDataSize, events,
|
||||||
|
eventCount);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
ArrayDeleter<system_profiler_event_header*> eventsDeleter(events);
|
||||||
|
|
||||||
// get the data source name
|
// get the data source name
|
||||||
BString dataSourceName;
|
BString dataSourceName;
|
||||||
@@ -167,19 +177,15 @@ ModelLoader::_Load()
|
|||||||
|
|
||||||
// create a model
|
// create a model
|
||||||
fModel = new(std::nothrow) Model(dataSourceName.String(), eventData,
|
fModel = new(std::nothrow) Model(dataSourceName.String(), eventData,
|
||||||
eventDataSize);
|
eventDataSize, events, eventCount);
|
||||||
if (fModel == NULL) {
|
if (fModel == NULL)
|
||||||
free(eventData);
|
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
}
|
eventDataDeleter.Detach();
|
||||||
|
eventsDeleter.Detach();
|
||||||
|
|
||||||
// create a debug input stream
|
// create a debug input stream
|
||||||
BDebugEventInputStream* input = new(std::nothrow) BDebugEventInputStream;
|
BDebugEventInputStream input;
|
||||||
if (input == NULL)
|
error = input.SetTo(eventData, eventDataSize, false);
|
||||||
return B_NO_MEMORY;
|
|
||||||
ObjectDeleter<BDebugEventInputStream> inputDeleter(input);
|
|
||||||
|
|
||||||
error = input->SetTo(eventData, eventDataSize, false);
|
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
@@ -201,7 +207,7 @@ ModelLoader::_Load()
|
|||||||
uint32 cpu;
|
uint32 cpu;
|
||||||
const void* buffer;
|
const void* buffer;
|
||||||
off_t offset;
|
off_t offset;
|
||||||
ssize_t bufferSize = input->ReadNextEvent(&event, &cpu, &buffer,
|
ssize_t bufferSize = input.ReadNextEvent(&event, &cpu, &buffer,
|
||||||
&offset);
|
&offset);
|
||||||
if (bufferSize < 0)
|
if (bufferSize < 0)
|
||||||
return bufferSize;
|
return bufferSize;
|
||||||
@@ -320,6 +326,65 @@ ModelLoader::_ReadDebugEvents(void** _eventData, size_t* _size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ModelLoader::_CreateDebugEventArray(void* eventData, size_t eventDataSize,
|
||||||
|
system_profiler_event_header**& _events, size_t& _eventCount)
|
||||||
|
{
|
||||||
|
// count the events
|
||||||
|
BDebugEventInputStream input;
|
||||||
|
status_t error = input.SetTo(eventData, eventDataSize, false);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
size_t eventCount = 0;
|
||||||
|
while (true) {
|
||||||
|
// get next event
|
||||||
|
uint32 event;
|
||||||
|
uint32 cpu;
|
||||||
|
const void* buffer;
|
||||||
|
ssize_t bufferSize = input.ReadNextEvent(&event, &cpu, &buffer, NULL);
|
||||||
|
if (bufferSize < 0)
|
||||||
|
return bufferSize;
|
||||||
|
if (buffer == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
eventCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the array
|
||||||
|
system_profiler_event_header** events = new(std::nothrow)
|
||||||
|
system_profiler_event_header*[eventCount];
|
||||||
|
if (events == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
// populate the array
|
||||||
|
error = input.SetTo(eventData, eventDataSize, false);
|
||||||
|
if (error != B_OK) {
|
||||||
|
delete[] events;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t eventIndex = 0;
|
||||||
|
while (true) {
|
||||||
|
// get next event
|
||||||
|
uint32 event;
|
||||||
|
uint32 cpu;
|
||||||
|
const void* buffer;
|
||||||
|
off_t offset;
|
||||||
|
input.ReadNextEvent(&event, &cpu, &buffer, &offset);
|
||||||
|
if (buffer == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
events[eventIndex++]
|
||||||
|
= (system_profiler_event_header*)((uint8*)eventData + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
_events = events;
|
||||||
|
_eventCount = eventCount;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
ModelLoader::_ProcessEvent(uint32 event, uint32 cpu, const void* buffer,
|
ModelLoader::_ProcessEvent(uint32 event, uint32 cpu, const void* buffer,
|
||||||
size_t size)
|
size_t size)
|
||||||
|
|||||||
@@ -46,6 +46,10 @@ private:
|
|||||||
status_t _Load();
|
status_t _Load();
|
||||||
status_t _ReadDebugEvents(void** _eventData,
|
status_t _ReadDebugEvents(void** _eventData,
|
||||||
size_t* _size);
|
size_t* _size);
|
||||||
|
status_t _CreateDebugEventArray(void* eventData,
|
||||||
|
size_t eventDataSize,
|
||||||
|
system_profiler_event_header**& _events,
|
||||||
|
size_t& _eventCount);
|
||||||
status_t _ProcessEvent(uint32 event, uint32 cpu,
|
status_t _ProcessEvent(uint32 event, uint32 cpu,
|
||||||
const void* buffer, size_t size);
|
const void* buffer, size_t size);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user