1 /* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "Model.h" 8 9 #include <new> 10 11 #include <stdio.h> 12 #include <stdlib.h> 13 14 #include <AutoDeleter.h> 15 16 #include <thread_defs.h> 17 18 19 20 static const char* const kThreadStateNames[] = { 21 "running", 22 "still running", 23 "preempted", 24 "ready", 25 "waiting", 26 "unknown" 27 }; 28 29 30 const char* 31 thread_state_name(ThreadState state) 32 { 33 return kThreadStateNames[state]; 34 } 35 36 37 const char* 38 wait_object_type_name(uint32 type) 39 { 40 switch (type) { 41 case THREAD_BLOCK_TYPE_SEMAPHORE: 42 return "semaphore"; 43 case THREAD_BLOCK_TYPE_CONDITION_VARIABLE: 44 return "condition"; 45 case THREAD_BLOCK_TYPE_MUTEX: 46 return "mutex"; 47 case THREAD_BLOCK_TYPE_RW_LOCK: 48 return "rw lock"; 49 case THREAD_BLOCK_TYPE_USER: 50 return "user"; 51 case THREAD_BLOCK_TYPE_OTHER: 52 case THREAD_BLOCK_TYPE_OTHER_OBJECT: 53 return "other"; 54 case THREAD_BLOCK_TYPE_SNOOZE: 55 return "snooze"; 56 case THREAD_BLOCK_TYPE_SIGNAL: 57 return "signal"; 58 default: 59 return "unknown"; 60 } 61 } 62 63 64 // #pragma mark - CPU 65 66 67 Model::CPU::CPU() 68 : 69 fIdleTime(0) 70 { 71 } 72 73 74 void 75 Model::CPU::SetIdleTime(nanotime_t time) 76 { 77 fIdleTime = time; 78 } 79 80 81 // #pragma mark - IORequest 82 83 84 Model::IORequest::IORequest( 85 system_profiler_io_request_scheduled* scheduledEvent, 86 system_profiler_io_request_finished* finishedEvent, size_t operationCount) 87 : 88 scheduledEvent(scheduledEvent), 89 finishedEvent(finishedEvent), 90 operationCount(operationCount) 91 { 92 } 93 94 95 Model::IORequest::~IORequest() 96 { 97 } 98 99 100 /*static*/ Model::IORequest* 101 Model::IORequest::Create(system_profiler_io_request_scheduled* scheduledEvent, 102 system_profiler_io_request_finished* finishedEvent, size_t operationCount) 103 { 104 void* memory = malloc( 105 sizeof(IORequest) + operationCount * sizeof(IOOperation)); 106 if (memory == NULL) 107 return NULL; 108 109 return new(memory) IORequest(scheduledEvent, finishedEvent, operationCount); 110 } 111 112 113 void 114 Model::IORequest::Delete() 115 { 116 free(this); 117 } 118 119 120 // #pragma mark - IOScheduler 121 122 123 Model::IOScheduler::IOScheduler(system_profiler_io_scheduler_added* event, 124 int32 index) 125 : 126 fAddedEvent(event), 127 fIndex(index) 128 { 129 } 130 131 132 // #pragma mark - WaitObject 133 134 135 Model::WaitObject::WaitObject(const system_profiler_wait_object_info* event) 136 : 137 fEvent(event), 138 fWaits(0), 139 fTotalWaitTime(0) 140 { 141 } 142 143 144 Model::WaitObject::~WaitObject() 145 { 146 } 147 148 149 void 150 Model::WaitObject::AddWait(nanotime_t waitTime) 151 { 152 fWaits++; 153 fTotalWaitTime += waitTime; 154 } 155 156 157 // #pragma mark - WaitObjectGroup 158 159 160 Model::WaitObjectGroup::WaitObjectGroup(WaitObject* waitObject) 161 : 162 fWaits(-1), 163 fTotalWaitTime(-1) 164 { 165 fWaitObjects.AddItem(waitObject); 166 } 167 168 169 Model::WaitObjectGroup::~WaitObjectGroup() 170 { 171 } 172 173 174 int64 175 Model::WaitObjectGroup::Waits() 176 { 177 if (fWaits < 0) 178 _ComputeWaits(); 179 180 return fWaits; 181 } 182 183 184 nanotime_t 185 Model::WaitObjectGroup::TotalWaitTime() 186 { 187 if (fTotalWaitTime < 0) 188 _ComputeWaits(); 189 190 return fTotalWaitTime; 191 } 192 193 194 void 195 Model::WaitObjectGroup::_ComputeWaits() 196 { 197 fWaits = 0; 198 fTotalWaitTime = 0; 199 200 for (int32 i = fWaitObjects.CountItems(); i-- > 0;) { 201 WaitObject* waitObject = fWaitObjects.ItemAt(i); 202 203 fWaits += waitObject->Waits(); 204 fTotalWaitTime += waitObject->TotalWaitTime(); 205 } 206 } 207 208 209 // #pragma mark - ThreadWaitObject 210 211 212 Model::ThreadWaitObject::ThreadWaitObject(WaitObject* waitObject) 213 : 214 fWaitObject(waitObject), 215 fWaits(0), 216 fTotalWaitTime(0) 217 { 218 } 219 220 221 Model::ThreadWaitObject::~ThreadWaitObject() 222 { 223 } 224 225 226 void 227 Model::ThreadWaitObject::AddWait(nanotime_t waitTime) 228 { 229 fWaits++; 230 fTotalWaitTime += waitTime; 231 232 fWaitObject->AddWait(waitTime); 233 } 234 235 236 // #pragma mark - ThreadWaitObjectGroup 237 238 239 Model::ThreadWaitObjectGroup::ThreadWaitObjectGroup( 240 ThreadWaitObject* threadWaitObject) 241 { 242 fWaitObjects.Add(threadWaitObject); 243 } 244 245 246 Model::ThreadWaitObjectGroup::~ThreadWaitObjectGroup() 247 { 248 } 249 250 251 bool 252 Model::ThreadWaitObjectGroup::GetThreadWaitObjects( 253 BObjectList<ThreadWaitObject>& objects) 254 { 255 ThreadWaitObjectList::ConstIterator it = fWaitObjects.GetIterator(); 256 while (ThreadWaitObject* object = it.Next()) { 257 if (!objects.AddItem(object)) 258 return false; 259 } 260 261 return true; 262 } 263 264 265 // #pragma mark - Team 266 267 268 Model::Team::Team(const system_profiler_team_added* event, nanotime_t time) 269 : 270 fCreationEvent(event), 271 fCreationTime(time), 272 fDeletionTime(-1), 273 fThreads(10) 274 { 275 } 276 277 278 Model::Team::~Team() 279 { 280 } 281 282 283 bool 284 Model::Team::AddThread(Thread* thread) 285 { 286 return fThreads.BinaryInsert(thread, &Thread::CompareByCreationTimeID); 287 } 288 289 290 // #pragma mark - Thread 291 292 293 Model::Thread::Thread(Team* team, const system_profiler_thread_added* event, 294 nanotime_t time) 295 : 296 fEvents(NULL), 297 fEventCount(0), 298 fIORequests(NULL), 299 fIORequestCount(0), 300 fTeam(team), 301 fCreationEvent(event), 302 fCreationTime(time), 303 fDeletionTime(-1), 304 fRuns(0), 305 fTotalRunTime(0), 306 fMinRunTime(-1), 307 fMaxRunTime(-1), 308 fLatencies(0), 309 fTotalLatency(0), 310 fMinLatency(-1), 311 fMaxLatency(-1), 312 fReruns(0), 313 fTotalRerunTime(0), 314 fMinRerunTime(-1), 315 fMaxRerunTime(-1), 316 fWaits(0), 317 fTotalWaitTime(0), 318 fUnspecifiedWaitTime(0), 319 fIOCount(0), 320 fIOTime(0), 321 fPreemptions(0), 322 fIndex(-1), 323 fWaitObjectGroups(20, true) 324 { 325 } 326 327 328 Model::Thread::~Thread() 329 { 330 if (fIORequests != NULL) { 331 for (size_t i = 0; i < fIORequestCount; i++) 332 fIORequests[i]->Delete(); 333 334 delete[] fIORequests; 335 } 336 337 delete[] fEvents; 338 } 339 340 341 void 342 Model::Thread::SetEvents(system_profiler_event_header** events, 343 size_t eventCount) 344 { 345 fEvents = events; 346 fEventCount = eventCount; 347 } 348 349 350 void 351 Model::Thread::SetIORequests(IORequest** requests, size_t requestCount) 352 { 353 fIORequests = requests; 354 fIORequestCount = requestCount; 355 } 356 357 358 size_t 359 Model::Thread::ClosestRequestStartIndex(nanotime_t minRequestStartTime) const 360 { 361 size_t lower = 0; 362 size_t upper = fIORequestCount; 363 while (lower < upper) { 364 size_t mid = (lower + upper) / 2; 365 IORequest* request = fIORequests[mid]; 366 367 if (request->ScheduledTime() < minRequestStartTime) 368 lower = mid + 1; 369 else 370 upper = mid; 371 } 372 373 return lower; 374 } 375 376 377 Model::ThreadWaitObjectGroup* 378 Model::Thread::ThreadWaitObjectGroupFor(uint32 type, addr_t object) const 379 { 380 type_and_object key; 381 key.type = type; 382 key.object = object; 383 384 return fWaitObjectGroups.BinarySearchByKey(key, 385 &ThreadWaitObjectGroup::CompareWithTypeObject); 386 } 387 388 389 void 390 Model::Thread::AddRun(nanotime_t runTime) 391 { 392 fRuns++; 393 fTotalRunTime += runTime; 394 395 if (fMinRunTime < 0 || runTime < fMinRunTime) 396 fMinRunTime = runTime; 397 if (runTime > fMaxRunTime) 398 fMaxRunTime = runTime; 399 } 400 401 402 void 403 Model::Thread::AddRerun(nanotime_t runTime) 404 { 405 fReruns++; 406 fTotalRerunTime += runTime; 407 408 if (fMinRerunTime < 0 || runTime < fMinRerunTime) 409 fMinRerunTime = runTime; 410 if (runTime > fMaxRerunTime) 411 fMaxRerunTime = runTime; 412 } 413 414 415 void 416 Model::Thread::AddLatency(nanotime_t latency) 417 { 418 fLatencies++; 419 fTotalLatency += latency; 420 421 if (fMinLatency < 0 || latency < fMinLatency) 422 fMinLatency = latency; 423 if (latency > fMaxLatency) 424 fMaxLatency = latency; 425 } 426 427 428 void 429 Model::Thread::AddPreemption(nanotime_t runTime) 430 { 431 fPreemptions++; 432 } 433 434 435 void 436 Model::Thread::AddWait(nanotime_t waitTime) 437 { 438 fWaits++; 439 fTotalWaitTime += waitTime; 440 } 441 442 443 void 444 Model::Thread::AddUnspecifiedWait(nanotime_t waitTime) 445 { 446 fUnspecifiedWaitTime += waitTime; 447 } 448 449 450 Model::ThreadWaitObject* 451 Model::Thread::AddThreadWaitObject(WaitObject* waitObject, 452 ThreadWaitObjectGroup** _threadWaitObjectGroup) 453 { 454 // create a thread wait object 455 ThreadWaitObject* threadWaitObject 456 = new(std::nothrow) ThreadWaitObject(waitObject); 457 if (threadWaitObject == NULL) 458 return NULL; 459 460 // find the thread wait object group 461 ThreadWaitObjectGroup* threadWaitObjectGroup 462 = ThreadWaitObjectGroupFor(waitObject->Type(), waitObject->Object()); 463 if (threadWaitObjectGroup == NULL) { 464 // doesn't exist yet -- create 465 threadWaitObjectGroup = new(std::nothrow) ThreadWaitObjectGroup( 466 threadWaitObject); 467 if (threadWaitObjectGroup == NULL) { 468 delete threadWaitObject; 469 return NULL; 470 } 471 472 // add to the list 473 if (!fWaitObjectGroups.BinaryInsert(threadWaitObjectGroup, 474 &ThreadWaitObjectGroup::CompareByTypeObject)) { 475 delete threadWaitObjectGroup; 476 return NULL; 477 } 478 } else { 479 // exists -- just add the object 480 threadWaitObjectGroup->AddWaitObject(threadWaitObject); 481 } 482 483 if (_threadWaitObjectGroup != NULL) 484 *_threadWaitObjectGroup = threadWaitObjectGroup; 485 486 return threadWaitObject; 487 } 488 489 490 void 491 Model::Thread::SetIOs(int64 count, nanotime_t time) 492 { 493 fIOCount = count; 494 fIOTime = time; 495 } 496 497 498 // #pragma mark - SchedulingState 499 500 501 Model::SchedulingState::~SchedulingState() 502 { 503 Clear(); 504 } 505 506 507 status_t 508 Model::SchedulingState::Init() 509 { 510 status_t error = fThreadStates.Init(); 511 if (error != B_OK) 512 return error; 513 514 return B_OK; 515 } 516 517 518 status_t 519 Model::SchedulingState::Init(const CompactSchedulingState* state) 520 { 521 status_t error = Init(); 522 if (error != B_OK) 523 return error; 524 525 if (state == NULL) 526 return B_OK; 527 528 fLastEventTime = state->LastEventTime(); 529 for (int32 i = 0; const CompactThreadSchedulingState* compactThreadState 530 = state->ThreadStateAt(i); i++) { 531 ThreadSchedulingState* threadState 532 = new(std::nothrow) ThreadSchedulingState(*compactThreadState); 533 if (threadState == NULL) 534 return B_NO_MEMORY; 535 536 fThreadStates.Insert(threadState); 537 } 538 539 return B_OK; 540 } 541 542 543 void 544 Model::SchedulingState::Clear() 545 { 546 ThreadSchedulingState* state = fThreadStates.Clear(true); 547 while (state != NULL) { 548 ThreadSchedulingState* next = state->next; 549 DeleteThread(state); 550 state = next; 551 } 552 553 fLastEventTime = -1; 554 } 555 556 void 557 Model::SchedulingState::DeleteThread(ThreadSchedulingState* thread) 558 { 559 delete thread; 560 } 561 562 563 // #pragma mark - CompactSchedulingState 564 565 566 /*static*/ Model::CompactSchedulingState* 567 Model::CompactSchedulingState::Create(const SchedulingState& state, 568 off_t eventOffset) 569 { 570 nanotime_t lastEventTime = state.LastEventTime(); 571 572 // count the active threads 573 int32 threadCount = 0; 574 for (ThreadSchedulingStateTable::Iterator it 575 = state.ThreadStates().GetIterator(); 576 ThreadSchedulingState* threadState = it.Next();) { 577 Thread* thread = threadState->thread; 578 if (thread->CreationTime() <= lastEventTime 579 && (thread->DeletionTime() == -1 580 || thread->DeletionTime() >= lastEventTime)) { 581 threadCount++; 582 } 583 } 584 585 CompactSchedulingState* compactState = (CompactSchedulingState*)malloc( 586 sizeof(CompactSchedulingState) 587 + threadCount * sizeof(CompactThreadSchedulingState)); 588 if (compactState == NULL) 589 return NULL; 590 591 // copy the state info 592 compactState->fEventOffset = eventOffset; 593 compactState->fThreadCount = threadCount; 594 compactState->fLastEventTime = lastEventTime; 595 596 int32 threadIndex = 0; 597 for (ThreadSchedulingStateTable::Iterator it 598 = state.ThreadStates().GetIterator(); 599 ThreadSchedulingState* threadState = it.Next();) { 600 Thread* thread = threadState->thread; 601 if (thread->CreationTime() <= lastEventTime 602 && (thread->DeletionTime() == -1 603 || thread->DeletionTime() >= lastEventTime)) { 604 compactState->fThreadStates[threadIndex++] = *threadState; 605 } 606 } 607 608 return compactState; 609 } 610 611 612 void 613 Model::CompactSchedulingState::Delete() 614 { 615 free(this); 616 } 617 618 619 // #pragma mark - Model 620 621 622 Model::Model(const char* dataSourceName, void* eventData, size_t eventDataSize, 623 system_profiler_event_header** events, size_t eventCount) 624 : 625 fDataSourceName(dataSourceName), 626 fEventData(eventData), 627 fEvents(events), 628 fEventDataSize(eventDataSize), 629 fEventCount(eventCount), 630 fCPUCount(1), 631 fBaseTime(0), 632 fLastEventTime(0), 633 fIdleTime(0), 634 fCPUs(20, true), 635 fTeams(20, true), 636 fThreads(20, true), 637 fWaitObjectGroups(20, true), 638 fIOSchedulers(10, true), 639 fSchedulingStates(100) 640 { 641 } 642 643 644 Model::~Model() 645 { 646 for (int32 i = 0; CompactSchedulingState* state 647 = fSchedulingStates.ItemAt(i); i++) { 648 state->Delete(); 649 } 650 651 delete[] fEvents; 652 653 free(fEventData); 654 655 for (int32 i = 0; void* data = fAssociatedData.ItemAt(i); i++) 656 free(data); 657 } 658 659 660 size_t 661 Model::ClosestEventIndex(nanotime_t eventTime) const 662 { 663 // The events themselves are unmodified and use an absolute time. 664 eventTime += fBaseTime; 665 666 // Binary search the event. Since not all events have a timestamp, we have 667 // to do a bit of iteration, too. 668 size_t lower = 0; 669 size_t upper = CountEvents(); 670 while (lower < upper) { 671 size_t mid = (lower + upper) / 2; 672 while (mid < upper) { 673 system_profiler_event_header* header = fEvents[mid]; 674 switch (header->event) { 675 case B_SYSTEM_PROFILER_THREAD_SCHEDULED: 676 case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE: 677 case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE: 678 break; 679 default: 680 mid++; 681 continue; 682 } 683 684 break; 685 } 686 687 if (mid == upper) { 688 lower = mid; 689 break; 690 } 691 692 system_profiler_thread_scheduling_event* event 693 = (system_profiler_thread_scheduling_event*)(fEvents[mid] + 1); 694 if (event->time < eventTime) 695 lower = mid + 1; 696 else 697 upper = mid; 698 } 699 700 return lower; 701 } 702 703 704 bool 705 Model::AddAssociatedData(void* data) 706 { 707 return fAssociatedData.AddItem(data); 708 } 709 710 711 void 712 Model::RemoveAssociatedData(void* data) 713 { 714 fAssociatedData.RemoveItem(data); 715 } 716 717 718 void 719 Model::LoadingFinished() 720 { 721 // set the thread indices 722 for (int32 i = 0; Thread* thread = fThreads.ItemAt(i); i++) 723 thread->SetIndex(i); 724 725 // compute the total idle time 726 fIdleTime = 0; 727 for (int32 i = 0; CPU* cpu = CPUAt(i); i++) 728 fIdleTime += cpu->IdleTime(); 729 } 730 731 732 void 733 Model::SetBaseTime(nanotime_t time) 734 { 735 fBaseTime = time; 736 } 737 738 739 void 740 Model::SetLastEventTime(nanotime_t time) 741 { 742 fLastEventTime = time; 743 } 744 745 746 bool 747 Model::SetCPUCount(int32 count) 748 { 749 fCPUCount = count; 750 751 fCPUs.MakeEmpty(); 752 753 for (int32 i = 0; i < fCPUCount; i++) { 754 CPU* cpu = new(std::nothrow) CPU; 755 if (cpu == NULL || !fCPUs.AddItem(cpu)) { 756 delete cpu; 757 return false; 758 } 759 } 760 761 return true; 762 } 763 764 765 int32 766 Model::CountTeams() const 767 { 768 return fTeams.CountItems(); 769 } 770 771 772 Model::Team* 773 Model::TeamAt(int32 index) const 774 { 775 return fTeams.ItemAt(index); 776 } 777 778 779 Model::Team* 780 Model::TeamByID(team_id id) const 781 { 782 return fTeams.BinarySearchByKey(id, &Team::CompareWithID); 783 } 784 785 786 Model::Team* 787 Model::AddTeam(const system_profiler_team_added* event, nanotime_t time) 788 { 789 Team* team = TeamByID(event->team); 790 if (team != NULL) { 791 fprintf(stderr, "Duplicate team: %" B_PRId32 "\n", event->team); 792 // TODO: User feedback! 793 return team; 794 } 795 796 team = new(std::nothrow) Team(event, time); 797 if (team == NULL) 798 return NULL; 799 800 if (!fTeams.BinaryInsert(team, &Team::CompareByID)) { 801 delete team; 802 return NULL; 803 } 804 805 return team; 806 } 807 808 809 int32 810 Model::CountThreads() const 811 { 812 return fThreads.CountItems(); 813 } 814 815 816 Model::Thread* 817 Model::ThreadAt(int32 index) const 818 { 819 return fThreads.ItemAt(index); 820 } 821 822 823 Model::Thread* 824 Model::ThreadByID(thread_id id) const 825 { 826 return fThreads.BinarySearchByKey(id, &Thread::CompareWithID); 827 } 828 829 830 Model::Thread* 831 Model::AddThread(const system_profiler_thread_added* event, nanotime_t time) 832 { 833 // check whether we do already know the thread 834 Thread* thread = ThreadByID(event->thread); 835 if (thread != NULL) { 836 fprintf(stderr, "Duplicate thread: %" B_PRId32 "\n", event->thread); 837 // TODO: User feedback! 838 return thread; 839 } 840 841 // get its team 842 Team* team = TeamByID(event->team); 843 if (team == NULL) { 844 fprintf(stderr, "No team for thread: %" B_PRId32 "\n", event->thread); 845 return NULL; 846 } 847 848 // create the thread and add it 849 thread = new(std::nothrow) Thread(team, event, time); 850 if (thread == NULL) 851 return NULL; 852 ObjectDeleter<Thread> threadDeleter(thread); 853 854 if (!fThreads.BinaryInsert(thread, &Thread::CompareByID)) 855 return NULL; 856 857 if (!team->AddThread(thread)) { 858 fThreads.RemoveItem(thread); 859 return NULL; 860 } 861 862 threadDeleter.Detach(); 863 return thread; 864 } 865 866 867 Model::WaitObject* 868 Model::AddWaitObject(const system_profiler_wait_object_info* event, 869 WaitObjectGroup** _waitObjectGroup) 870 { 871 // create a wait object 872 WaitObject* waitObject = new(std::nothrow) WaitObject(event); 873 if (waitObject == NULL) 874 return NULL; 875 876 // find the wait object group 877 WaitObjectGroup* waitObjectGroup 878 = WaitObjectGroupFor(waitObject->Type(), waitObject->Object()); 879 if (waitObjectGroup == NULL) { 880 // doesn't exist yet -- create 881 waitObjectGroup = new(std::nothrow) WaitObjectGroup(waitObject); 882 if (waitObjectGroup == NULL) { 883 delete waitObject; 884 return NULL; 885 } 886 887 // add to the list 888 if (!fWaitObjectGroups.BinaryInsert(waitObjectGroup, 889 &WaitObjectGroup::CompareByTypeObject)) { 890 delete waitObjectGroup; 891 return NULL; 892 } 893 } else { 894 // exists -- just add the object 895 waitObjectGroup->AddWaitObject(waitObject); 896 } 897 898 if (_waitObjectGroup != NULL) 899 *_waitObjectGroup = waitObjectGroup; 900 901 return waitObject; 902 } 903 904 905 int32 906 Model::CountWaitObjectGroups() const 907 { 908 return fWaitObjectGroups.CountItems(); 909 } 910 911 912 Model::WaitObjectGroup* 913 Model::WaitObjectGroupAt(int32 index) const 914 { 915 return fWaitObjectGroups.ItemAt(index); 916 } 917 918 919 Model::WaitObjectGroup* 920 Model::WaitObjectGroupFor(uint32 type, addr_t object) const 921 { 922 type_and_object key; 923 key.type = type; 924 key.object = object; 925 926 return fWaitObjectGroups.BinarySearchByKey(key, 927 &WaitObjectGroup::CompareWithTypeObject); 928 } 929 930 931 Model::ThreadWaitObject* 932 Model::AddThreadWaitObject(thread_id threadID, WaitObject* waitObject, 933 ThreadWaitObjectGroup** _threadWaitObjectGroup) 934 { 935 Thread* thread = ThreadByID(threadID); 936 if (thread == NULL) 937 return NULL; 938 939 return thread->AddThreadWaitObject(waitObject, _threadWaitObjectGroup); 940 } 941 942 943 Model::ThreadWaitObjectGroup* 944 Model::ThreadWaitObjectGroupFor(thread_id threadID, uint32 type, addr_t object) const 945 { 946 Thread* thread = ThreadByID(threadID); 947 if (thread == NULL) 948 return NULL; 949 950 return thread->ThreadWaitObjectGroupFor(type, object); 951 } 952 953 954 int32 955 Model::CountIOSchedulers() const 956 { 957 return fIOSchedulers.CountItems(); 958 } 959 960 961 Model::IOScheduler* 962 Model::IOSchedulerAt(int32 index) const 963 { 964 return fIOSchedulers.ItemAt(index); 965 } 966 967 968 Model::IOScheduler* 969 Model::IOSchedulerByID(int32 id) const 970 { 971 for (int32 i = 0; IOScheduler* scheduler = fIOSchedulers.ItemAt(i); i++) { 972 if (scheduler->ID() == id) 973 return scheduler; 974 } 975 976 return NULL; 977 } 978 979 980 Model::IOScheduler* 981 Model::AddIOScheduler(system_profiler_io_scheduler_added* event) 982 { 983 IOScheduler* scheduler = new(std::nothrow) IOScheduler(event, 984 fIOSchedulers.CountItems()); 985 if (scheduler == NULL || !fIOSchedulers.AddItem(scheduler)) { 986 delete scheduler; 987 return NULL; 988 } 989 990 return scheduler; 991 } 992 993 994 bool 995 Model::AddSchedulingStateSnapshot(const SchedulingState& state, 996 off_t eventOffset) 997 { 998 CompactSchedulingState* compactState = CompactSchedulingState::Create(state, 999 eventOffset); 1000 if (compactState == NULL) 1001 return false; 1002 1003 if (!fSchedulingStates.AddItem(compactState)) { 1004 compactState->Delete(); 1005 return false; 1006 } 1007 1008 return true; 1009 } 1010 1011 1012 const Model::CompactSchedulingState* 1013 Model::ClosestSchedulingState(nanotime_t eventTime) const 1014 { 1015 int32 index = fSchedulingStates.BinarySearchIndexByKey(eventTime, 1016 &_CompareEventTimeSchedulingState); 1017 if (index >= 0) 1018 return fSchedulingStates.ItemAt(index); 1019 1020 // no exact match 1021 index = -index - 1; 1022 return index > 0 ? fSchedulingStates.ItemAt(index - 1) : NULL; 1023 } 1024 1025 1026 /*static*/ int 1027 Model::_CompareEventTimeSchedulingState(const nanotime_t* time, 1028 const CompactSchedulingState* state) 1029 { 1030 if (*time < state->LastEventTime()) 1031 return -1; 1032 return *time == state->LastEventTime() ? 0 : 1; 1033 } 1034 1035