1 /* 2 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "Thread.h" 8 9 #include <algorithm> 10 #include <new> 11 12 #include <debug_support.h> 13 14 #include "debug_utils.h" 15 16 #include "Image.h" 17 #include "Options.h" 18 #include "Team.h" 19 20 21 // #pragma mark - ThreadImage 22 23 24 ThreadImage::ThreadImage(Image* image, ImageProfileResult* result) 25 : 26 fImage(image), 27 fResult(result) 28 { 29 fImage->AcquireReference(); 30 fResult->AcquireReference(); 31 } 32 33 34 ThreadImage::~ThreadImage() 35 { 36 fImage->ReleaseReference(); 37 fResult->ReleaseReference(); 38 } 39 40 41 // #pragma mark - Thread 42 43 44 Thread::Thread(Team* team, thread_id threadID, const char* name, bigtime_t initialCPUTime) 45 : 46 fTeam(team), 47 fID(threadID), 48 fName(name), 49 fLastCPUTime(initialCPUTime), 50 fSampleArea(-1), 51 fSamples(NULL), 52 fProfileResult(NULL), 53 fLazyImages(true) 54 { 55 fTeam->AcquireReference(); 56 } 57 58 59 Thread::~Thread() 60 { 61 if (fSampleArea >= 0) 62 delete_area(fSampleArea); 63 64 if (fProfileResult != NULL) 65 fProfileResult->ReleaseReference(); 66 67 while (ThreadImage* image = fImages.RemoveHead()) 68 delete image; 69 while (ThreadImage* image = fOldImages.RemoveHead()) 70 delete image; 71 72 fTeam->ReleaseReference(); 73 } 74 75 76 int32 77 Thread::EntityID() const 78 { 79 return ID(); 80 } 81 82 83 const char* 84 Thread::EntityName() const 85 { 86 return Name(); 87 } 88 89 90 const char* 91 Thread::EntityType() const 92 { 93 return "thread"; 94 } 95 96 97 void 98 Thread::SetProfileResult(ProfileResult* result) 99 { 100 ProfileResult* oldResult = fProfileResult; 101 102 fProfileResult = result; 103 if (fProfileResult != NULL) 104 fProfileResult->AcquireReference(); 105 106 if (oldResult) 107 oldResult->ReleaseReference(); 108 } 109 110 111 void 112 Thread::UpdateInfo(const char* name) 113 { 114 fName = name; 115 } 116 117 118 void 119 Thread::SetSampleArea(area_id area, addr_t* samples) 120 { 121 fSampleArea = area; 122 fSamples = samples; 123 } 124 125 126 void 127 Thread::SetInterval(bigtime_t interval) 128 { 129 fProfileResult->SetInterval(interval); 130 } 131 132 133 void 134 Thread::SetLazyImages(bool lazy) 135 { 136 fLazyImages = lazy; 137 } 138 139 140 status_t 141 Thread::AddImage(Image* image) 142 { 143 ImageProfileResult* result; 144 status_t error = fProfileResult->GetImageProfileResult( 145 image->GetSharedImage(), image->ID(), result); 146 if (error != B_OK) 147 return error; 148 149 BReference<ImageProfileResult> resultReference(result, true); 150 151 ThreadImage* threadImage = new(std::nothrow) ThreadImage(image, result); 152 if (threadImage == NULL) 153 return B_NO_MEMORY; 154 155 if (fLazyImages) 156 fNewImages.Add(threadImage); 157 else 158 fImages.Add(threadImage); 159 160 return B_OK; 161 } 162 163 164 void 165 Thread::RemoveImage(Image* image) 166 { 167 ImageList::Iterator it = fImages.GetIterator(); 168 while (ThreadImage* threadImage = it.Next()) { 169 if (threadImage->GetImage() == image) { 170 it.Remove(); 171 if (threadImage->Result()->TotalHits() > 0) 172 fOldImages.Add(threadImage); 173 else 174 delete threadImage; 175 break; 176 } 177 } 178 } 179 180 181 void 182 Thread::AddSamples(int32 count, int32 dropped, int32 stackDepth, 183 bool variableStackDepth, int32 event) 184 { 185 _SynchronizeImages(event); 186 187 if (variableStackDepth) { 188 addr_t* samples = fSamples; 189 190 while (count > 0) { 191 addr_t sampleCount = *(samples++); 192 193 if (sampleCount >= B_DEBUG_PROFILE_EVENT_BASE) { 194 int32 eventParameterCount 195 = sampleCount & B_DEBUG_PROFILE_EVENT_PARAMETER_MASK; 196 if (sampleCount == B_DEBUG_PROFILE_IMAGE_EVENT) { 197 _SynchronizeImages((int32)samples[0]); 198 } else { 199 fprintf(stderr, "unknown profile event: %#lx\n", 200 sampleCount); 201 } 202 203 samples += eventParameterCount; 204 count -= eventParameterCount + 1; 205 continue; 206 } 207 208 fProfileResult->AddSamples(this, samples, sampleCount); 209 210 samples += sampleCount; 211 count -= sampleCount + 1; 212 } 213 } else { 214 count = count / stackDepth * stackDepth; 215 216 for (int32 i = 0; i < count; i += stackDepth) 217 fProfileResult->AddSamples(this, fSamples + i, stackDepth); 218 } 219 220 fProfileResult->AddDroppedTicks(dropped); 221 } 222 223 224 void 225 Thread::AddSamples(addr_t* samples, int32 sampleCount) 226 { 227 fProfileResult->AddSamples(this, samples, sampleCount); 228 } 229 230 231 void 232 Thread::UpdateCPUTime(bigtime_t time) 233 { 234 bigtime_t elapsed = time - fLastCPUTime; 235 int64 expectedTicks = elapsed / fProfileResult->Interval(); 236 fLastCPUTime = time; 237 238 fProfileResult->AddExpectedTicks(expectedTicks); 239 } 240 241 242 void 243 Thread::PrintResults() 244 { 245 fProfileResult->PrintResults(this); 246 } 247 248 249 int32 250 Thread::CountImages() const 251 { 252 return fImages.Count() + fOldImages.Count(); 253 } 254 255 256 ImageProfileResult* 257 Thread::VisitImages(Visitor& visitor) const 258 { 259 ImageList::ConstIterator it = fOldImages.GetIterator(); 260 while (ThreadImage* image = it.Next()) { 261 if (visitor.VisitImage(image->Result())) 262 return image->Result(); 263 } 264 265 it = fImages.GetIterator(); 266 while (ThreadImage* image = it.Next()) { 267 if (visitor.VisitImage(image->Result())) 268 return image->Result(); 269 } 270 271 return NULL; 272 } 273 274 275 ImageProfileResult* 276 Thread::FindImage(addr_t address, addr_t& _loadDelta) const 277 { 278 ImageList::ConstIterator it = fImages.GetIterator(); 279 while (ThreadImage* image = it.Next()) { 280 if (image->GetImage()->ContainsAddress(address)) { 281 _loadDelta = image->GetImage()->LoadDelta(); 282 return image->Result(); 283 } 284 } 285 return NULL; 286 } 287 288 289 void 290 Thread::_SynchronizeImages(int32 event) 291 { 292 // remove obsolete images 293 ImageList::Iterator it = fImages.GetIterator(); 294 while (ThreadImage* image = it.Next()) { 295 int32 deleted = image->GetImage()->DeletionEvent(); 296 if (deleted >= 0 && event >= deleted) { 297 it.Remove(); 298 if (image->Result()->TotalHits() > 0) 299 fOldImages.Add(image); 300 else 301 delete image; 302 } 303 } 304 305 // add new images 306 it = fNewImages.GetIterator(); 307 while (ThreadImage* image = it.Next()) { 308 if (image->GetImage()->CreationEvent() <= event) { 309 it.Remove(); 310 int32 deleted = image->GetImage()->DeletionEvent(); 311 if (deleted >= 0 && event >= deleted) { 312 // image already deleted 313 delete image; 314 } else 315 fImages.Add(image); 316 } 317 } 318 } 319