BTRFS: Implement BTree::Path and change _Find.
[haiku.git] / src / apps / debuganalyzer / model_loader / ModelLoader.cpp
blob7b75f2cfd0fb145d792044a8d00c7f0357001735
1 /*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "ModelLoader.h"
9 #include <stdio.h>
10 #include <string.h>
12 #include <algorithm>
13 #include <new>
15 #include <AutoDeleter.h>
16 #include <AutoLocker.h>
17 #include <DebugEventStream.h>
19 #include <system_profiler_defs.h>
20 #include <thread_defs.h>
22 #include "DataSource.h"
23 #include "MessageCodes.h"
24 #include "Model.h"
27 // add a scheduling state snapshot every x events
28 static const uint32 kSchedulingSnapshotInterval = 1024;
30 static const uint32 kMaxCPUCount = 1024;
33 struct SimpleWaitObjectInfo : system_profiler_wait_object_info {
34 SimpleWaitObjectInfo(uint32 type)
36 this->type = type;
37 object = 0;
38 referenced_object = 0;
39 name[0] = '\0';
44 static const SimpleWaitObjectInfo kSnoozeWaitObjectInfo(
45 THREAD_BLOCK_TYPE_SNOOZE);
46 static const SimpleWaitObjectInfo kSignalWaitObjectInfo(
47 THREAD_BLOCK_TYPE_SIGNAL);
50 // #pragma mark - CPUInfo
53 struct ModelLoader::CPUInfo {
54 nanotime_t idleTime;
56 CPUInfo()
58 idleTime(0)
64 // #pragma mark - IOOperation
67 struct ModelLoader::IOOperation : DoublyLinkedListLinkImpl<IOOperation> {
68 io_operation_started* startedEvent;
69 io_operation_finished* finishedEvent;
71 IOOperation(io_operation_started* startedEvent)
73 startedEvent(startedEvent),
74 finishedEvent(NULL)
80 // #pragma mark - IORequest
83 struct ModelLoader::IORequest : DoublyLinkedListLinkImpl<IORequest> {
84 io_request_scheduled* scheduledEvent;
85 io_request_finished* finishedEvent;
86 IOOperationList operations;
87 size_t operationCount;
88 IORequest* hashNext;
90 IORequest(io_request_scheduled* scheduledEvent)
92 scheduledEvent(scheduledEvent),
93 finishedEvent(NULL),
94 operationCount(0)
98 ~IORequest()
100 while (IOOperation* operation = operations.RemoveHead())
101 delete operation;
104 void AddOperation(IOOperation* operation)
106 operations.Add(operation);
107 operationCount++;
110 IOOperation* FindOperation(void* address) const
112 for (IOOperationList::ConstReverseIterator it
113 = operations.GetReverseIterator();
114 IOOperation* operation = it.Next();) {
115 if (operation->startedEvent->operation == address)
116 return operation;
119 return NULL;
122 Model::IORequest* CreateModelRequest() const
124 size_t operationCount = operations.Count();
126 Model::IORequest* modelRequest = Model::IORequest::Create(
127 scheduledEvent, finishedEvent, operationCount);
128 if (modelRequest == NULL)
129 return NULL;
131 size_t index = 0;
132 for (IOOperationList::ConstIterator it = operations.GetIterator();
133 IOOperation* operation = it.Next();) {
134 Model::IOOperation& modelOperation
135 = modelRequest->operations[index++];
136 modelOperation.startedEvent = operation->startedEvent;
137 modelOperation.finishedEvent = operation->finishedEvent;
140 return modelRequest;
145 // #pragma mark - IORequestHashDefinition
148 struct ModelLoader::IORequestHashDefinition {
149 typedef void* KeyType;
150 typedef IORequest ValueType;
152 size_t HashKey(KeyType key) const
153 { return (size_t)key; }
155 size_t Hash(const IORequest* value) const
156 { return HashKey(value->scheduledEvent->request); }
158 bool Compare(KeyType key, const IORequest* value) const
159 { return key == value->scheduledEvent->request; }
161 IORequest*& GetLink(IORequest* value) const
162 { return value->hashNext; }
166 // #pragma mark - ExtendedThreadSchedulingState
169 struct ModelLoader::ExtendedThreadSchedulingState
170 : Model::ThreadSchedulingState {
172 ExtendedThreadSchedulingState(Model::Thread* thread)
174 Model::ThreadSchedulingState(thread),
175 fEvents(NULL),
176 fEventIndex(0),
177 fEventCount(0)
181 ~ExtendedThreadSchedulingState()
183 delete[] fEvents;
185 while (IORequest* request = fIORequests.RemoveHead())
186 delete request;
187 while (IORequest* request = fPendingIORequests.RemoveHead())
188 delete request;
191 system_profiler_event_header** Events() const
193 return fEvents;
196 size_t CountEvents() const
198 return fEventCount;
201 system_profiler_event_header** DetachEvents()
203 system_profiler_event_header** events = fEvents;
204 fEvents = NULL;
205 return events;
208 void IncrementEventCount()
210 fEventCount++;
213 void AddEvent(system_profiler_event_header* event)
215 fEvents[fEventIndex++] = event;
218 bool AllocateEventArray()
220 if (fEventCount == 0)
221 return true;
223 fEvents = new(std::nothrow) system_profiler_event_header*[fEventCount];
224 if (fEvents == NULL)
225 return false;
227 return true;
230 void AddIORequest(IORequest* request)
232 fPendingIORequests.Add(request);
235 void IORequestFinished(IORequest* request)
237 fPendingIORequests.Remove(request);
238 fIORequests.Add(request);
241 bool PrepareThreadIORequests(Model::IORequest**& _requests,
242 size_t& _requestCount)
244 fIORequests.MoveFrom(&fPendingIORequests);
245 size_t requestCount = fIORequests.Count();
247 if (requestCount == 0) {
248 _requests = NULL;
249 _requestCount = 0;
250 return true;
253 Model::IORequest** requests
254 = new(std::nothrow) Model::IORequest*[requestCount];
255 if (requests == NULL)
256 return false;
258 size_t index = 0;
259 while (IORequest* request = fIORequests.RemoveHead()) {
260 ObjectDeleter<IORequest> requestDeleter(request);
262 Model::IORequest* modelRequest = request->CreateModelRequest();
263 if (modelRequest == NULL) {
264 for (size_t i = 0; i < index; i++)
265 requests[i]->Delete();
266 return false;
269 requests[index++] = modelRequest;
272 _requests = requests;
273 _requestCount = requestCount;
274 return true;
277 private:
278 system_profiler_event_header** fEvents;
279 size_t fEventIndex;
280 size_t fEventCount;
281 IORequestList fIORequests;
282 IORequestList fPendingIORequests;
286 // #pragma mark - ExtendedSchedulingState
289 struct ModelLoader::ExtendedSchedulingState : Model::SchedulingState {
290 inline ExtendedThreadSchedulingState* LookupThread(thread_id threadID) const
292 Model::ThreadSchedulingState* thread
293 = Model::SchedulingState::LookupThread(threadID);
294 return thread != NULL
295 ? static_cast<ExtendedThreadSchedulingState*>(thread) : NULL;
299 protected:
300 virtual void DeleteThread(Model::ThreadSchedulingState* thread)
302 delete static_cast<ExtendedThreadSchedulingState*>(thread);
307 // #pragma mark - ModelLoader
310 inline void
311 ModelLoader::_UpdateLastEventTime(nanotime_t time)
313 if (fBaseTime < 0) {
314 fBaseTime = time;
315 fModel->SetBaseTime(time);
318 fState->SetLastEventTime(time - fBaseTime);
322 ModelLoader::ModelLoader(DataSource* dataSource,
323 const BMessenger& target, void* targetCookie)
325 AbstractModelLoader(target, targetCookie),
326 fModel(NULL),
327 fDataSource(dataSource),
328 fCPUInfos(NULL),
329 fState(NULL),
330 fIORequests(NULL)
335 ModelLoader::~ModelLoader()
337 delete[] fCPUInfos;
338 delete fDataSource;
339 delete fModel;
340 delete fState;
341 delete fIORequests;
345 Model*
346 ModelLoader::DetachModel()
348 AutoLocker<BLocker> locker(fLock);
350 if (fModel == NULL || fLoading)
351 return NULL;
353 Model* model = fModel;
354 fModel = NULL;
356 return model;
360 status_t
361 ModelLoader::PrepareForLoading()
363 if (fModel != NULL || fDataSource == NULL)
364 return B_BAD_VALUE;
366 // create and init the state
367 fState = new(std::nothrow) ExtendedSchedulingState;
368 if (fState == NULL)
369 return B_NO_MEMORY;
371 status_t error = fState->Init();
372 if (error != B_OK)
373 return error;
375 // create CPU info array
376 fCPUInfos = new(std::nothrow) CPUInfo[kMaxCPUCount];
377 if (fCPUInfos == NULL)
378 return B_NO_MEMORY;
380 // create IORequest hash table
381 fIORequests = new(std::nothrow) IORequestTable;
382 if (fIORequests == NULL || fIORequests->Init() != B_OK)
383 return B_NO_MEMORY;
385 return B_OK;
389 status_t
390 ModelLoader::Load()
392 try {
393 return _Load();
394 } catch(...) {
395 return B_ERROR;
400 void
401 ModelLoader::FinishLoading(bool success)
403 delete fState;
404 fState = NULL;
406 if (!success) {
407 delete fModel;
408 fModel = NULL;
411 delete[] fCPUInfos;
412 fCPUInfos = NULL;
414 delete fIORequests;
415 fIORequests = NULL;
419 status_t
420 ModelLoader::_Load()
422 // read the complete data into memory
423 void* eventData;
424 size_t eventDataSize;
425 status_t error = _ReadDebugEvents(&eventData, &eventDataSize);
426 if (error != B_OK)
427 return error;
428 MemoryDeleter eventDataDeleter(eventData);
430 // create a debug event array
431 system_profiler_event_header** events;
432 size_t eventCount;
433 error = _CreateDebugEventArray(eventData, eventDataSize, events,
434 eventCount);
435 if (error != B_OK)
436 return error;
437 ArrayDeleter<system_profiler_event_header*> eventsDeleter(events);
439 // get the data source name
440 BString dataSourceName;
441 fDataSource->GetName(dataSourceName);
443 // create a model
444 fModel = new(std::nothrow) Model(dataSourceName.String(), eventData,
445 eventDataSize, events, eventCount);
446 if (fModel == NULL)
447 return B_NO_MEMORY;
448 eventDataDeleter.Detach();
449 eventsDeleter.Detach();
451 // create a debug input stream
452 BDebugEventInputStream input;
453 error = input.SetTo(eventData, eventDataSize, false);
454 if (error != B_OK)
455 return error;
457 // add the snooze and signal wait objects to the model
458 if (fModel->AddWaitObject(&kSnoozeWaitObjectInfo, NULL) == NULL
459 || fModel->AddWaitObject(&kSignalWaitObjectInfo, NULL) == NULL) {
460 return B_NO_MEMORY;
463 // process the events
464 fMaxCPUIndex = 0;
465 fState->Clear();
466 fBaseTime = -1;
467 uint64 count = 0;
469 while (true) {
470 // get next event
471 uint32 event;
472 uint32 cpu;
473 const void* buffer;
474 off_t offset;
475 ssize_t bufferSize = input.ReadNextEvent(&event, &cpu, &buffer,
476 &offset);
477 if (bufferSize < 0)
478 return bufferSize;
479 if (buffer == NULL)
480 break;
482 // process the event
483 status_t error = _ProcessEvent(event, cpu, buffer, bufferSize);
484 if (error != B_OK)
485 return error;
487 if (cpu > fMaxCPUIndex) {
488 if (cpu + 1 > kMaxCPUCount)
489 return B_BAD_DATA;
490 fMaxCPUIndex = cpu;
493 // periodically check whether we're supposed to abort
494 if (++count % 32 == 0) {
495 AutoLocker<BLocker> locker(fLock);
496 if (fAborted)
497 return B_ERROR;
500 // periodically add scheduling snapshots
501 if (count % kSchedulingSnapshotInterval == 0)
502 fModel->AddSchedulingStateSnapshot(*fState, offset);
505 if (!fModel->SetCPUCount(fMaxCPUIndex + 1))
506 return B_NO_MEMORY;
508 for (uint32 i = 0; i <= fMaxCPUIndex; i++)
509 fModel->CPUAt(i)->SetIdleTime(fCPUInfos[i].idleTime);
511 fModel->SetLastEventTime(fState->LastEventTime());
513 if (!_SetThreadEvents() || !_SetThreadIORequests())
514 return B_NO_MEMORY;
516 fModel->LoadingFinished();
518 return B_OK;
522 status_t
523 ModelLoader::_ReadDebugEvents(void** _eventData, size_t* _size)
525 // get a BDataIO from the data source
526 BDataIO* io;
527 status_t error = fDataSource->CreateDataIO(&io);
528 if (error != B_OK)
529 return error;
530 ObjectDeleter<BDataIO> dataIOtDeleter(io);
532 // First we need to find out how large a buffer to allocate.
533 size_t size;
535 if (BPositionIO* positionIO = dynamic_cast<BPositionIO*>(io)) {
536 // it's a BPositionIO -- this makes things easier, since we know how
537 // many bytes to read
538 off_t currentPos = positionIO->Position();
539 if (currentPos < 0)
540 return currentPos;
542 off_t fileSize;
543 error = positionIO->GetSize(&fileSize);
544 if (error != B_OK)
545 return error;
547 size = fileSize - currentPos;
548 } else {
549 // no BPositionIO -- we need to determine the total size by iteratively
550 // reading the whole data one time
552 // allocate a dummy buffer for reading
553 const size_t kBufferSize = 1024 * 1024;
554 void* buffer = malloc(kBufferSize);
555 if (buffer == NULL)
556 return B_NO_MEMORY;
557 MemoryDeleter bufferDeleter(buffer);
559 size = 0;
560 while (true) {
561 ssize_t bytesRead = io->Read(buffer, kBufferSize);
562 if (bytesRead < 0)
563 return bytesRead;
564 if (bytesRead == 0)
565 break;
567 size += bytesRead;
570 // we've got the size -- recreate the BDataIO
571 dataIOtDeleter.Delete();
572 error = fDataSource->CreateDataIO(&io);
573 if (error != B_OK)
574 return error;
575 dataIOtDeleter.SetTo(io);
578 // allocate the data buffer
579 void* data = malloc(size);
580 if (data == NULL)
581 return B_NO_MEMORY;
582 MemoryDeleter dataDeleter(data);
584 // read the data
585 ssize_t bytesRead = io->Read(data, size);
586 if (bytesRead < 0)
587 return bytesRead;
588 if ((size_t)bytesRead != size)
589 return B_FILE_ERROR;
591 dataDeleter.Detach();
592 *_eventData = data;
593 *_size = size;
594 return B_OK;
598 status_t
599 ModelLoader::_CreateDebugEventArray(void* eventData, size_t eventDataSize,
600 system_profiler_event_header**& _events, size_t& _eventCount)
602 // count the events
603 BDebugEventInputStream input;
604 status_t error = input.SetTo(eventData, eventDataSize, false);
605 if (error != B_OK)
606 return error;
608 size_t eventCount = 0;
609 while (true) {
610 // get next event
611 uint32 event;
612 uint32 cpu;
613 const void* buffer;
614 ssize_t bufferSize = input.ReadNextEvent(&event, &cpu, &buffer, NULL);
615 if (bufferSize < 0)
616 return bufferSize;
617 if (buffer == NULL)
618 break;
620 eventCount++;
623 // create the array
624 system_profiler_event_header** events = new(std::nothrow)
625 system_profiler_event_header*[eventCount];
626 if (events == NULL)
627 return B_NO_MEMORY;
629 // populate the array
630 error = input.SetTo(eventData, eventDataSize, false);
631 if (error != B_OK) {
632 delete[] events;
633 return error;
636 size_t eventIndex = 0;
637 while (true) {
638 // get next event
639 uint32 event;
640 uint32 cpu;
641 const void* buffer;
642 off_t offset;
643 input.ReadNextEvent(&event, &cpu, &buffer, &offset);
644 if (buffer == NULL)
645 break;
647 events[eventIndex++]
648 = (system_profiler_event_header*)((uint8*)eventData + offset);
651 _events = events;
652 _eventCount = eventCount;
653 return B_OK;
657 status_t
658 ModelLoader::_ProcessEvent(uint32 event, uint32 cpu, const void* buffer,
659 size_t size)
661 switch (event) {
662 case B_SYSTEM_PROFILER_TEAM_ADDED:
663 _HandleTeamAdded((system_profiler_team_added*)buffer);
664 break;
666 case B_SYSTEM_PROFILER_TEAM_REMOVED:
667 _HandleTeamRemoved((system_profiler_team_removed*)buffer);
668 break;
670 case B_SYSTEM_PROFILER_TEAM_EXEC:
671 _HandleTeamExec((system_profiler_team_exec*)buffer);
672 break;
674 case B_SYSTEM_PROFILER_THREAD_ADDED:
675 _HandleThreadAdded((system_profiler_thread_added*)buffer);
676 break;
678 case B_SYSTEM_PROFILER_THREAD_REMOVED:
679 _HandleThreadRemoved((system_profiler_thread_removed*)buffer);
680 break;
682 case B_SYSTEM_PROFILER_THREAD_SCHEDULED:
683 _HandleThreadScheduled(cpu,
684 (system_profiler_thread_scheduled*)buffer);
685 break;
687 case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE:
688 _HandleThreadEnqueuedInRunQueue(
689 (thread_enqueued_in_run_queue*)buffer);
690 break;
692 case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE:
693 _HandleThreadRemovedFromRunQueue(cpu,
694 (thread_removed_from_run_queue*)buffer);
695 break;
697 case B_SYSTEM_PROFILER_WAIT_OBJECT_INFO:
698 _HandleWaitObjectInfo((system_profiler_wait_object_info*)buffer);
699 break;
701 case B_SYSTEM_PROFILER_IO_SCHEDULER_ADDED:
702 _HandleIOSchedulerAdded(
703 (system_profiler_io_scheduler_added*)buffer);
704 break;
706 case B_SYSTEM_PROFILER_IO_SCHEDULER_REMOVED:
707 // not so interesting
708 break;
710 case B_SYSTEM_PROFILER_IO_REQUEST_SCHEDULED:
711 _HandleIORequestScheduled((io_request_scheduled*)buffer);
712 break;
713 case B_SYSTEM_PROFILER_IO_REQUEST_FINISHED:
714 _HandleIORequestFinished((io_request_finished*)buffer);
715 break;
716 case B_SYSTEM_PROFILER_IO_OPERATION_STARTED:
717 _HandleIOOperationStarted((io_operation_started*)buffer);
718 break;
719 case B_SYSTEM_PROFILER_IO_OPERATION_FINISHED:
720 _HandleIOOperationFinished((io_operation_finished*)buffer);
721 break;
723 default:
724 printf("unsupported event type %" B_PRIu32 ", size: %" B_PRIuSIZE
725 "\n", event, size);
726 return B_BAD_DATA;
729 return B_OK;
733 bool
734 ModelLoader::_SetThreadEvents()
736 // allocate the threads' events arrays
737 for (int32 i = 0; Model::Thread* thread = fModel->ThreadAt(i); i++) {
738 ExtendedThreadSchedulingState* state
739 = fState->LookupThread(thread->ID());
740 if (!state->AllocateEventArray())
741 return false;
744 // fill the threads' event arrays
745 system_profiler_event_header** events = fModel->Events();
746 size_t eventCount = fModel->CountEvents();
747 for (size_t i = 0; i < eventCount; i++) {
748 system_profiler_event_header* header = events[i];
749 void* buffer = header + 1;
751 switch (header->event) {
752 case B_SYSTEM_PROFILER_THREAD_ADDED:
754 system_profiler_thread_added* event
755 = (system_profiler_thread_added*)buffer;
756 fState->LookupThread(event->thread)->AddEvent(header);
757 break;
760 case B_SYSTEM_PROFILER_THREAD_REMOVED:
762 system_profiler_thread_removed* event
763 = (system_profiler_thread_removed*)buffer;
764 fState->LookupThread(event->thread)->AddEvent(header);
765 break;
768 case B_SYSTEM_PROFILER_THREAD_SCHEDULED:
770 system_profiler_thread_scheduled* event
771 = (system_profiler_thread_scheduled*)buffer;
772 fState->LookupThread(event->thread)->AddEvent(header);
774 if (event->thread != event->previous_thread) {
775 fState->LookupThread(event->previous_thread)
776 ->AddEvent(header);
778 break;
781 case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE:
783 thread_enqueued_in_run_queue* event
784 = (thread_enqueued_in_run_queue*)buffer;
785 fState->LookupThread(event->thread)->AddEvent(header);
786 break;
789 case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE:
791 thread_removed_from_run_queue* event
792 = (thread_removed_from_run_queue*)buffer;
793 fState->LookupThread(event->thread)->AddEvent(header);
794 break;
797 default:
798 break;
802 // transfer the events arrays from the scheduling states to the thread
803 // objects
804 for (int32 i = 0; Model::Thread* thread = fModel->ThreadAt(i); i++) {
805 ExtendedThreadSchedulingState* state
806 = fState->LookupThread(thread->ID());
807 thread->SetEvents(state->Events(), state->CountEvents());
808 state->DetachEvents();
811 return true;
815 bool
816 ModelLoader::_SetThreadIORequests()
818 for (int32 i = 0; Model::Thread* thread = fModel->ThreadAt(i); i++) {
819 ExtendedThreadSchedulingState* state
820 = fState->LookupThread(thread->ID());
821 Model::IORequest** requests;
822 size_t requestCount;
823 if (!state->PrepareThreadIORequests(requests, requestCount))
824 return false;
825 if (requestCount > 0)
826 _SetThreadIORequests(thread, requests, requestCount);
829 return true;
833 void
834 ModelLoader::_SetThreadIORequests(Model::Thread* thread,
835 Model::IORequest** requests, size_t requestCount)
837 // compute some totals
838 int64 ioCount = 0;
839 nanotime_t ioTime = 0;
841 // sort requests by scheduler and start time
842 std::sort(requests, requests + requestCount,
843 Model::IORequest::SchedulerTimeLess);
845 nanotime_t endTime = fBaseTime + fModel->LastEventTime();
847 // compute the summed up I/O times
848 nanotime_t ioStart = requests[0]->scheduledEvent->time;
849 nanotime_t previousEnd = requests[0]->finishedEvent != NULL
850 ? requests[0]->finishedEvent->time : endTime;
851 int32 scheduler = requests[0]->scheduledEvent->scheduler;
853 for (size_t i = 1; i < requestCount; i++) {
854 system_profiler_io_request_scheduled* scheduledEvent
855 = requests[i]->scheduledEvent;
856 if (scheduledEvent->scheduler != scheduler
857 || scheduledEvent->time >= previousEnd) {
858 ioCount++;
859 ioTime += previousEnd - ioStart;
860 ioStart = scheduledEvent->time;
863 previousEnd = requests[i]->finishedEvent != NULL
864 ? requests[i]->finishedEvent->time : endTime;
867 ioCount++;
868 ioTime += previousEnd - ioStart;
870 // sort requests by start time
871 std::sort(requests, requests + requestCount, Model::IORequest::TimeLess);
873 // set the computed values
874 thread->SetIORequests(requests, requestCount);
875 thread->SetIOs(ioCount, ioTime);
879 void
880 ModelLoader::_HandleTeamAdded(system_profiler_team_added* event)
882 if (fModel->AddTeam(event, fState->LastEventTime()) == NULL)
883 throw std::bad_alloc();
887 void
888 ModelLoader::_HandleTeamRemoved(system_profiler_team_removed* event)
890 if (Model::Team* team = fModel->TeamByID(event->team))
891 team->SetDeletionTime(fState->LastEventTime());
892 else {
893 printf("Warning: Removed event for unknown team: %" B_PRId32 "\n",
894 event->team);
899 void
900 ModelLoader::_HandleTeamExec(system_profiler_team_exec* event)
902 // TODO:...
906 void
907 ModelLoader::_HandleThreadAdded(system_profiler_thread_added* event)
909 _AddThread(event)->IncrementEventCount();
913 void
914 ModelLoader::_HandleThreadRemoved(system_profiler_thread_removed* event)
916 ExtendedThreadSchedulingState* thread = fState->LookupThread(event->thread);
917 if (thread == NULL) {
918 printf("Warning: Removed event for unknown thread: %" B_PRId32 "\n",
919 event->thread);
920 thread = _AddUnknownThread(event->thread);
923 thread->thread->SetDeletionTime(fState->LastEventTime());
924 thread->IncrementEventCount();
928 void
929 ModelLoader::_HandleThreadScheduled(uint32 cpu,
930 system_profiler_thread_scheduled* event)
932 _UpdateLastEventTime(event->time);
934 ExtendedThreadSchedulingState* thread = fState->LookupThread(event->thread);
935 if (thread == NULL) {
936 printf("Warning: Schedule event for unknown thread: %" B_PRId32 "\n",
937 event->thread);
938 thread = _AddUnknownThread(event->thread);
939 return;
942 nanotime_t diffTime = fState->LastEventTime() - thread->lastTime;
944 if (thread->state == READY) {
945 // thread scheduled after having been woken up
946 thread->thread->AddLatency(diffTime);
947 } else if (thread->state == PREEMPTED) {
948 // thread scheduled after having been preempted before
949 thread->thread->AddRerun(diffTime);
952 if (thread->state == STILL_RUNNING) {
953 // Thread was running and continues to run.
954 thread->state = RUNNING;
957 if (thread->state != RUNNING) {
958 thread->lastTime = fState->LastEventTime();
959 thread->state = RUNNING;
962 thread->IncrementEventCount();
964 // unscheduled thread
966 if (event->thread == event->previous_thread)
967 return;
969 thread = fState->LookupThread(event->previous_thread);
970 if (thread == NULL) {
971 printf("Warning: Schedule event for unknown previous thread: %" B_PRId32
972 "\n", event->previous_thread);
973 thread = _AddUnknownThread(event->previous_thread);
976 diffTime = fState->LastEventTime() - thread->lastTime;
978 if (thread->state == STILL_RUNNING) {
979 // thread preempted
980 thread->thread->AddPreemption(diffTime);
981 thread->thread->AddRun(diffTime);
982 if (thread->priority == 0)
983 _AddIdleTime(cpu, diffTime);
985 thread->lastTime = fState->LastEventTime();
986 thread->state = PREEMPTED;
987 } else if (thread->state == RUNNING) {
988 // thread starts waiting (it hadn't been added to the run
989 // queue before being unscheduled)
990 thread->thread->AddRun(diffTime);
991 if (thread->priority == 0)
992 _AddIdleTime(cpu, diffTime);
994 if (event->previous_thread_state == B_THREAD_WAITING) {
995 addr_t waitObject = event->previous_thread_wait_object;
996 switch (event->previous_thread_wait_object_type) {
997 case THREAD_BLOCK_TYPE_SNOOZE:
998 case THREAD_BLOCK_TYPE_SIGNAL:
999 waitObject = 0;
1000 break;
1001 case THREAD_BLOCK_TYPE_SEMAPHORE:
1002 case THREAD_BLOCK_TYPE_CONDITION_VARIABLE:
1003 case THREAD_BLOCK_TYPE_MUTEX:
1004 case THREAD_BLOCK_TYPE_RW_LOCK:
1005 case THREAD_BLOCK_TYPE_OTHER:
1006 default:
1007 break;
1010 _AddThreadWaitObject(thread,
1011 event->previous_thread_wait_object_type, waitObject);
1014 thread->lastTime = fState->LastEventTime();
1015 thread->state = WAITING;
1016 } else if (thread->state == UNKNOWN) {
1017 uint32 threadState = event->previous_thread_state;
1018 if (threadState == B_THREAD_WAITING
1019 || threadState == B_THREAD_SUSPENDED) {
1020 thread->lastTime = fState->LastEventTime();
1021 thread->state = WAITING;
1022 } else if (threadState == B_THREAD_READY) {
1023 thread->lastTime = fState->LastEventTime();
1024 thread->state = PREEMPTED;
1028 thread->IncrementEventCount();
1032 void
1033 ModelLoader::_HandleThreadEnqueuedInRunQueue(
1034 thread_enqueued_in_run_queue* event)
1036 _UpdateLastEventTime(event->time);
1038 ExtendedThreadSchedulingState* thread = fState->LookupThread(event->thread);
1039 if (thread == NULL) {
1040 printf("Warning: Enqueued in run queue event for unknown thread: %"
1041 B_PRId32 "\n", event->thread);
1042 thread = _AddUnknownThread(event->thread);
1045 if (thread->state == RUNNING || thread->state == STILL_RUNNING) {
1046 // Thread was running and is reentered into the run queue. This
1047 // is done by the scheduler, if the thread remains ready.
1048 thread->state = STILL_RUNNING;
1049 } else {
1050 // Thread was waiting and is ready now.
1051 nanotime_t diffTime = fState->LastEventTime() - thread->lastTime;
1052 if (thread->waitObject != NULL) {
1053 thread->waitObject->AddWait(diffTime);
1054 thread->waitObject = NULL;
1055 thread->thread->AddWait(diffTime);
1056 } else if (thread->state != UNKNOWN)
1057 thread->thread->AddUnspecifiedWait(diffTime);
1059 thread->lastTime = fState->LastEventTime();
1060 thread->state = READY;
1063 thread->priority = event->priority;
1065 thread->IncrementEventCount();
1069 void
1070 ModelLoader::_HandleThreadRemovedFromRunQueue(uint32 cpu,
1071 thread_removed_from_run_queue* event)
1073 _UpdateLastEventTime(event->time);
1075 ExtendedThreadSchedulingState* thread = fState->LookupThread(event->thread);
1076 if (thread == NULL) {
1077 printf("Warning: Removed from run queue event for unknown thread: "
1078 "%" B_PRId32 "\n", event->thread);
1079 thread = _AddUnknownThread(event->thread);
1082 // This really only happens when the thread priority is changed
1083 // while the thread is ready.
1085 nanotime_t diffTime = fState->LastEventTime() - thread->lastTime;
1086 if (thread->state == RUNNING) {
1087 // This should never happen.
1088 thread->thread->AddRun(diffTime);
1089 if (thread->priority == 0)
1090 _AddIdleTime(cpu, diffTime);
1091 } else if (thread->state == READY || thread->state == PREEMPTED) {
1092 // Not really correct, but the case is rare and we keep it
1093 // simple.
1094 thread->thread->AddUnspecifiedWait(diffTime);
1097 thread->lastTime = fState->LastEventTime();
1098 thread->state = WAITING;
1100 thread->IncrementEventCount();
1104 void
1105 ModelLoader::_HandleWaitObjectInfo(system_profiler_wait_object_info* event)
1107 if (fModel->AddWaitObject(event, NULL) == NULL)
1108 throw std::bad_alloc();
1112 void
1113 ModelLoader::_HandleIOSchedulerAdded(system_profiler_io_scheduler_added* event)
1115 Model::IOScheduler* scheduler = fModel->IOSchedulerByID(event->scheduler);
1116 if (scheduler != NULL) {
1117 printf("Warning: Duplicate added event for I/O scheduler %" B_PRId32
1118 "\n", event->scheduler);
1119 return;
1122 if (fModel->AddIOScheduler(event) == NULL)
1123 throw std::bad_alloc();
1127 void
1128 ModelLoader::_HandleIORequestScheduled(io_request_scheduled* event)
1130 IORequest* request = fIORequests->Lookup(event->request);
1131 if (request != NULL) {
1132 printf("Warning: Duplicate schedule event for I/O request %p\n",
1133 event->request);
1134 return;
1137 ExtendedThreadSchedulingState* thread = fState->LookupThread(event->thread);
1138 if (thread == NULL) {
1139 printf("Warning: I/O request for unknown thread %" B_PRId32 "\n",
1140 event->thread);
1141 thread = _AddUnknownThread(event->thread);
1144 if (fModel->IOSchedulerByID(event->scheduler) == NULL) {
1145 printf("Warning: I/O requests for unknown scheduler %" B_PRId32 "\n",
1146 event->scheduler);
1147 // TODO: Add state for unknown scheduler, as we do for threads.
1148 return;
1151 request = new(std::nothrow) IORequest(event);
1152 if (request == NULL)
1153 throw std::bad_alloc();
1155 fIORequests->Insert(request);
1156 thread->AddIORequest(request);
1160 void
1161 ModelLoader::_HandleIORequestFinished(io_request_finished* event)
1163 IORequest* request = fIORequests->Lookup(event->request);
1164 if (request == NULL)
1165 return;
1167 request->finishedEvent = event;
1169 fIORequests->Remove(request);
1170 fState->LookupThread(request->scheduledEvent->thread)
1171 ->IORequestFinished(request);
1175 void
1176 ModelLoader::_HandleIOOperationStarted(io_operation_started* event)
1178 IORequest* request = fIORequests->Lookup(event->request);
1179 if (request == NULL) {
1180 printf("Warning: I/O request for operation %p not found\n",
1181 event->operation);
1182 return;
1185 IOOperation* operation = new(std::nothrow) IOOperation(event);
1186 if (operation == NULL)
1187 throw std::bad_alloc();
1189 request->AddOperation(operation);
1193 void
1194 ModelLoader::_HandleIOOperationFinished(io_operation_finished* event)
1196 IORequest* request = fIORequests->Lookup(event->request);
1197 if (request == NULL) {
1198 printf("Warning: I/O request for operation %p not found\n",
1199 event->operation);
1200 return;
1203 IOOperation* operation = request->FindOperation(event->operation);
1204 if (operation == NULL) {
1205 printf("Warning: operation %p not found\n", event->operation);
1206 return;
1209 operation->finishedEvent = event;
1213 ModelLoader::ExtendedThreadSchedulingState*
1214 ModelLoader::_AddThread(system_profiler_thread_added* event)
1216 // do we know the thread already?
1217 ExtendedThreadSchedulingState* info = fState->LookupThread(event->thread);
1218 if (info != NULL) {
1219 printf("Warning: Duplicate thread added event for thread %" B_PRId32
1220 "\n", event->thread);
1221 return info;
1224 // add the thread to the model
1225 Model::Thread* thread = fModel->AddThread(event, fState->LastEventTime());
1226 if (thread == NULL)
1227 throw std::bad_alloc();
1229 // create and add a ThreadSchedulingState
1230 info = new(std::nothrow) ExtendedThreadSchedulingState(thread);
1231 if (info == NULL)
1232 throw std::bad_alloc();
1234 // TODO: The priority is missing from the system_profiler_thread_added
1235 // struct. For now guess at least whether this is an idle thread.
1236 if (strncmp(event->name, "idle thread", strlen("idle thread")) == 0)
1237 info->priority = 0;
1238 else
1239 info->priority = B_NORMAL_PRIORITY;
1241 fState->InsertThread(info);
1243 return info;
1247 ModelLoader::ExtendedThreadSchedulingState*
1248 ModelLoader::_AddUnknownThread(thread_id threadID)
1250 // create a dummy "add thread" event
1251 system_profiler_thread_added* event = (system_profiler_thread_added*)
1252 malloc(sizeof(system_profiler_thread_added));
1253 if (event == NULL)
1254 throw std::bad_alloc();
1256 if (!fModel->AddAssociatedData(event)) {
1257 free(event);
1258 throw std::bad_alloc();
1261 try {
1262 event->team = _AddUnknownTeam()->ID();
1263 event->thread = threadID;
1264 snprintf(event->name, sizeof(event->name), "unknown thread %" B_PRId32,
1265 threadID);
1267 // add the thread to the model
1268 ExtendedThreadSchedulingState* state = _AddThread(event);
1269 return state;
1270 } catch (...) {
1271 throw;
1275 Model::Team*
1276 ModelLoader::_AddUnknownTeam()
1278 team_id teamID = 0;
1279 Model::Team* team = fModel->TeamByID(teamID);
1280 if (team != NULL)
1281 return team;
1283 // create a dummy "add team" event
1284 static const char* const kUnknownThreadsTeamName = "unknown threads";
1285 size_t nameLength = strlen(kUnknownThreadsTeamName);
1287 system_profiler_team_added* event = (system_profiler_team_added*)
1288 malloc(sizeof(system_profiler_team_added) + nameLength);
1289 if (event == NULL)
1290 throw std::bad_alloc();
1292 event->team = teamID;
1293 event->args_offset = nameLength;
1294 strlcpy(event->name, kUnknownThreadsTeamName, nameLength + 1);
1296 // add the team to the model
1297 team = fModel->AddTeam(event, fState->LastEventTime());
1298 if (team == NULL)
1299 throw std::bad_alloc();
1301 return team;
1305 void
1306 ModelLoader::_AddThreadWaitObject(ExtendedThreadSchedulingState* thread,
1307 uint32 type, addr_t object)
1309 Model::WaitObjectGroup* waitObjectGroup
1310 = fModel->WaitObjectGroupFor(type, object);
1311 if (waitObjectGroup == NULL) {
1312 // The algorithm should prevent this case.
1313 printf("ModelLoader::_AddThreadWaitObject(): Unknown wait object: type:"
1314 " %" B_PRIu32 ", " "object: %#" B_PRIxADDR "\n", type, object);
1315 return;
1318 Model::WaitObject* waitObject = waitObjectGroup->MostRecentWaitObject();
1320 Model::ThreadWaitObjectGroup* threadWaitObjectGroup
1321 = fModel->ThreadWaitObjectGroupFor(thread->ID(), type, object);
1323 if (threadWaitObjectGroup == NULL
1324 || threadWaitObjectGroup->MostRecentWaitObject() != waitObject) {
1325 Model::ThreadWaitObject* threadWaitObject
1326 = fModel->AddThreadWaitObject(thread->ID(), waitObject,
1327 &threadWaitObjectGroup);
1328 if (threadWaitObject == NULL)
1329 throw std::bad_alloc();
1332 thread->waitObject = threadWaitObjectGroup->MostRecentThreadWaitObject();
1336 void
1337 ModelLoader::_AddIdleTime(uint32 cpu, nanotime_t time)
1339 fCPUInfos[cpu].idleTime += time;