BTRFS: Implement BTree::Path and change _Find.
[haiku.git] / src / apps / debuganalyzer / model / Model.cpp
blobfe1119ab7d19c9a2bdf21855bcc3e26e50cdb3c5
1 /*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "Model.h"
9 #include <new>
11 #include <stdio.h>
12 #include <stdlib.h>
14 #include <AutoDeleter.h>
16 #include <thread_defs.h>
20 static const char* const kThreadStateNames[] = {
21 "running",
22 "still running",
23 "preempted",
24 "ready",
25 "waiting",
26 "unknown"
30 const char*
31 thread_state_name(ThreadState state)
33 return kThreadStateNames[state];
37 const char*
38 wait_object_type_name(uint32 type)
40 switch (type) {
41 case THREAD_BLOCK_TYPE_SEMAPHORE:
42 return "semaphore";
43 case THREAD_BLOCK_TYPE_CONDITION_VARIABLE:
44 return "condition";
45 case THREAD_BLOCK_TYPE_MUTEX:
46 return "mutex";
47 case THREAD_BLOCK_TYPE_RW_LOCK:
48 return "rw lock";
49 case THREAD_BLOCK_TYPE_OTHER:
50 return "other";
51 case THREAD_BLOCK_TYPE_SNOOZE:
52 return "snooze";
53 case THREAD_BLOCK_TYPE_SIGNAL:
54 return "signal";
55 default:
56 return "unknown";
61 // #pragma mark - CPU
64 Model::CPU::CPU()
66 fIdleTime(0)
71 void
72 Model::CPU::SetIdleTime(nanotime_t time)
74 fIdleTime = time;
78 // #pragma mark - IORequest
81 Model::IORequest::IORequest(
82 system_profiler_io_request_scheduled* scheduledEvent,
83 system_profiler_io_request_finished* finishedEvent, size_t operationCount)
85 scheduledEvent(scheduledEvent),
86 finishedEvent(finishedEvent),
87 operationCount(operationCount)
92 Model::IORequest::~IORequest()
97 /*static*/ Model::IORequest*
98 Model::IORequest::Create(system_profiler_io_request_scheduled* scheduledEvent,
99 system_profiler_io_request_finished* finishedEvent, size_t operationCount)
101 void* memory = malloc(
102 sizeof(IORequest) + operationCount * sizeof(IOOperation));
103 if (memory == NULL)
104 return NULL;
106 return new(memory) IORequest(scheduledEvent, finishedEvent, operationCount);
110 void
111 Model::IORequest::Delete()
113 free(this);
117 // #pragma mark - IOScheduler
120 Model::IOScheduler::IOScheduler(system_profiler_io_scheduler_added* event,
121 int32 index)
123 fAddedEvent(event),
124 fIndex(index)
129 // #pragma mark - WaitObject
132 Model::WaitObject::WaitObject(const system_profiler_wait_object_info* event)
134 fEvent(event),
135 fWaits(0),
136 fTotalWaitTime(0)
141 Model::WaitObject::~WaitObject()
146 void
147 Model::WaitObject::AddWait(nanotime_t waitTime)
149 fWaits++;
150 fTotalWaitTime += waitTime;
154 // #pragma mark - WaitObjectGroup
157 Model::WaitObjectGroup::WaitObjectGroup(WaitObject* waitObject)
159 fWaits(-1),
160 fTotalWaitTime(-1)
162 fWaitObjects.AddItem(waitObject);
166 Model::WaitObjectGroup::~WaitObjectGroup()
171 int64
172 Model::WaitObjectGroup::Waits()
174 if (fWaits < 0)
175 _ComputeWaits();
177 return fWaits;
181 nanotime_t
182 Model::WaitObjectGroup::TotalWaitTime()
184 if (fTotalWaitTime < 0)
185 _ComputeWaits();
187 return fTotalWaitTime;
191 void
192 Model::WaitObjectGroup::_ComputeWaits()
194 fWaits = 0;
195 fTotalWaitTime = 0;
197 for (int32 i = fWaitObjects.CountItems(); i-- > 0;) {
198 WaitObject* waitObject = fWaitObjects.ItemAt(i);
200 fWaits += waitObject->Waits();
201 fTotalWaitTime += waitObject->TotalWaitTime();
206 // #pragma mark - ThreadWaitObject
209 Model::ThreadWaitObject::ThreadWaitObject(WaitObject* waitObject)
211 fWaitObject(waitObject),
212 fWaits(0),
213 fTotalWaitTime(0)
218 Model::ThreadWaitObject::~ThreadWaitObject()
223 void
224 Model::ThreadWaitObject::AddWait(nanotime_t waitTime)
226 fWaits++;
227 fTotalWaitTime += waitTime;
229 fWaitObject->AddWait(waitTime);
233 // #pragma mark - ThreadWaitObjectGroup
236 Model::ThreadWaitObjectGroup::ThreadWaitObjectGroup(
237 ThreadWaitObject* threadWaitObject)
239 fWaitObjects.Add(threadWaitObject);
243 Model::ThreadWaitObjectGroup::~ThreadWaitObjectGroup()
248 bool
249 Model::ThreadWaitObjectGroup::GetThreadWaitObjects(
250 BObjectList<ThreadWaitObject>& objects)
252 ThreadWaitObjectList::Iterator it = fWaitObjects.GetIterator();
253 while (ThreadWaitObject* object = it.Next()) {
254 if (!objects.AddItem(object))
255 return false;
258 return true;
262 // #pragma mark - Team
265 Model::Team::Team(const system_profiler_team_added* event, nanotime_t time)
267 fCreationEvent(event),
268 fCreationTime(time),
269 fDeletionTime(-1),
270 fThreads(10)
275 Model::Team::~Team()
280 bool
281 Model::Team::AddThread(Thread* thread)
283 return fThreads.BinaryInsert(thread, &Thread::CompareByCreationTimeID);
287 // #pragma mark - Thread
290 Model::Thread::Thread(Team* team, const system_profiler_thread_added* event,
291 nanotime_t time)
293 fEvents(NULL),
294 fEventCount(0),
295 fIORequests(NULL),
296 fIORequestCount(0),
297 fTeam(team),
298 fCreationEvent(event),
299 fCreationTime(time),
300 fDeletionTime(-1),
301 fRuns(0),
302 fTotalRunTime(0),
303 fMinRunTime(-1),
304 fMaxRunTime(-1),
305 fLatencies(0),
306 fTotalLatency(0),
307 fMinLatency(-1),
308 fMaxLatency(-1),
309 fReruns(0),
310 fTotalRerunTime(0),
311 fMinRerunTime(-1),
312 fMaxRerunTime(-1),
313 fWaits(0),
314 fTotalWaitTime(0),
315 fUnspecifiedWaitTime(0),
316 fIOCount(0),
317 fIOTime(0),
318 fPreemptions(0),
319 fIndex(-1),
320 fWaitObjectGroups(20, true)
325 Model::Thread::~Thread()
327 if (fIORequests != NULL) {
328 for (size_t i = 0; i < fIORequestCount; i++)
329 fIORequests[i]->Delete();
331 delete[] fIORequests;
334 delete[] fEvents;
338 void
339 Model::Thread::SetEvents(system_profiler_event_header** events,
340 size_t eventCount)
342 fEvents = events;
343 fEventCount = eventCount;
347 void
348 Model::Thread::SetIORequests(IORequest** requests, size_t requestCount)
350 fIORequests = requests;
351 fIORequestCount = requestCount;
355 size_t
356 Model::Thread::ClosestRequestStartIndex(nanotime_t minRequestStartTime) const
358 size_t lower = 0;
359 size_t upper = fIORequestCount;
360 while (lower < upper) {
361 size_t mid = (lower + upper) / 2;
362 IORequest* request = fIORequests[mid];
364 if (request->ScheduledTime() < minRequestStartTime)
365 lower = mid + 1;
366 else
367 upper = mid;
370 return lower;
374 Model::ThreadWaitObjectGroup*
375 Model::Thread::ThreadWaitObjectGroupFor(uint32 type, addr_t object) const
377 type_and_object key;
378 key.type = type;
379 key.object = object;
381 return fWaitObjectGroups.BinarySearchByKey(key,
382 &ThreadWaitObjectGroup::CompareWithTypeObject);
386 void
387 Model::Thread::AddRun(nanotime_t runTime)
389 fRuns++;
390 fTotalRunTime += runTime;
392 if (fMinRunTime < 0 || runTime < fMinRunTime)
393 fMinRunTime = runTime;
394 if (runTime > fMaxRunTime)
395 fMaxRunTime = runTime;
399 void
400 Model::Thread::AddRerun(nanotime_t runTime)
402 fReruns++;
403 fTotalRerunTime += runTime;
405 if (fMinRerunTime < 0 || runTime < fMinRerunTime)
406 fMinRerunTime = runTime;
407 if (runTime > fMaxRerunTime)
408 fMaxRerunTime = runTime;
412 void
413 Model::Thread::AddLatency(nanotime_t latency)
415 fLatencies++;
416 fTotalLatency += latency;
418 if (fMinLatency < 0 || latency < fMinLatency)
419 fMinLatency = latency;
420 if (latency > fMaxLatency)
421 fMaxLatency = latency;
425 void
426 Model::Thread::AddPreemption(nanotime_t runTime)
428 fPreemptions++;
432 void
433 Model::Thread::AddWait(nanotime_t waitTime)
435 fWaits++;
436 fTotalWaitTime += waitTime;
440 void
441 Model::Thread::AddUnspecifiedWait(nanotime_t waitTime)
443 fUnspecifiedWaitTime += waitTime;
447 Model::ThreadWaitObject*
448 Model::Thread::AddThreadWaitObject(WaitObject* waitObject,
449 ThreadWaitObjectGroup** _threadWaitObjectGroup)
451 // create a thread wait object
452 ThreadWaitObject* threadWaitObject
453 = new(std::nothrow) ThreadWaitObject(waitObject);
454 if (threadWaitObject == NULL)
455 return NULL;
457 // find the thread wait object group
458 ThreadWaitObjectGroup* threadWaitObjectGroup
459 = ThreadWaitObjectGroupFor(waitObject->Type(), waitObject->Object());
460 if (threadWaitObjectGroup == NULL) {
461 // doesn't exist yet -- create
462 threadWaitObjectGroup = new(std::nothrow) ThreadWaitObjectGroup(
463 threadWaitObject);
464 if (threadWaitObjectGroup == NULL) {
465 delete threadWaitObject;
466 return NULL;
469 // add to the list
470 if (!fWaitObjectGroups.BinaryInsert(threadWaitObjectGroup,
471 &ThreadWaitObjectGroup::CompareByTypeObject)) {
472 delete threadWaitObjectGroup;
473 return NULL;
475 } else {
476 // exists -- just add the object
477 threadWaitObjectGroup->AddWaitObject(threadWaitObject);
480 if (_threadWaitObjectGroup != NULL)
481 *_threadWaitObjectGroup = threadWaitObjectGroup;
483 return threadWaitObject;
487 void
488 Model::Thread::SetIOs(int64 count, nanotime_t time)
490 fIOCount = count;
491 fIOTime = time;
495 // #pragma mark - SchedulingState
498 Model::SchedulingState::~SchedulingState()
500 Clear();
504 status_t
505 Model::SchedulingState::Init()
507 status_t error = fThreadStates.Init();
508 if (error != B_OK)
509 return error;
511 return B_OK;
515 status_t
516 Model::SchedulingState::Init(const CompactSchedulingState* state)
518 status_t error = Init();
519 if (error != B_OK)
520 return error;
522 if (state == NULL)
523 return B_OK;
525 fLastEventTime = state->LastEventTime();
526 for (int32 i = 0; const CompactThreadSchedulingState* compactThreadState
527 = state->ThreadStateAt(i); i++) {
528 ThreadSchedulingState* threadState
529 = new(std::nothrow) ThreadSchedulingState(*compactThreadState);
530 if (threadState == NULL)
531 return B_NO_MEMORY;
533 fThreadStates.Insert(threadState);
536 return B_OK;
540 void
541 Model::SchedulingState::Clear()
543 ThreadSchedulingState* state = fThreadStates.Clear(true);
544 while (state != NULL) {
545 ThreadSchedulingState* next = state->next;
546 DeleteThread(state);
547 state = next;
550 fLastEventTime = -1;
553 void
554 Model::SchedulingState::DeleteThread(ThreadSchedulingState* thread)
556 delete thread;
560 // #pragma mark - CompactSchedulingState
563 /*static*/ Model::CompactSchedulingState*
564 Model::CompactSchedulingState::Create(const SchedulingState& state,
565 off_t eventOffset)
567 nanotime_t lastEventTime = state.LastEventTime();
569 // count the active threads
570 int32 threadCount = 0;
571 for (ThreadSchedulingStateTable::Iterator it
572 = state.ThreadStates().GetIterator();
573 ThreadSchedulingState* threadState = it.Next();) {
574 Thread* thread = threadState->thread;
575 if (thread->CreationTime() <= lastEventTime
576 && (thread->DeletionTime() == -1
577 || thread->DeletionTime() >= lastEventTime)) {
578 threadCount++;
582 CompactSchedulingState* compactState = (CompactSchedulingState*)malloc(
583 sizeof(CompactSchedulingState)
584 + threadCount * sizeof(CompactThreadSchedulingState));
585 if (compactState == NULL)
586 return NULL;
588 // copy the state info
589 compactState->fEventOffset = eventOffset;
590 compactState->fThreadCount = threadCount;
591 compactState->fLastEventTime = lastEventTime;
593 int32 threadIndex = 0;
594 for (ThreadSchedulingStateTable::Iterator it
595 = state.ThreadStates().GetIterator();
596 ThreadSchedulingState* threadState = it.Next();) {
597 Thread* thread = threadState->thread;
598 if (thread->CreationTime() <= lastEventTime
599 && (thread->DeletionTime() == -1
600 || thread->DeletionTime() >= lastEventTime)) {
601 compactState->fThreadStates[threadIndex++] = *threadState;
605 return compactState;
609 void
610 Model::CompactSchedulingState::Delete()
612 free(this);
616 // #pragma mark - Model
619 Model::Model(const char* dataSourceName, void* eventData, size_t eventDataSize,
620 system_profiler_event_header** events, size_t eventCount)
622 fDataSourceName(dataSourceName),
623 fEventData(eventData),
624 fEvents(events),
625 fEventDataSize(eventDataSize),
626 fEventCount(eventCount),
627 fCPUCount(1),
628 fBaseTime(0),
629 fLastEventTime(0),
630 fIdleTime(0),
631 fCPUs(20, true),
632 fTeams(20, true),
633 fThreads(20, true),
634 fWaitObjectGroups(20, true),
635 fIOSchedulers(10, true),
636 fSchedulingStates(100)
641 Model::~Model()
643 for (int32 i = 0; CompactSchedulingState* state
644 = fSchedulingStates.ItemAt(i); i++) {
645 state->Delete();
648 delete[] fEvents;
650 free(fEventData);
652 for (int32 i = 0; void* data = fAssociatedData.ItemAt(i); i++)
653 free(data);
657 size_t
658 Model::ClosestEventIndex(nanotime_t eventTime) const
660 // The events themselves are unmodified and use an absolute time.
661 eventTime += fBaseTime;
663 // Binary search the event. Since not all events have a timestamp, we have
664 // to do a bit of iteration, too.
665 size_t lower = 0;
666 size_t upper = CountEvents();
667 while (lower < upper) {
668 size_t mid = (lower + upper) / 2;
669 while (mid < upper) {
670 system_profiler_event_header* header = fEvents[mid];
671 switch (header->event) {
672 case B_SYSTEM_PROFILER_THREAD_SCHEDULED:
673 case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE:
674 case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE:
675 break;
676 default:
677 mid++;
678 continue;
681 break;
684 if (mid == upper) {
685 lower = mid;
686 break;
689 system_profiler_thread_scheduling_event* event
690 = (system_profiler_thread_scheduling_event*)(fEvents[mid] + 1);
691 if (event->time < eventTime)
692 lower = mid + 1;
693 else
694 upper = mid;
697 return lower;
701 bool
702 Model::AddAssociatedData(void* data)
704 return fAssociatedData.AddItem(data);
708 void
709 Model::RemoveAssociatedData(void* data)
711 fAssociatedData.RemoveItem(data);
715 void
716 Model::LoadingFinished()
718 // set the thread indices
719 for (int32 i = 0; Thread* thread = fThreads.ItemAt(i); i++)
720 thread->SetIndex(i);
722 // compute the total idle time
723 fIdleTime = 0;
724 for (int32 i = 0; CPU* cpu = CPUAt(i); i++)
725 fIdleTime += cpu->IdleTime();
729 void
730 Model::SetBaseTime(nanotime_t time)
732 fBaseTime = time;
736 void
737 Model::SetLastEventTime(nanotime_t time)
739 fLastEventTime = time;
743 bool
744 Model::SetCPUCount(int32 count)
746 fCPUCount = count;
748 fCPUs.MakeEmpty();
750 for (int32 i = 0; i < fCPUCount; i++) {
751 CPU* cpu = new(std::nothrow) CPU;
752 if (cpu == NULL || !fCPUs.AddItem(cpu)) {
753 delete cpu;
754 return false;
758 return true;
762 int32
763 Model::CountTeams() const
765 return fTeams.CountItems();
769 Model::Team*
770 Model::TeamAt(int32 index) const
772 return fTeams.ItemAt(index);
776 Model::Team*
777 Model::TeamByID(team_id id) const
779 return fTeams.BinarySearchByKey(id, &Team::CompareWithID);
783 Model::Team*
784 Model::AddTeam(const system_profiler_team_added* event, nanotime_t time)
786 Team* team = TeamByID(event->team);
787 if (team != NULL) {
788 fprintf(stderr, "Duplicate team: %" B_PRId32 "\n", event->team);
789 // TODO: User feedback!
790 return team;
793 team = new(std::nothrow) Team(event, time);
794 if (team == NULL)
795 return NULL;
797 if (!fTeams.BinaryInsert(team, &Team::CompareByID)) {
798 delete team;
799 return NULL;
802 return team;
806 int32
807 Model::CountThreads() const
809 return fThreads.CountItems();
813 Model::Thread*
814 Model::ThreadAt(int32 index) const
816 return fThreads.ItemAt(index);
820 Model::Thread*
821 Model::ThreadByID(thread_id id) const
823 return fThreads.BinarySearchByKey(id, &Thread::CompareWithID);
827 Model::Thread*
828 Model::AddThread(const system_profiler_thread_added* event, nanotime_t time)
830 // check whether we do already know the thread
831 Thread* thread = ThreadByID(event->thread);
832 if (thread != NULL) {
833 fprintf(stderr, "Duplicate thread: %" B_PRId32 "\n", event->thread);
834 // TODO: User feedback!
835 return thread;
838 // get its team
839 Team* team = TeamByID(event->team);
840 if (team == NULL) {
841 fprintf(stderr, "No team for thread: %" B_PRId32 "\n", event->thread);
842 return NULL;
845 // create the thread and add it
846 thread = new(std::nothrow) Thread(team, event, time);
847 if (thread == NULL)
848 return NULL;
849 ObjectDeleter<Thread> threadDeleter(thread);
851 if (!fThreads.BinaryInsert(thread, &Thread::CompareByID))
852 return NULL;
854 if (!team->AddThread(thread)) {
855 fThreads.RemoveItem(thread);
856 return NULL;
859 threadDeleter.Detach();
860 return thread;
864 Model::WaitObject*
865 Model::AddWaitObject(const system_profiler_wait_object_info* event,
866 WaitObjectGroup** _waitObjectGroup)
868 // create a wait object
869 WaitObject* waitObject = new(std::nothrow) WaitObject(event);
870 if (waitObject == NULL)
871 return NULL;
873 // find the wait object group
874 WaitObjectGroup* waitObjectGroup
875 = WaitObjectGroupFor(waitObject->Type(), waitObject->Object());
876 if (waitObjectGroup == NULL) {
877 // doesn't exist yet -- create
878 waitObjectGroup = new(std::nothrow) WaitObjectGroup(waitObject);
879 if (waitObjectGroup == NULL) {
880 delete waitObject;
881 return NULL;
884 // add to the list
885 if (!fWaitObjectGroups.BinaryInsert(waitObjectGroup,
886 &WaitObjectGroup::CompareByTypeObject)) {
887 delete waitObjectGroup;
888 return NULL;
890 } else {
891 // exists -- just add the object
892 waitObjectGroup->AddWaitObject(waitObject);
895 if (_waitObjectGroup != NULL)
896 *_waitObjectGroup = waitObjectGroup;
898 return waitObject;
902 int32
903 Model::CountWaitObjectGroups() const
905 return fWaitObjectGroups.CountItems();
909 Model::WaitObjectGroup*
910 Model::WaitObjectGroupAt(int32 index) const
912 return fWaitObjectGroups.ItemAt(index);
916 Model::WaitObjectGroup*
917 Model::WaitObjectGroupFor(uint32 type, addr_t object) const
919 type_and_object key;
920 key.type = type;
921 key.object = object;
923 return fWaitObjectGroups.BinarySearchByKey(key,
924 &WaitObjectGroup::CompareWithTypeObject);
928 Model::ThreadWaitObject*
929 Model::AddThreadWaitObject(thread_id threadID, WaitObject* waitObject,
930 ThreadWaitObjectGroup** _threadWaitObjectGroup)
932 Thread* thread = ThreadByID(threadID);
933 if (thread == NULL)
934 return NULL;
936 return thread->AddThreadWaitObject(waitObject, _threadWaitObjectGroup);
940 Model::ThreadWaitObjectGroup*
941 Model::ThreadWaitObjectGroupFor(thread_id threadID, uint32 type, addr_t object) const
943 Thread* thread = ThreadByID(threadID);
944 if (thread == NULL)
945 return NULL;
947 return thread->ThreadWaitObjectGroupFor(type, object);
951 int32
952 Model::CountIOSchedulers() const
954 return fIOSchedulers.CountItems();
958 Model::IOScheduler*
959 Model::IOSchedulerAt(int32 index) const
961 return fIOSchedulers.ItemAt(index);
965 Model::IOScheduler*
966 Model::IOSchedulerByID(int32 id) const
968 for (int32 i = 0; IOScheduler* scheduler = fIOSchedulers.ItemAt(i); i++) {
969 if (scheduler->ID() == id)
970 return scheduler;
973 return NULL;
977 Model::IOScheduler*
978 Model::AddIOScheduler(system_profiler_io_scheduler_added* event)
980 IOScheduler* scheduler = new(std::nothrow) IOScheduler(event,
981 fIOSchedulers.CountItems());
982 if (scheduler == NULL || !fIOSchedulers.AddItem(scheduler)) {
983 delete scheduler;
984 return NULL;
987 return scheduler;
991 bool
992 Model::AddSchedulingStateSnapshot(const SchedulingState& state,
993 off_t eventOffset)
995 CompactSchedulingState* compactState = CompactSchedulingState::Create(state,
996 eventOffset);
997 if (compactState == NULL)
998 return false;
1000 if (!fSchedulingStates.AddItem(compactState)) {
1001 compactState->Delete();
1002 return false;
1005 return true;
1009 const Model::CompactSchedulingState*
1010 Model::ClosestSchedulingState(nanotime_t eventTime) const
1012 int32 index = fSchedulingStates.BinarySearchIndexByKey(eventTime,
1013 &_CompareEventTimeSchedulingState);
1014 if (index >= 0)
1015 return fSchedulingStates.ItemAt(index);
1017 // no exact match
1018 index = -index - 1;
1019 return index > 0 ? fSchedulingStates.ItemAt(index - 1) : NULL;
1023 /*static*/ int
1024 Model::_CompareEventTimeSchedulingState(const nanotime_t* time,
1025 const CompactSchedulingState* state)
1027 if (*time < state->LastEventTime())
1028 return -1;
1029 return *time == state->LastEventTime() ? 0 : 1;