1 /* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "ModelLoader.h" 8 9 #include <stdio.h> 10 #include <string.h> 11 12 #include <algorithm> 13 #include <new> 14 15 #include <AutoDeleter.h> 16 #include <AutoLocker.h> 17 #include <DebugEventStream.h> 18 19 #include <system_profiler_defs.h> 20 #include <thread_defs.h> 21 22 #include "DataSource.h" 23 #include "MessageCodes.h" 24 #include "Model.h" 25 26 27 // add a scheduling state snapshot every x events 28 static const uint32 kSchedulingSnapshotInterval = 1024; 29 30 static const uint32 kMaxCPUCount = 1024; 31 32 33 struct SimpleWaitObjectInfo : system_profiler_wait_object_info { 34 SimpleWaitObjectInfo(uint32 type) 35 { 36 this->type = type; 37 object = 0; 38 referenced_object = 0; 39 name[0] = '\0'; 40 } 41 }; 42 43 44 static const SimpleWaitObjectInfo kSnoozeWaitObjectInfo( 45 THREAD_BLOCK_TYPE_SNOOZE); 46 static const SimpleWaitObjectInfo kSignalWaitObjectInfo( 47 THREAD_BLOCK_TYPE_SIGNAL); 48 49 50 // #pragma mark - CPUInfo 51 52 53 struct ModelLoader::CPUInfo { 54 nanotime_t idleTime; 55 56 CPUInfo() 57 : 58 idleTime(0) 59 { 60 } 61 }; 62 63 64 // #pragma mark - IOOperation 65 66 67 struct ModelLoader::IOOperation : DoublyLinkedListLinkImpl<IOOperation> { 68 io_operation_started* startedEvent; 69 io_operation_finished* finishedEvent; 70 71 IOOperation(io_operation_started* startedEvent) 72 : 73 startedEvent(startedEvent), 74 finishedEvent(NULL) 75 { 76 } 77 }; 78 79 80 // #pragma mark - IORequest 81 82 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; 89 90 IORequest(io_request_scheduled* scheduledEvent) 91 : 92 scheduledEvent(scheduledEvent), 93 finishedEvent(NULL), 94 operationCount(0) 95 { 96 } 97 98 ~IORequest() 99 { 100 while (IOOperation* operation = operations.RemoveHead()) 101 delete operation; 102 } 103 104 void AddOperation(IOOperation* operation) 105 { 106 operations.Add(operation); 107 operationCount++; 108 } 109 110 IOOperation* FindOperation(void* address) const 111 { 112 for (IOOperationList::ConstReverseIterator it 113 = operations.GetReverseIterator(); 114 IOOperation* operation = it.Next();) { 115 if (operation->startedEvent->operation == address) 116 return operation; 117 } 118 119 return NULL; 120 } 121 122 Model::IORequest* CreateModelRequest() const 123 { 124 size_t operationCount = operations.Count(); 125 126 Model::IORequest* modelRequest = Model::IORequest::Create( 127 scheduledEvent, finishedEvent, operationCount); 128 if (modelRequest == NULL) 129 return NULL; 130 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; 138 } 139 140 return modelRequest; 141 } 142 }; 143 144 145 // #pragma mark - IORequestHashDefinition 146 147 148 struct ModelLoader::IORequestHashDefinition { 149 typedef void* KeyType; 150 typedef IORequest ValueType; 151 152 size_t HashKey(KeyType key) const 153 { return (size_t)key; } 154 155 size_t Hash(const IORequest* value) const 156 { return HashKey(value->scheduledEvent->request); } 157 158 bool Compare(KeyType key, const IORequest* value) const 159 { return key == value->scheduledEvent->request; } 160 161 IORequest*& GetLink(IORequest* value) const 162 { return value->hashNext; } 163 }; 164 165 166 // #pragma mark - ExtendedThreadSchedulingState 167 168 169 struct ModelLoader::ExtendedThreadSchedulingState 170 : Model::ThreadSchedulingState { 171 172 ExtendedThreadSchedulingState(Model::Thread* thread) 173 : 174 Model::ThreadSchedulingState(thread), 175 fEvents(NULL), 176 fEventIndex(0), 177 fEventCount(0) 178 { 179 } 180 181 ~ExtendedThreadSchedulingState() 182 { 183 delete[] fEvents; 184 185 while (IORequest* request = fIORequests.RemoveHead()) 186 delete request; 187 while (IORequest* request = fPendingIORequests.RemoveHead()) 188 delete request; 189 } 190 191 system_profiler_event_header** Events() const 192 { 193 return fEvents; 194 } 195 196 size_t CountEvents() const 197 { 198 return fEventCount; 199 } 200 201 system_profiler_event_header** DetachEvents() 202 { 203 system_profiler_event_header** events = fEvents; 204 fEvents = NULL; 205 return events; 206 } 207 208 void IncrementEventCount() 209 { 210 fEventCount++; 211 } 212 213 void AddEvent(system_profiler_event_header* event) 214 { 215 fEvents[fEventIndex++] = event; 216 } 217 218 bool AllocateEventArray() 219 { 220 if (fEventCount == 0) 221 return true; 222 223 fEvents = new(std::nothrow) system_profiler_event_header*[fEventCount]; 224 if (fEvents == NULL) 225 return false; 226 227 return true; 228 } 229 230 void AddIORequest(IORequest* request) 231 { 232 fPendingIORequests.Add(request); 233 } 234 235 void IORequestFinished(IORequest* request) 236 { 237 fPendingIORequests.Remove(request); 238 fIORequests.Add(request); 239 } 240 241 bool PrepareThreadIORequests(Model::IORequest**& _requests, 242 size_t& _requestCount) 243 { 244 fIORequests.MoveFrom(&fPendingIORequests); 245 size_t requestCount = fIORequests.Count(); 246 247 if (requestCount == 0) { 248 _requests = NULL; 249 _requestCount = 0; 250 return true; 251 } 252 253 Model::IORequest** requests 254 = new(std::nothrow) Model::IORequest*[requestCount]; 255 if (requests == NULL) 256 return false; 257 258 size_t index = 0; 259 while (IORequest* request = fIORequests.RemoveHead()) { 260 ObjectDeleter<IORequest> requestDeleter(request); 261 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; 267 } 268 269 requests[index++] = modelRequest; 270 } 271 272 _requests = requests; 273 _requestCount = requestCount; 274 return true; 275 } 276 277 private: 278 system_profiler_event_header** fEvents; 279 size_t fEventIndex; 280 size_t fEventCount; 281 IORequestList fIORequests; 282 IORequestList fPendingIORequests; 283 }; 284 285 286 // #pragma mark - ExtendedSchedulingState 287 288 289 struct ModelLoader::ExtendedSchedulingState : Model::SchedulingState { 290 inline ExtendedThreadSchedulingState* LookupThread(thread_id threadID) const 291 { 292 Model::ThreadSchedulingState* thread 293 = Model::SchedulingState::LookupThread(threadID); 294 return thread != NULL 295 ? static_cast<ExtendedThreadSchedulingState*>(thread) : NULL; 296 } 297 298 299 protected: 300 virtual void DeleteThread(Model::ThreadSchedulingState* thread) 301 { 302 delete static_cast<ExtendedThreadSchedulingState*>(thread); 303 } 304 }; 305 306 307 // #pragma mark - ModelLoader 308 309 310 inline void 311 ModelLoader::_UpdateLastEventTime(nanotime_t time) 312 { 313 if (fBaseTime < 0) { 314 fBaseTime = time; 315 fModel->SetBaseTime(time); 316 } 317 318 fState->SetLastEventTime(time - fBaseTime); 319 } 320 321 322 ModelLoader::ModelLoader(DataSource* dataSource, 323 const BMessenger& target, void* targetCookie) 324 : 325 AbstractModelLoader(target, targetCookie), 326 fModel(NULL), 327 fDataSource(dataSource), 328 fCPUInfos(NULL), 329 fState(NULL), 330 fIORequests(NULL) 331 { 332 } 333 334 335 ModelLoader::~ModelLoader() 336 { 337 delete[] fCPUInfos; 338 delete fDataSource; 339 delete fModel; 340 delete fState; 341 delete fIORequests; 342 } 343 344 345 Model* 346 ModelLoader::DetachModel() 347 { 348 AutoLocker<BLocker> locker(fLock); 349 350 if (fModel == NULL || fLoading) 351 return NULL; 352 353 Model* model = fModel; 354 fModel = NULL; 355 356 return model; 357 } 358 359 360 status_t 361 ModelLoader::PrepareForLoading() 362 { 363 if (fModel != NULL || fDataSource == NULL) 364 return B_BAD_VALUE; 365 366 // create and init the state 367 fState = new(std::nothrow) ExtendedSchedulingState; 368 if (fState == NULL) 369 return B_NO_MEMORY; 370 371 status_t error = fState->Init(); 372 if (error != B_OK) 373 return error; 374 375 // create CPU info array 376 fCPUInfos = new(std::nothrow) CPUInfo[kMaxCPUCount]; 377 if (fCPUInfos == NULL) 378 return B_NO_MEMORY; 379 380 // create IORequest hash table 381 fIORequests = new(std::nothrow) IORequestTable; 382 if (fIORequests == NULL || fIORequests->Init() != B_OK) 383 return B_NO_MEMORY; 384 385 return B_OK; 386 } 387 388 389 status_t 390 ModelLoader::Load() 391 { 392 try { 393 return _Load(); 394 } catch(...) { 395 return B_ERROR; 396 } 397 } 398 399 400 void 401 ModelLoader::FinishLoading(bool success) 402 { 403 delete fState; 404 fState = NULL; 405 406 if (!success) { 407 delete fModel; 408 fModel = NULL; 409 } 410 411 delete[] fCPUInfos; 412 fCPUInfos = NULL; 413 414 delete fIORequests; 415 fIORequests = NULL; 416 } 417 418 419 status_t 420 ModelLoader::_Load() 421 { 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); 429 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); 438 439 // get the data source name 440 BString dataSourceName; 441 fDataSource->GetName(dataSourceName); 442 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(); 450 451 // create a debug input stream 452 BDebugEventInputStream input; 453 error = input.SetTo(eventData, eventDataSize, false); 454 if (error != B_OK) 455 return error; 456 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; 461 } 462 463 // process the events 464 fMaxCPUIndex = 0; 465 fState->Clear(); 466 fBaseTime = -1; 467 uint64 count = 0; 468 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; 481 482 // process the event 483 status_t error = _ProcessEvent(event, cpu, buffer, bufferSize); 484 if (error != B_OK) 485 return error; 486 487 if (cpu > fMaxCPUIndex) { 488 if (cpu + 1 > kMaxCPUCount) 489 return B_BAD_DATA; 490 fMaxCPUIndex = cpu; 491 } 492 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; 498 } 499 500 // periodically add scheduling snapshots 501 if (count % kSchedulingSnapshotInterval == 0) 502 fModel->AddSchedulingStateSnapshot(*fState, offset); 503 } 504 505 if (!fModel->SetCPUCount(fMaxCPUIndex + 1)) 506 return B_NO_MEMORY; 507 508 for (uint32 i = 0; i <= fMaxCPUIndex; i++) 509 fModel->CPUAt(i)->SetIdleTime(fCPUInfos[i].idleTime); 510 511 fModel->SetLastEventTime(fState->LastEventTime()); 512 513 if (!_SetThreadEvents() || !_SetThreadIORequests()) 514 return B_NO_MEMORY; 515 516 fModel->LoadingFinished(); 517 518 return B_OK; 519 } 520 521 522 status_t 523 ModelLoader::_ReadDebugEvents(void** _eventData, size_t* _size) 524 { 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); 531 532 // First we need to find out how large a buffer to allocate. 533 size_t size; 534 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; 541 542 off_t fileSize; 543 error = positionIO->GetSize(&fileSize); 544 if (error != B_OK) 545 return error; 546 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 551 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); 558 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; 566 567 size += bytesRead; 568 } 569 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); 576 } 577 578 // allocate the data buffer 579 void* data = malloc(size); 580 if (data == NULL) 581 return B_NO_MEMORY; 582 MemoryDeleter dataDeleter(data); 583 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; 590 591 dataDeleter.Detach(); 592 *_eventData = data; 593 *_size = size; 594 return B_OK; 595 } 596 597 598 status_t 599 ModelLoader::_CreateDebugEventArray(void* eventData, size_t eventDataSize, 600 system_profiler_event_header**& _events, size_t& _eventCount) 601 { 602 // count the events 603 BDebugEventInputStream input; 604 status_t error = input.SetTo(eventData, eventDataSize, false); 605 if (error != B_OK) 606 return error; 607 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; 619 620 eventCount++; 621 } 622 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; 628 629 // populate the array 630 error = input.SetTo(eventData, eventDataSize, false); 631 if (error != B_OK) { 632 delete[] events; 633 return error; 634 } 635 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; 646 647 events[eventIndex++] 648 = (system_profiler_event_header*)((uint8*)eventData + offset); 649 } 650 651 _events = events; 652 _eventCount = eventCount; 653 return B_OK; 654 } 655 656 657 status_t 658 ModelLoader::_ProcessEvent(uint32 event, uint32 cpu, const void* buffer, 659 size_t size) 660 { 661 switch (event) { 662 case B_SYSTEM_PROFILER_TEAM_ADDED: 663 _HandleTeamAdded((system_profiler_team_added*)buffer); 664 break; 665 666 case B_SYSTEM_PROFILER_TEAM_REMOVED: 667 _HandleTeamRemoved((system_profiler_team_removed*)buffer); 668 break; 669 670 case B_SYSTEM_PROFILER_TEAM_EXEC: 671 _HandleTeamExec((system_profiler_team_exec*)buffer); 672 break; 673 674 case B_SYSTEM_PROFILER_THREAD_ADDED: 675 _HandleThreadAdded((system_profiler_thread_added*)buffer); 676 break; 677 678 case B_SYSTEM_PROFILER_THREAD_REMOVED: 679 _HandleThreadRemoved((system_profiler_thread_removed*)buffer); 680 break; 681 682 case B_SYSTEM_PROFILER_THREAD_SCHEDULED: 683 _HandleThreadScheduled(cpu, 684 (system_profiler_thread_scheduled*)buffer); 685 break; 686 687 case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE: 688 _HandleThreadEnqueuedInRunQueue( 689 (thread_enqueued_in_run_queue*)buffer); 690 break; 691 692 case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE: 693 _HandleThreadRemovedFromRunQueue(cpu, 694 (thread_removed_from_run_queue*)buffer); 695 break; 696 697 case B_SYSTEM_PROFILER_WAIT_OBJECT_INFO: 698 _HandleWaitObjectInfo((system_profiler_wait_object_info*)buffer); 699 break; 700 701 case B_SYSTEM_PROFILER_IO_SCHEDULER_ADDED: 702 _HandleIOSchedulerAdded( 703 (system_profiler_io_scheduler_added*)buffer); 704 break; 705 706 case B_SYSTEM_PROFILER_IO_SCHEDULER_REMOVED: 707 // not so interesting 708 break; 709 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; 722 723 default: 724 printf("unsupported event type %lu, size: %lu\n", event, size); 725 return B_BAD_DATA; 726 break; 727 } 728 729 return B_OK; 730 } 731 732 733 bool 734 ModelLoader::_SetThreadEvents() 735 { 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; 742 } 743 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; 750 751 switch (header->event) { 752 case B_SYSTEM_PROFILER_THREAD_ADDED: 753 { 754 system_profiler_thread_added* event 755 = (system_profiler_thread_added*)buffer; 756 fState->LookupThread(event->thread)->AddEvent(header); 757 break; 758 } 759 760 case B_SYSTEM_PROFILER_THREAD_REMOVED: 761 { 762 system_profiler_thread_removed* event 763 = (system_profiler_thread_removed*)buffer; 764 fState->LookupThread(event->thread)->AddEvent(header); 765 break; 766 } 767 768 case B_SYSTEM_PROFILER_THREAD_SCHEDULED: 769 { 770 system_profiler_thread_scheduled* event 771 = (system_profiler_thread_scheduled*)buffer; 772 fState->LookupThread(event->thread)->AddEvent(header); 773 774 if (event->thread != event->previous_thread) { 775 fState->LookupThread(event->previous_thread) 776 ->AddEvent(header); 777 } 778 break; 779 } 780 781 case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE: 782 { 783 thread_enqueued_in_run_queue* event 784 = (thread_enqueued_in_run_queue*)buffer; 785 fState->LookupThread(event->thread)->AddEvent(header); 786 break; 787 } 788 789 case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE: 790 { 791 thread_removed_from_run_queue* event 792 = (thread_removed_from_run_queue*)buffer; 793 fState->LookupThread(event->thread)->AddEvent(header); 794 break; 795 } 796 797 default: 798 break; 799 } 800 } 801 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(); 809 } 810 811 return true; 812 } 813 814 815 bool 816 ModelLoader::_SetThreadIORequests() 817 { 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); 827 } 828 829 return true; 830 } 831 832 833 void 834 ModelLoader::_SetThreadIORequests(Model::Thread* thread, 835 Model::IORequest** requests, size_t requestCount) 836 { 837 // compute some totals 838 int64 ioCount = 0; 839 nanotime_t ioTime = 0; 840 841 // sort requests by scheduler and start time 842 std::sort(requests, requests + requestCount, 843 Model::IORequest::SchedulerTimeLess); 844 845 nanotime_t endTime = fBaseTime + fModel->LastEventTime(); 846 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; 852 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; 861 } 862 863 previousEnd = requests[i]->finishedEvent != NULL 864 ? requests[i]->finishedEvent->time : endTime; 865 } 866 867 ioCount++; 868 ioTime += previousEnd - ioStart; 869 870 // sort requests by start time 871 std::sort(requests, requests + requestCount, Model::IORequest::TimeLess); 872 873 // set the computed values 874 thread->SetIORequests(requests, requestCount); 875 thread->SetIOs(ioCount, ioTime); 876 } 877 878 879 void 880 ModelLoader::_HandleTeamAdded(system_profiler_team_added* event) 881 { 882 if (fModel->AddTeam(event, fState->LastEventTime()) == NULL) 883 throw std::bad_alloc(); 884 } 885 886 887 void 888 ModelLoader::_HandleTeamRemoved(system_profiler_team_removed* event) 889 { 890 if (Model::Team* team = fModel->TeamByID(event->team)) 891 team->SetDeletionTime(fState->LastEventTime()); 892 else 893 printf("Removed event for unknown team: %ld\n", event->team); 894 } 895 896 897 void 898 ModelLoader::_HandleTeamExec(system_profiler_team_exec* event) 899 { 900 // TODO:... 901 } 902 903 904 void 905 ModelLoader::_HandleThreadAdded(system_profiler_thread_added* event) 906 { 907 ExtendedThreadSchedulingState* thread = _AddThread(event); 908 if (thread == NULL) 909 throw std::bad_alloc(); 910 911 thread->IncrementEventCount(); 912 } 913 914 915 void 916 ModelLoader::_HandleThreadRemoved(system_profiler_thread_removed* event) 917 { 918 ExtendedThreadSchedulingState* thread = fState->LookupThread(event->thread); 919 if (thread != NULL) { 920 thread->thread->SetDeletionTime(fState->LastEventTime()); 921 thread->IncrementEventCount(); 922 } else 923 printf("Removed event for unknown team: %ld\n", event->thread); 924 } 925 926 927 void 928 ModelLoader::_HandleThreadScheduled(uint32 cpu, 929 system_profiler_thread_scheduled* event) 930 { 931 _UpdateLastEventTime(event->time); 932 933 ExtendedThreadSchedulingState* thread = fState->LookupThread(event->thread); 934 if (thread == NULL) { 935 printf("Schedule event for unknown thread: %ld\n", event->thread); 936 return; 937 } 938 939 nanotime_t diffTime = fState->LastEventTime() - thread->lastTime; 940 941 if (thread->state == READY) { 942 // thread scheduled after having been woken up 943 thread->thread->AddLatency(diffTime); 944 } else if (thread->state == PREEMPTED) { 945 // thread scheduled after having been preempted before 946 thread->thread->AddRerun(diffTime); 947 } 948 949 if (thread->state == STILL_RUNNING) { 950 // Thread was running and continues to run. 951 thread->state = RUNNING; 952 } 953 954 if (thread->state != RUNNING) { 955 thread->lastTime = fState->LastEventTime(); 956 thread->state = RUNNING; 957 } 958 959 thread->IncrementEventCount(); 960 961 // unscheduled thread 962 963 if (event->thread == event->previous_thread) 964 return; 965 966 thread = fState->LookupThread(event->previous_thread); 967 if (thread == NULL) { 968 printf("Schedule event for unknown previous thread: %ld\n", 969 event->previous_thread); 970 return; 971 } 972 973 diffTime = fState->LastEventTime() - thread->lastTime; 974 975 if (thread->state == STILL_RUNNING) { 976 // thread preempted 977 thread->thread->AddPreemption(diffTime); 978 thread->thread->AddRun(diffTime); 979 if (thread->priority == 0) 980 _AddIdleTime(cpu, diffTime); 981 982 thread->lastTime = fState->LastEventTime(); 983 thread->state = PREEMPTED; 984 } else if (thread->state == RUNNING) { 985 // thread starts waiting (it hadn't been added to the run 986 // queue before being unscheduled) 987 thread->thread->AddRun(diffTime); 988 if (thread->priority == 0) 989 _AddIdleTime(cpu, diffTime); 990 991 if (event->previous_thread_state == B_THREAD_WAITING) { 992 addr_t waitObject = event->previous_thread_wait_object; 993 switch (event->previous_thread_wait_object_type) { 994 case THREAD_BLOCK_TYPE_SNOOZE: 995 case THREAD_BLOCK_TYPE_SIGNAL: 996 waitObject = 0; 997 break; 998 case THREAD_BLOCK_TYPE_SEMAPHORE: 999 case THREAD_BLOCK_TYPE_CONDITION_VARIABLE: 1000 case THREAD_BLOCK_TYPE_MUTEX: 1001 case THREAD_BLOCK_TYPE_RW_LOCK: 1002 case THREAD_BLOCK_TYPE_OTHER: 1003 default: 1004 break; 1005 } 1006 1007 _AddThreadWaitObject(thread, 1008 event->previous_thread_wait_object_type, waitObject); 1009 } 1010 1011 thread->lastTime = fState->LastEventTime(); 1012 thread->state = WAITING; 1013 } else if (thread->state == UNKNOWN) { 1014 uint32 threadState = event->previous_thread_state; 1015 if (threadState == B_THREAD_WAITING 1016 || threadState == B_THREAD_SUSPENDED) { 1017 thread->lastTime = fState->LastEventTime(); 1018 thread->state = WAITING; 1019 } else if (threadState == B_THREAD_READY) { 1020 thread->lastTime = fState->LastEventTime(); 1021 thread->state = PREEMPTED; 1022 } 1023 } 1024 1025 thread->IncrementEventCount(); 1026 } 1027 1028 1029 void 1030 ModelLoader::_HandleThreadEnqueuedInRunQueue( 1031 thread_enqueued_in_run_queue* event) 1032 { 1033 _UpdateLastEventTime(event->time); 1034 1035 ExtendedThreadSchedulingState* thread = fState->LookupThread(event->thread); 1036 if (thread == NULL) { 1037 printf("Enqueued in run queue event for unknown thread: %ld\n", 1038 event->thread); 1039 return; 1040 } 1041 1042 if (thread->state == RUNNING || thread->state == STILL_RUNNING) { 1043 // Thread was running and is reentered into the run queue. This 1044 // is done by the scheduler, if the thread remains ready. 1045 thread->state = STILL_RUNNING; 1046 } else { 1047 // Thread was waiting and is ready now. 1048 nanotime_t diffTime = fState->LastEventTime() - thread->lastTime; 1049 if (thread->waitObject != NULL) { 1050 thread->waitObject->AddWait(diffTime); 1051 thread->waitObject = NULL; 1052 thread->thread->AddWait(diffTime); 1053 } else if (thread->state != UNKNOWN) 1054 thread->thread->AddUnspecifiedWait(diffTime); 1055 1056 thread->lastTime = fState->LastEventTime(); 1057 thread->state = READY; 1058 } 1059 1060 thread->priority = event->priority; 1061 1062 thread->IncrementEventCount(); 1063 } 1064 1065 1066 void 1067 ModelLoader::_HandleThreadRemovedFromRunQueue(uint32 cpu, 1068 thread_removed_from_run_queue* event) 1069 { 1070 _UpdateLastEventTime(event->time); 1071 1072 ExtendedThreadSchedulingState* thread = fState->LookupThread(event->thread); 1073 if (thread == NULL) { 1074 printf("Removed from run queue event for unknown thread: %ld\n", 1075 event->thread); 1076 return; 1077 } 1078 1079 // This really only happens when the thread priority is changed 1080 // while the thread is ready. 1081 1082 nanotime_t diffTime = fState->LastEventTime() - thread->lastTime; 1083 if (thread->state == RUNNING) { 1084 // This should never happen. 1085 thread->thread->AddRun(diffTime); 1086 if (thread->priority == 0) 1087 _AddIdleTime(cpu, diffTime); 1088 } else if (thread->state == READY || thread->state == PREEMPTED) { 1089 // Not really correct, but the case is rare and we keep it 1090 // simple. 1091 thread->thread->AddUnspecifiedWait(diffTime); 1092 } 1093 1094 thread->lastTime = fState->LastEventTime(); 1095 thread->state = WAITING; 1096 1097 thread->IncrementEventCount(); 1098 } 1099 1100 1101 void 1102 ModelLoader::_HandleWaitObjectInfo(system_profiler_wait_object_info* event) 1103 { 1104 if (fModel->AddWaitObject(event, NULL) == NULL) 1105 throw std::bad_alloc(); 1106 } 1107 1108 1109 void 1110 ModelLoader::_HandleIOSchedulerAdded(system_profiler_io_scheduler_added* event) 1111 { 1112 Model::IOScheduler* scheduler = fModel->IOSchedulerByID(event->scheduler); 1113 if (scheduler != NULL) { 1114 printf("Duplicate added event for I/O scheduler %ld\n", 1115 event->scheduler); 1116 return; 1117 } 1118 1119 if (fModel->AddIOScheduler(event) == NULL) 1120 throw std::bad_alloc(); 1121 } 1122 1123 1124 void 1125 ModelLoader::_HandleIORequestScheduled(io_request_scheduled* event) 1126 { 1127 IORequest* request = fIORequests->Lookup(event->request); 1128 if (request != NULL) { 1129 printf("Duplicate schedule event for I/O request %p\n", event->request); 1130 return; 1131 } 1132 1133 ExtendedThreadSchedulingState* thread = fState->LookupThread(event->thread); 1134 if (thread == NULL) { 1135 printf("I/O request for unknown thread %ld\n", event->thread); 1136 return; 1137 } 1138 1139 if (fModel->IOSchedulerByID(event->scheduler) == NULL) { 1140 printf("I/O requests for unknown scheduler %ld\n", event->scheduler); 1141 return; 1142 } 1143 1144 request = new(std::nothrow) IORequest(event); 1145 if (request == NULL) 1146 throw std::bad_alloc(); 1147 1148 fIORequests->Insert(request); 1149 thread->AddIORequest(request); 1150 } 1151 1152 1153 void 1154 ModelLoader::_HandleIORequestFinished(io_request_finished* event) 1155 { 1156 IORequest* request = fIORequests->Lookup(event->request); 1157 if (request == NULL) 1158 return; 1159 1160 request->finishedEvent = event; 1161 1162 fIORequests->Remove(request); 1163 fState->LookupThread(request->scheduledEvent->thread) 1164 ->IORequestFinished(request); 1165 } 1166 1167 1168 void 1169 ModelLoader::_HandleIOOperationStarted(io_operation_started* event) 1170 { 1171 IORequest* request = fIORequests->Lookup(event->request); 1172 if (request == NULL) { 1173 printf("ModelLoader::_HandleIOOperationStarted(): I/O request for operation %p not found\n", 1174 event->operation); 1175 return; 1176 } 1177 1178 IOOperation* operation = new(std::nothrow) IOOperation(event); 1179 if (operation == NULL) 1180 throw std::bad_alloc(); 1181 1182 request->AddOperation(operation); 1183 } 1184 1185 1186 void 1187 ModelLoader::_HandleIOOperationFinished(io_operation_finished* event) 1188 { 1189 IORequest* request = fIORequests->Lookup(event->request); 1190 if (request == NULL) { 1191 printf("ModelLoader::_HandleIOOperationFinished(): I/O request for " 1192 "operation %p not found\n", event->operation); 1193 return; 1194 } 1195 1196 IOOperation* operation = request->FindOperation(event->operation); 1197 if (operation == NULL) { 1198 printf("ModelLoader::_HandleIOOperationFinished(): operation %p not " 1199 "found\n", event->operation); 1200 return; 1201 } 1202 1203 operation->finishedEvent = event; 1204 } 1205 1206 1207 ModelLoader::ExtendedThreadSchedulingState* 1208 ModelLoader::_AddThread(system_profiler_thread_added* event) 1209 { 1210 // do we know the thread already? 1211 ExtendedThreadSchedulingState* info = fState->LookupThread(event->thread); 1212 if (info != NULL) { 1213 // TODO: ? 1214 return info; 1215 } 1216 1217 // add the thread to the model 1218 Model::Thread* thread = fModel->AddThread(event, fState->LastEventTime()); 1219 if (thread == NULL) 1220 return NULL; 1221 1222 // create and add a ThreadSchedulingState 1223 info = new(std::nothrow) ExtendedThreadSchedulingState(thread); 1224 if (info == NULL) 1225 return NULL; 1226 1227 // TODO: The priority is missing from the system_profiler_thread_added 1228 // struct. For now guess at least whether this is an idle thread. 1229 if (strncmp(event->name, "idle thread", strlen("idle thread")) == 0) 1230 info->priority = 0; 1231 else 1232 info->priority = B_NORMAL_PRIORITY; 1233 1234 fState->InsertThread(info); 1235 1236 return info; 1237 } 1238 1239 1240 void 1241 ModelLoader::_AddThreadWaitObject(ExtendedThreadSchedulingState* thread, 1242 uint32 type, addr_t object) 1243 { 1244 Model::WaitObjectGroup* waitObjectGroup 1245 = fModel->WaitObjectGroupFor(type, object); 1246 if (waitObjectGroup == NULL) { 1247 // The algorithm should prevent this case. 1248 printf("ModelLoader::_AddThreadWaitObject(): Unknown wait object: type: %lu, " 1249 "object: %#lx\n", type, object); 1250 return; 1251 } 1252 1253 Model::WaitObject* waitObject = waitObjectGroup->MostRecentWaitObject(); 1254 1255 Model::ThreadWaitObjectGroup* threadWaitObjectGroup 1256 = fModel->ThreadWaitObjectGroupFor(thread->ID(), type, object); 1257 1258 if (threadWaitObjectGroup == NULL 1259 || threadWaitObjectGroup->MostRecentWaitObject() != waitObject) { 1260 Model::ThreadWaitObject* threadWaitObject 1261 = fModel->AddThreadWaitObject(thread->ID(), waitObject, 1262 &threadWaitObjectGroup); 1263 if (threadWaitObject == NULL) 1264 throw std::bad_alloc(); 1265 } 1266 1267 thread->waitObject = threadWaitObjectGroup->MostRecentThreadWaitObject(); 1268 } 1269 1270 1271 void 1272 ModelLoader::_AddIdleTime(uint32 cpu, nanotime_t time) 1273 { 1274 fCPUInfos[cpu].idleTime += time; 1275 } 1276