diff --git a/src/apps/debuganalyzer/MainWindow.cpp b/src/apps/debuganalyzer/MainWindow.cpp index 4bcbed1f97..b01a1b63ed 100644 --- a/src/apps/debuganalyzer/MainWindow.cpp +++ b/src/apps/debuganalyzer/MainWindow.cpp @@ -25,6 +25,7 @@ MainWindow::MainWindow(DataSource* dataSource) BWindow(BRect(50, 50, 599, 499), "DebugAnalyzer", B_DOCUMENT_WINDOW, B_ASYNCHRONOUS_CONTROLS), fMainTabView(NULL), + fThreadsPage(new ThreadsPage), fModel(NULL), fModelLoader(NULL) { @@ -117,4 +118,6 @@ MainWindow::_SetModel(Model* model) { delete fModel; fModel = model; + + fThreadsPage->SetModel(fModel); } diff --git a/src/apps/debuganalyzer/MainWindow.h b/src/apps/debuganalyzer/MainWindow.h index fc9ec8b645..1c7ace903f 100644 --- a/src/apps/debuganalyzer/MainWindow.h +++ b/src/apps/debuganalyzer/MainWindow.h @@ -12,6 +12,7 @@ class BTabView; class DataSource; class ModelLoader; class Model; +class ThreadsPage; class MainWindow : public BWindow { @@ -30,6 +31,7 @@ private: private: BTabView* fMainTabView; + ThreadsPage* fThreadsPage; Model* fModel; ModelLoader* fModelLoader; }; diff --git a/src/apps/debuganalyzer/Model.cpp b/src/apps/debuganalyzer/Model.cpp index 6e3d3251b0..a7e009d83e 100644 --- a/src/apps/debuganalyzer/Model.cpp +++ b/src/apps/debuganalyzer/Model.cpp @@ -5,12 +5,174 @@ #include "Model.h" +#include -Model::Model() +#include +#include + +#include + + +// #pragma mark - Team + + +Model::Team::Team(const system_profiler_team_added* event, bigtime_t time) + : + fCreationEvent(event), + fCreationTime(time), + fDeletionTime(-1), + fThreads(10) +{ +} + + +Model::Team::~Team() +{ +} + + +bool +Model::Team::AddThread(Thread* thread) +{ + return fThreads.BinaryInsert(thread, &Thread::CompareByCreationTimeID); +} + + +// #pragma mark - Thread + + +Model::Thread::Thread(Team* team, const system_profiler_thread_added* event, + bigtime_t time) + : + fTeam(team), + fCreationEvent(event), + fCreationTime(time), + fDeletionTime(-1) +{ +} + + +Model::Thread::~Thread() +{ +} + + +// #pragma mark - Model + + +Model::Model(void* eventData, size_t eventDataSize) + : + fEventData(eventData), + fEventDataSize(eventDataSize), + fTeams(20, true), + fThreads(20, true) { } Model::~Model() { + free(fEventData); +} + + +int32 +Model::CountTeams() const +{ + return fTeams.CountItems(); +} + + +Model::Team* +Model::TeamAt(int32 index) const +{ + return fTeams.ItemAt(index); +} + + +Model::Team* +Model::TeamByID(team_id id) const +{ + return fTeams.BinarySearchByKey(id, &Team::CompareWithID); +} + + +Model::Team* +Model::AddTeam(const system_profiler_team_added* event, bigtime_t time) +{ + Team* team = TeamByID(event->team); + if (team != NULL) { + fprintf(stderr, "Duplicate team: %ld\n", event->team); + // TODO: User feedback! + return team; + } + + team = new(std::nothrow) Team(event, time); + if (team == NULL) + return NULL; + + if (!fTeams.BinaryInsert(team, &Team::CompareByID)) { + delete team; + return NULL; + } + + return team; +} + + +int32 +Model::CountThreads() const +{ + return fThreads.CountItems(); +} + + +Model::Thread* +Model::ThreadAt(int32 index) const +{ + return fThreads.ItemAt(index); +} + + +Model::Thread* +Model::ThreadByID(thread_id id) const +{ + return fThreads.BinarySearchByKey(id, &Thread::CompareWithID); +} + + +Model::Thread* +Model::AddThread(const system_profiler_thread_added* event, bigtime_t time) +{ + // check whether we do already know the thread + Thread* thread = ThreadByID(event->thread); + if (thread != NULL) { + fprintf(stderr, "Duplicate thread: %ld\n", event->thread); + // TODO: User feedback! + return thread; + } + + // get its team + Team* team = TeamByID(event->team); + if (team == NULL) { + fprintf(stderr, "No team for thread: %ld\n", event->thread); + return NULL; + } + + // create the thread and add it + thread = new(std::nothrow) Thread(team, event, time); + if (thread == NULL) + return NULL; + ObjectDeleter threadDeleter(thread); + + if (!fThreads.BinaryInsert(thread, &Thread::CompareByID)) + return NULL; + + if (!team->AddThread(thread)) { + fThreads.RemoveItem(thread); + return NULL; + } + + threadDeleter.Detach(); + return thread; } diff --git a/src/apps/debuganalyzer/Model.h b/src/apps/debuganalyzer/Model.h index f23cdb6078..45d85ad476 100644 --- a/src/apps/debuganalyzer/Model.h +++ b/src/apps/debuganalyzer/Model.h @@ -5,15 +5,185 @@ #ifndef MODEL_H #define MODEL_H +#include +#include + +#include + class Model { public: - Model(); + struct creation_time_id; + class Team; + class Thread; + +public: + Model(void* eventData, size_t eventDataSize); ~Model(); + int32 CountTeams() const; + Team* TeamAt(int32 index) const; + Team* TeamByID(team_id id) const; + Team* AddTeam( + const system_profiler_team_added* event, + bigtime_t time); + + int32 CountThreads() const; + Thread* ThreadAt(int32 index) const; + Thread* ThreadByID(thread_id id) const; + Thread* AddThread( + const system_profiler_thread_added* event, + bigtime_t time); + private: + typedef BObjectList TeamList; + typedef BObjectList ThreadList; + +private: + void* fEventData; + size_t fEventDataSize; + TeamList fTeams; // sorted by ID + ThreadList fThreads; // sorted by ID }; +struct Model::creation_time_id { + bigtime_t time; + thread_id id; +}; + + +class Model::Team { +public: + Team(const system_profiler_team_added* event, + bigtime_t time); + ~Team(); + + inline team_id ID() const; + + bool AddThread(Thread* thread); + + inline void SetDeletionTime(bigtime_t time); + + static inline int CompareByID(const Team* a, const Team* b); + static inline int CompareWithID(const team_id* id, + const Team* team); + +private: + typedef BObjectList ThreadList; + +private: + const system_profiler_team_added* fCreationEvent; + bigtime_t fCreationTime; + bigtime_t fDeletionTime; + ThreadList fThreads; // sorted by creation time, ID +}; + + +class Model::Thread { +public: + Thread(Team* team, + const system_profiler_thread_added* event, + bigtime_t time); + ~Thread(); + + inline thread_id ID() const; + + inline void SetDeletionTime(bigtime_t time); + + static inline int CompareByID(const Thread* a, const Thread* b); + static inline int CompareWithID(const thread_id* id, + const Thread* thread); + + static inline int CompareByCreationTimeID(const Thread* a, + const Thread* b); + static inline int CompareWithCreationTimeID( + const creation_time_id* key, + const Thread* thread); + +private: + Team* fTeam; + const system_profiler_thread_added* fCreationEvent; + bigtime_t fCreationTime; + bigtime_t fDeletionTime; +}; + + +team_id +Model::Team::ID() const +{ + return fCreationEvent->team; +} + + +void +Model::Team::SetDeletionTime(bigtime_t time) +{ + fDeletionTime = time; +} + + +/*static*/ int +Model::Team::CompareByID(const Team* a, const Team* b) +{ + return a->ID() - b->ID(); +} + + +/*static*/ int +Model::Team::CompareWithID(const team_id* id, const Team* team) +{ + return *id - team->ID(); +} + + +thread_id +Model::Thread::ID() const +{ + return fCreationEvent->thread; +} + + +void +Model::Thread::SetDeletionTime(bigtime_t time) +{ + fDeletionTime = time; +} + + +/*static*/ int +Model::Thread::CompareByID(const Thread* a, const Thread* b) +{ + return a->ID() - b->ID(); +} + + +/*static*/ int +Model::Thread::CompareWithID(const thread_id* id, const Thread* thread) +{ + return *id - thread->ID(); +} + + +/*static*/ int +Model::Thread::CompareByCreationTimeID(const Thread* a, const Thread* b) +{ + creation_time_id key; + key.time = a->fCreationTime; + key.id = a->ID(); + return CompareWithCreationTimeID(&key, b); +} + + +/*static*/ int +Model::Thread::CompareWithCreationTimeID(const creation_time_id* key, + const Thread* thread) +{ + bigtime_t cmp = key->time - thread->fCreationTime; + if (cmp == 0) + return key->id - thread->ID(); + return cmp < 0 ? -1 : 1; +} + #endif // MODEL_H diff --git a/src/apps/debuganalyzer/ModelLoader.cpp b/src/apps/debuganalyzer/ModelLoader.cpp index 6690385dc8..c407b214ea 100644 --- a/src/apps/debuganalyzer/ModelLoader.cpp +++ b/src/apps/debuganalyzer/ModelLoader.cpp @@ -61,21 +61,12 @@ ModelLoader::StartLoading() if (fModel != NULL || fLoading || fDataSource == NULL) return B_BAD_VALUE; - // create a model - Model* model = new(std::nothrow) Model; - if (model == NULL) - return B_NO_MEMORY; - ObjectDeleter modelDeleter(model); - // spawn the loader thread fLoaderThread = spawn_thread(&_LoaderEntry, "main model loader", B_NORMAL_PRIORITY, this); if (fLoaderThread < 0) return fLoaderThread; - modelDeleter.Detach(); - fModel = model; - fLoading = true; fAborted = false; @@ -156,12 +147,19 @@ ModelLoader::_Loader() status_t ModelLoader::_Load() { - // get a BDataIO from the data source - BDataIO* io; - status_t error = fDataSource->CreateDataIO(&io); + // read the complete data into memory + void* eventData; + size_t eventDataSize; + status_t error = _ReadDebugEvents(&eventData, &eventDataSize); if (error != B_OK) return error; - ObjectDeleter dataIOtDeleter(io); + + // create a model + fModel = new(std::nothrow) Model(eventData, eventDataSize); + if (fModel == NULL) { + free(eventData); + return B_NO_MEMORY; + } // create a debug input stream BDebugEventInputStream* input = new(std::nothrow) BDebugEventInputStream; @@ -169,11 +167,12 @@ ModelLoader::_Load() return B_NO_MEMORY; ObjectDeleter inputDeleter(input); - error = input->SetTo(io); + error = input->SetTo(eventData, eventDataSize, false); if (error != B_OK) return error; // process the events + fLastEventTime = -1; uint32 count = 0; while (true) { @@ -202,26 +201,143 @@ ModelLoader::_Load() } +status_t +ModelLoader::_ReadDebugEvents(void** _eventData, size_t* _size) +{ + // get a BDataIO from the data source + BDataIO* io; + status_t error = fDataSource->CreateDataIO(&io); + if (error != B_OK) + return error; + ObjectDeleter dataIOtDeleter(io); + + // First we need to find out how large a buffer to allocate. + size_t size; + + if (BPositionIO* positionIO = dynamic_cast(io)) { + // it's a BPositionIO -- this makes things easier, since we know how + // many bytes to read + off_t currentPos = positionIO->Position(); + if (currentPos < 0) + return currentPos; + + off_t fileSize; + error = positionIO->GetSize(&fileSize); + if (error != B_OK) + return error; + + size = fileSize - currentPos; + } else { + // no BPositionIO -- we need to determine the total size by iteratively + // reading the whole data one time + + // allocate a dummy buffer for reading + const size_t kBufferSize = 1024 * 1024; + void* buffer = malloc(kBufferSize); + if (buffer == NULL) + return B_NO_MEMORY; + MemoryDeleter bufferDeleter(buffer); + + size = 0; + while (true) { + ssize_t bytesRead = io->Read(buffer, kBufferSize); + if (bytesRead < 0) + return bytesRead; + if (bytesRead == 0) + break; + + size += bytesRead; + } + + // we've got the size -- recreate the BDataIO + dataIOtDeleter.Delete(); + error = fDataSource->CreateDataIO(&io); + if (error != B_OK) + return error; + dataIOtDeleter.SetTo(io); + } + + // allocate the data buffer + void* data = malloc(size); + if (data == NULL) + return B_NO_MEMORY; + MemoryDeleter dataDeleter(data); + + // read the data + ssize_t bytesRead = io->Read(data, size); + if (bytesRead < 0) + return bytesRead; + if ((size_t)bytesRead != size) + return B_FILE_ERROR; + + dataDeleter.Detach(); + *_eventData = data; + *_size = size; + return B_OK; +} + + status_t ModelLoader::_ProcessEvent(uint32 event, uint32 cpu, const void* buffer, size_t size) { switch (event) { case B_SYSTEM_PROFILER_TEAM_ADDED: -printf("B_SYSTEM_PROFILER_TEAM_ADDED: %lu\n", size); - break; + { +//printf("B_SYSTEM_PROFILER_TEAM_ADDED: %lu\n", size); + system_profiler_team_added* event + = (system_profiler_team_added*)buffer; + + if (fModel->AddTeam(event, fLastEventTime) == NULL) + return B_NO_MEMORY; + return B_OK; + } + case B_SYSTEM_PROFILER_TEAM_REMOVED: -printf("B_SYSTEM_PROFILER_TEAM_REMOVED: %lu\n", size); + { +//printf("B_SYSTEM_PROFILER_TEAM_REMOVED: %lu\n", size); + system_profiler_team_removed* event + = (system_profiler_team_removed*)buffer; + + if (Model::Team* team = fModel->TeamByID(event->team)) { + team->SetDeletionTime(fLastEventTime); + } else { + printf("Removed event for unknown team: %ld\n", event->team); + } break; + } + case B_SYSTEM_PROFILER_TEAM_EXEC: printf("B_SYSTEM_PROFILER_TEAM_EXEC: %lu\n", size); break; + case B_SYSTEM_PROFILER_THREAD_ADDED: -printf("B_SYSTEM_PROFILER_THREAD_ADDED: %lu\n", size); + { +//printf("B_SYSTEM_PROFILER_THREAD_ADDED: %lu\n", size); + system_profiler_thread_added* event + = (system_profiler_thread_added*)buffer; + + if (fModel->AddThread(event, fLastEventTime) == NULL) + return B_NO_MEMORY; + return B_OK; + break; + } + case B_SYSTEM_PROFILER_THREAD_REMOVED: -printf("B_SYSTEM_PROFILER_THREAD_REMOVED: %lu\n", size); +//printf("B_SYSTEM_PROFILER_THREAD_REMOVED: %lu\n", size); + { + system_profiler_thread_removed* event + = (system_profiler_thread_removed*)buffer; + + if (Model::Thread* thread = fModel->ThreadByID(event->thread)) { + thread->SetDeletionTime(fLastEventTime); + } else { + printf("Removed event for unknown team: %ld\n", event->thread); + } break; + } + case B_SYSTEM_PROFILER_THREAD_SCHEDULED: printf("B_SYSTEM_PROFILER_THREAD_SCHEDULED: %lu\n", size); break; @@ -240,7 +356,5 @@ return B_BAD_DATA; break; } - - // TODO: Implement! return B_OK; } diff --git a/src/apps/debuganalyzer/ModelLoader.h b/src/apps/debuganalyzer/ModelLoader.h index 2f56a8a9a0..d4bbc4ac6d 100644 --- a/src/apps/debuganalyzer/ModelLoader.h +++ b/src/apps/debuganalyzer/ModelLoader.h @@ -32,6 +32,8 @@ private: static status_t _LoaderEntry(void* data); status_t _Loader(); status_t _Load(); + status_t _ReadDebugEvents(void** _eventData, + size_t* _size); status_t _ProcessEvent(uint32 event, uint32 cpu, const void* buffer, size_t size); @@ -44,6 +46,7 @@ private: thread_id fLoaderThread; bool fLoading; bool fAborted; + bigtime_t fLastEventTime; }; diff --git a/src/apps/debuganalyzer/ThreadsPage.cpp b/src/apps/debuganalyzer/ThreadsPage.cpp index 98e110b541..c9add818f0 100644 --- a/src/apps/debuganalyzer/ThreadsPage.cpp +++ b/src/apps/debuganalyzer/ThreadsPage.cpp @@ -36,3 +36,10 @@ ThreadsPage::ThreadsPage() ThreadsPage::~ThreadsPage() { } + + +void +ThreadsPage::SetModel(Model* model) +{ + fModel = model; +} diff --git a/src/apps/debuganalyzer/ThreadsPage.h b/src/apps/debuganalyzer/ThreadsPage.h index c8abc8e9d7..f11e43cc4d 100644 --- a/src/apps/debuganalyzer/ThreadsPage.h +++ b/src/apps/debuganalyzer/ThreadsPage.h @@ -9,6 +9,7 @@ class BColumnListView; +class Model; class ThreadsPage : public BGroupView { @@ -16,8 +17,11 @@ public: ThreadsPage(); virtual ~ThreadsPage(); + void SetModel(Model* model); + private: BColumnListView* fThreadsListView; + Model* fModel; };