2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
7 #include "ModelLoader.h"
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"
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
)
38 referenced_object
= 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
{
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
),
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
;
90 IORequest(io_request_scheduled
* scheduledEvent
)
92 scheduledEvent(scheduledEvent
),
100 while (IOOperation
* operation
= operations
.RemoveHead())
104 void AddOperation(IOOperation
* operation
)
106 operations
.Add(operation
);
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
)
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
)
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
;
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
),
181 ~ExtendedThreadSchedulingState()
185 while (IORequest
* request
= fIORequests
.RemoveHead())
187 while (IORequest
* request
= fPendingIORequests
.RemoveHead())
191 system_profiler_event_header
** Events() const
196 size_t CountEvents() const
201 system_profiler_event_header
** DetachEvents()
203 system_profiler_event_header
** events
= fEvents
;
208 void IncrementEventCount()
213 void AddEvent(system_profiler_event_header
* event
)
215 fEvents
[fEventIndex
++] = event
;
218 bool AllocateEventArray()
220 if (fEventCount
== 0)
223 fEvents
= new(std::nothrow
) system_profiler_event_header
*[fEventCount
];
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) {
253 Model::IORequest
** requests
254 = new(std::nothrow
) Model::IORequest
*[requestCount
];
255 if (requests
== NULL
)
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();
269 requests
[index
++] = modelRequest
;
272 _requests
= requests
;
273 _requestCount
= requestCount
;
278 system_profiler_event_header
** fEvents
;
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
;
300 virtual void DeleteThread(Model::ThreadSchedulingState
* thread
)
302 delete static_cast<ExtendedThreadSchedulingState
*>(thread
);
307 // #pragma mark - ModelLoader
311 ModelLoader::_UpdateLastEventTime(nanotime_t 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
),
327 fDataSource(dataSource
),
335 ModelLoader::~ModelLoader()
346 ModelLoader::DetachModel()
348 AutoLocker
<BLocker
> locker(fLock
);
350 if (fModel
== NULL
|| fLoading
)
353 Model
* model
= fModel
;
361 ModelLoader::PrepareForLoading()
363 if (fModel
!= NULL
|| fDataSource
== NULL
)
366 // create and init the state
367 fState
= new(std::nothrow
) ExtendedSchedulingState
;
371 status_t error
= fState
->Init();
375 // create CPU info array
376 fCPUInfos
= new(std::nothrow
) CPUInfo
[kMaxCPUCount
];
377 if (fCPUInfos
== NULL
)
380 // create IORequest hash table
381 fIORequests
= new(std::nothrow
) IORequestTable
;
382 if (fIORequests
== NULL
|| fIORequests
->Init() != B_OK
)
401 ModelLoader::FinishLoading(bool success
)
422 // read the complete data into memory
424 size_t eventDataSize
;
425 status_t error
= _ReadDebugEvents(&eventData
, &eventDataSize
);
428 MemoryDeleter
eventDataDeleter(eventData
);
430 // create a debug event array
431 system_profiler_event_header
** events
;
433 error
= _CreateDebugEventArray(eventData
, eventDataSize
, events
,
437 ArrayDeleter
<system_profiler_event_header
*> eventsDeleter(events
);
439 // get the data source name
440 BString dataSourceName
;
441 fDataSource
->GetName(dataSourceName
);
444 fModel
= new(std::nothrow
) Model(dataSourceName
.String(), eventData
,
445 eventDataSize
, events
, eventCount
);
448 eventDataDeleter
.Detach();
449 eventsDeleter
.Detach();
451 // create a debug input stream
452 BDebugEventInputStream input
;
453 error
= input
.SetTo(eventData
, eventDataSize
, false);
457 // add the snooze and signal wait objects to the model
458 if (fModel
->AddWaitObject(&kSnoozeWaitObjectInfo
, NULL
) == NULL
459 || fModel
->AddWaitObject(&kSignalWaitObjectInfo
, NULL
) == NULL
) {
463 // process the events
475 ssize_t bufferSize
= input
.ReadNextEvent(&event
, &cpu
, &buffer
,
483 status_t error
= _ProcessEvent(event
, cpu
, buffer
, bufferSize
);
487 if (cpu
> fMaxCPUIndex
) {
488 if (cpu
+ 1 > kMaxCPUCount
)
493 // periodically check whether we're supposed to abort
494 if (++count
% 32 == 0) {
495 AutoLocker
<BLocker
> locker(fLock
);
500 // periodically add scheduling snapshots
501 if (count
% kSchedulingSnapshotInterval
== 0)
502 fModel
->AddSchedulingStateSnapshot(*fState
, offset
);
505 if (!fModel
->SetCPUCount(fMaxCPUIndex
+ 1))
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())
516 fModel
->LoadingFinished();
523 ModelLoader::_ReadDebugEvents(void** _eventData
, size_t* _size
)
525 // get a BDataIO from the data source
527 status_t error
= fDataSource
->CreateDataIO(&io
);
530 ObjectDeleter
<BDataIO
> dataIOtDeleter(io
);
532 // First we need to find out how large a buffer to allocate.
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();
543 error
= positionIO
->GetSize(&fileSize
);
547 size
= fileSize
- currentPos
;
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
);
557 MemoryDeleter
bufferDeleter(buffer
);
561 ssize_t bytesRead
= io
->Read(buffer
, kBufferSize
);
570 // we've got the size -- recreate the BDataIO
571 dataIOtDeleter
.Delete();
572 error
= fDataSource
->CreateDataIO(&io
);
575 dataIOtDeleter
.SetTo(io
);
578 // allocate the data buffer
579 void* data
= malloc(size
);
582 MemoryDeleter
dataDeleter(data
);
585 ssize_t bytesRead
= io
->Read(data
, size
);
588 if ((size_t)bytesRead
!= size
)
591 dataDeleter
.Detach();
599 ModelLoader::_CreateDebugEventArray(void* eventData
, size_t eventDataSize
,
600 system_profiler_event_header
**& _events
, size_t& _eventCount
)
603 BDebugEventInputStream input
;
604 status_t error
= input
.SetTo(eventData
, eventDataSize
, false);
608 size_t eventCount
= 0;
614 ssize_t bufferSize
= input
.ReadNextEvent(&event
, &cpu
, &buffer
, NULL
);
624 system_profiler_event_header
** events
= new(std::nothrow
)
625 system_profiler_event_header
*[eventCount
];
629 // populate the array
630 error
= input
.SetTo(eventData
, eventDataSize
, false);
636 size_t eventIndex
= 0;
643 input
.ReadNextEvent(&event
, &cpu
, &buffer
, &offset
);
648 = (system_profiler_event_header
*)((uint8
*)eventData
+ offset
);
652 _eventCount
= eventCount
;
658 ModelLoader::_ProcessEvent(uint32 event
, uint32 cpu
, const void* buffer
,
662 case B_SYSTEM_PROFILER_TEAM_ADDED
:
663 _HandleTeamAdded((system_profiler_team_added
*)buffer
);
666 case B_SYSTEM_PROFILER_TEAM_REMOVED
:
667 _HandleTeamRemoved((system_profiler_team_removed
*)buffer
);
670 case B_SYSTEM_PROFILER_TEAM_EXEC
:
671 _HandleTeamExec((system_profiler_team_exec
*)buffer
);
674 case B_SYSTEM_PROFILER_THREAD_ADDED
:
675 _HandleThreadAdded((system_profiler_thread_added
*)buffer
);
678 case B_SYSTEM_PROFILER_THREAD_REMOVED
:
679 _HandleThreadRemoved((system_profiler_thread_removed
*)buffer
);
682 case B_SYSTEM_PROFILER_THREAD_SCHEDULED
:
683 _HandleThreadScheduled(cpu
,
684 (system_profiler_thread_scheduled
*)buffer
);
687 case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE
:
688 _HandleThreadEnqueuedInRunQueue(
689 (thread_enqueued_in_run_queue
*)buffer
);
692 case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE
:
693 _HandleThreadRemovedFromRunQueue(cpu
,
694 (thread_removed_from_run_queue
*)buffer
);
697 case B_SYSTEM_PROFILER_WAIT_OBJECT_INFO
:
698 _HandleWaitObjectInfo((system_profiler_wait_object_info
*)buffer
);
701 case B_SYSTEM_PROFILER_IO_SCHEDULER_ADDED
:
702 _HandleIOSchedulerAdded(
703 (system_profiler_io_scheduler_added
*)buffer
);
706 case B_SYSTEM_PROFILER_IO_SCHEDULER_REMOVED
:
707 // not so interesting
710 case B_SYSTEM_PROFILER_IO_REQUEST_SCHEDULED
:
711 _HandleIORequestScheduled((io_request_scheduled
*)buffer
);
713 case B_SYSTEM_PROFILER_IO_REQUEST_FINISHED
:
714 _HandleIORequestFinished((io_request_finished
*)buffer
);
716 case B_SYSTEM_PROFILER_IO_OPERATION_STARTED
:
717 _HandleIOOperationStarted((io_operation_started
*)buffer
);
719 case B_SYSTEM_PROFILER_IO_OPERATION_FINISHED
:
720 _HandleIOOperationFinished((io_operation_finished
*)buffer
);
724 printf("unsupported event type %" B_PRIu32
", size: %" B_PRIuSIZE
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())
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
);
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
);
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
)
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
);
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
);
802 // transfer the events arrays from the scheduling states to the thread
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();
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
;
823 if (!state
->PrepareThreadIORequests(requests
, requestCount
))
825 if (requestCount
> 0)
826 _SetThreadIORequests(thread
, requests
, requestCount
);
834 ModelLoader::_SetThreadIORequests(Model::Thread
* thread
,
835 Model::IORequest
** requests
, size_t requestCount
)
837 // compute some totals
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
) {
859 ioTime
+= previousEnd
- ioStart
;
860 ioStart
= scheduledEvent
->time
;
863 previousEnd
= requests
[i
]->finishedEvent
!= NULL
864 ? requests
[i
]->finishedEvent
->time
: endTime
;
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
);
880 ModelLoader::_HandleTeamAdded(system_profiler_team_added
* event
)
882 if (fModel
->AddTeam(event
, fState
->LastEventTime()) == NULL
)
883 throw std::bad_alloc();
888 ModelLoader::_HandleTeamRemoved(system_profiler_team_removed
* event
)
890 if (Model::Team
* team
= fModel
->TeamByID(event
->team
))
891 team
->SetDeletionTime(fState
->LastEventTime());
893 printf("Warning: Removed event for unknown team: %" B_PRId32
"\n",
900 ModelLoader::_HandleTeamExec(system_profiler_team_exec
* event
)
907 ModelLoader::_HandleThreadAdded(system_profiler_thread_added
* event
)
909 _AddThread(event
)->IncrementEventCount();
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",
920 thread
= _AddUnknownThread(event
->thread
);
923 thread
->thread
->SetDeletionTime(fState
->LastEventTime());
924 thread
->IncrementEventCount();
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",
938 thread
= _AddUnknownThread(event
->thread
);
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
)
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
) {
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
:
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
:
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();
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
;
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();
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
1094 thread
->thread
->AddUnspecifiedWait(diffTime
);
1097 thread
->lastTime
= fState
->LastEventTime();
1098 thread
->state
= WAITING
;
1100 thread
->IncrementEventCount();
1105 ModelLoader::_HandleWaitObjectInfo(system_profiler_wait_object_info
* event
)
1107 if (fModel
->AddWaitObject(event
, NULL
) == NULL
)
1108 throw std::bad_alloc();
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
);
1122 if (fModel
->AddIOScheduler(event
) == NULL
)
1123 throw std::bad_alloc();
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",
1137 ExtendedThreadSchedulingState
* thread
= fState
->LookupThread(event
->thread
);
1138 if (thread
== NULL
) {
1139 printf("Warning: I/O request for unknown thread %" B_PRId32
"\n",
1141 thread
= _AddUnknownThread(event
->thread
);
1144 if (fModel
->IOSchedulerByID(event
->scheduler
) == NULL
) {
1145 printf("Warning: I/O requests for unknown scheduler %" B_PRId32
"\n",
1147 // TODO: Add state for unknown scheduler, as we do for threads.
1151 request
= new(std::nothrow
) IORequest(event
);
1152 if (request
== NULL
)
1153 throw std::bad_alloc();
1155 fIORequests
->Insert(request
);
1156 thread
->AddIORequest(request
);
1161 ModelLoader::_HandleIORequestFinished(io_request_finished
* event
)
1163 IORequest
* request
= fIORequests
->Lookup(event
->request
);
1164 if (request
== NULL
)
1167 request
->finishedEvent
= event
;
1169 fIORequests
->Remove(request
);
1170 fState
->LookupThread(request
->scheduledEvent
->thread
)
1171 ->IORequestFinished(request
);
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",
1185 IOOperation
* operation
= new(std::nothrow
) IOOperation(event
);
1186 if (operation
== NULL
)
1187 throw std::bad_alloc();
1189 request
->AddOperation(operation
);
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",
1203 IOOperation
* operation
= request
->FindOperation(event
->operation
);
1204 if (operation
== NULL
) {
1205 printf("Warning: operation %p not found\n", event
->operation
);
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
);
1219 printf("Warning: Duplicate thread added event for thread %" B_PRId32
1220 "\n", event
->thread
);
1224 // add the thread to the model
1225 Model::Thread
* thread
= fModel
->AddThread(event
, fState
->LastEventTime());
1227 throw std::bad_alloc();
1229 // create and add a ThreadSchedulingState
1230 info
= new(std::nothrow
) ExtendedThreadSchedulingState(thread
);
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)
1239 info
->priority
= B_NORMAL_PRIORITY
;
1241 fState
->InsertThread(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
));
1254 throw std::bad_alloc();
1256 if (!fModel
->AddAssociatedData(event
)) {
1258 throw std::bad_alloc();
1262 event
->team
= _AddUnknownTeam()->ID();
1263 event
->thread
= threadID
;
1264 snprintf(event
->name
, sizeof(event
->name
), "unknown thread %" B_PRId32
,
1267 // add the thread to the model
1268 ExtendedThreadSchedulingState
* state
= _AddThread(event
);
1276 ModelLoader::_AddUnknownTeam()
1279 Model::Team
* team
= fModel
->TeamByID(teamID
);
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
);
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());
1299 throw std::bad_alloc();
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
);
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();
1337 ModelLoader::_AddIdleTime(uint32 cpu
, nanotime_t time
)
1339 fCPUInfos
[cpu
].idleTime
+= time
;