1 /* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "ThreadModelLoader.h" 7 8 #include <stdio.h> 9 10 #include <new> 11 12 #include <AutoLocker.h> 13 #include <DebugEventStream.h> 14 15 #include "ThreadModel.h" 16 17 18 static int 19 compare_by_type_and_name(const Model::ThreadWaitObject* a, 20 const Model::ThreadWaitObject* b) 21 { 22 if (a->Type() != b->Type()) 23 return a->Type() < b->Type() ? -1 : 1; 24 25 return strcmp(a->Name(), b->Name()); 26 } 27 28 29 // #pragma mark - 30 31 32 ThreadModelLoader::ThreadModelLoader(Model* model, Model::Thread* thread, 33 const BMessenger& target, void* targetCookie) 34 : 35 AbstractModelLoader(target, targetCookie), 36 fModel(model), 37 fThread(thread), 38 fThreadModel(NULL) 39 { 40 } 41 42 43 ThreadModelLoader::~ThreadModelLoader() 44 { 45 delete fThreadModel; 46 } 47 48 49 ThreadModel* 50 ThreadModelLoader::DetachModel() 51 { 52 AutoLocker<BLocker> locker(fLock); 53 54 if (fThreadModel == NULL || fLoading) 55 return NULL; 56 57 ThreadModel* model = fThreadModel; 58 fThreadModel = NULL; 59 60 return model; 61 } 62 63 64 status_t 65 ThreadModelLoader::PrepareForLoading() 66 { 67 return B_OK; 68 } 69 70 71 status_t 72 ThreadModelLoader::Load() 73 { 74 try { 75 return _Load(); 76 } catch(...) { 77 return B_ERROR; 78 } 79 } 80 81 82 void 83 ThreadModelLoader::FinishLoading(bool success) 84 { 85 if (!success) { 86 delete fThreadModel; 87 fThreadModel = NULL; 88 } 89 } 90 91 92 status_t 93 ThreadModelLoader::_Load() 94 { 95 // create a model 96 fThreadModel = new(std::nothrow) ThreadModel(fModel, fThread); 97 if (fThreadModel == NULL) 98 return B_NO_MEMORY; 99 100 // collect all wait objects 101 BObjectList<Model::ThreadWaitObject> waitObjects; 102 103 int32 groupCount = fThread->CountThreadWaitObjectGroups(); 104 for (int32 i = 0; i < groupCount; i++) { 105 Model::ThreadWaitObjectGroup* group 106 = fThread->ThreadWaitObjectGroupAt(i); 107 108 if (!group->GetThreadWaitObjects(waitObjects)) 109 return B_NO_MEMORY; 110 } 111 112 // sort them by type and name 113 waitObjects.SortItems(&compare_by_type_and_name); 114 115 // create the groups 116 int32 waitObjectCount = waitObjects.CountItems(); 117 printf("%ld wait objects\n", waitObjectCount); 118 for (int32 i = 0; i < waitObjectCount;) { 119 printf("new wait object group at %ld\n", i); 120 // collect the objects for this group 121 Model::ThreadWaitObject* firstObject = waitObjects.ItemAt(i); 122 int32 k = i + 1; 123 for (; k < waitObjectCount; k++) { 124 if (compare_by_type_and_name(firstObject, waitObjects.ItemAt(k)) 125 != 0) { 126 break; 127 } 128 } 129 130 if (fThreadModel->AddWaitObjectGroup(waitObjects, i, k) == NULL) 131 return B_NO_MEMORY; 132 133 i = k; 134 } 135 136 // create a debug input stream 137 BDebugEventInputStream input; 138 uint8* eventData = (uint8*)fModel->EventData(); 139 status_t error = input.SetTo(eventData, fModel->EventDataSize(), false); 140 if (error != B_OK) 141 return error; 142 143 // process the events 144 thread_id threadID = fThread->ID(); 145 bool done = false; 146 uint32 count = 0; 147 148 while (!done) { 149 // get next event 150 uint32 eventType; 151 uint32 cpu; 152 const void* buffer; 153 off_t streamOffset; 154 ssize_t bufferSize = input.ReadNextEvent(&eventType, &cpu, &buffer, 155 &streamOffset); 156 if (bufferSize < 0) 157 return bufferSize; 158 if (buffer == NULL) 159 break; 160 161 // process the event 162 bool keepEvent = false; 163 164 switch (eventType) { 165 case B_SYSTEM_PROFILER_THREAD_REMOVED: 166 { 167 system_profiler_thread_removed* event 168 = (system_profiler_thread_removed*)buffer; 169 if (event->thread == threadID) 170 done = true; 171 break; 172 } 173 174 case B_SYSTEM_PROFILER_THREAD_SCHEDULED: 175 { 176 system_profiler_thread_scheduled* event 177 = (system_profiler_thread_scheduled*)buffer; 178 keepEvent = event->thread == threadID 179 || event->previous_thread == threadID ; 180 break; 181 } 182 183 case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE: 184 { 185 thread_enqueued_in_run_queue* event 186 = (thread_enqueued_in_run_queue*)buffer; 187 keepEvent = event->thread == threadID; 188 break; 189 } 190 191 case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE: 192 { 193 thread_removed_from_run_queue* event 194 = (thread_removed_from_run_queue*)buffer; 195 keepEvent = event->thread == threadID; 196 break; 197 } 198 199 default: 200 break; 201 } 202 203 if (keepEvent) { 204 fThreadModel->AddSchedulingEvent( 205 (system_profiler_event_header*)(eventData + streamOffset)); 206 } 207 208 // periodically check whether we're supposed to abort 209 if (++count % 32 == 0) { 210 AutoLocker<BLocker> locker(fLock); 211 if (fAborted) 212 return B_ERROR; 213 } 214 } 215 216 return B_OK; 217 } 218