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
ThreadImage(Image * image,ImageProfileResult * result)24 ThreadImage::ThreadImage(Image* image, ImageProfileResult* result)
25 :
26 fImage(image),
27 fResult(result)
28 {
29 fImage->AcquireReference();
30 fResult->AcquireReference();
31 }
32
33
~ThreadImage()34 ThreadImage::~ThreadImage()
35 {
36 fImage->ReleaseReference();
37 fResult->ReleaseReference();
38 }
39
40
41 // #pragma mark - Thread
42
43
Thread(Team * team,thread_id threadID,const char * name,bigtime_t initialCPUTime)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
~Thread()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
EntityID() const77 Thread::EntityID() const
78 {
79 return ID();
80 }
81
82
83 const char*
EntityName() const84 Thread::EntityName() const
85 {
86 return Name();
87 }
88
89
90 const char*
EntityType() const91 Thread::EntityType() const
92 {
93 return "thread";
94 }
95
96
97 void
SetProfileResult(ProfileResult * result)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
UpdateInfo(const char * name)112 Thread::UpdateInfo(const char* name)
113 {
114 fName = name;
115 }
116
117
118 void
SetSampleArea(area_id area,addr_t * samples)119 Thread::SetSampleArea(area_id area, addr_t* samples)
120 {
121 fSampleArea = area;
122 fSamples = samples;
123 }
124
125
126 void
SetInterval(bigtime_t interval)127 Thread::SetInterval(bigtime_t interval)
128 {
129 fProfileResult->SetInterval(interval);
130 }
131
132
133 void
SetLazyImages(bool lazy)134 Thread::SetLazyImages(bool lazy)
135 {
136 fLazyImages = lazy;
137 }
138
139
140 status_t
AddImage(Image * image)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
RemoveImage(Image * image)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
AddSamples(int32 count,int32 dropped,int32 stackDepth,bool variableStackDepth,int32 event)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
AddSamples(addr_t * samples,int32 sampleCount)225 Thread::AddSamples(addr_t* samples, int32 sampleCount)
226 {
227 fProfileResult->AddSamples(this, samples, sampleCount);
228 }
229
230
231 void
UpdateCPUTime(bigtime_t time)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
PrintResults()243 Thread::PrintResults()
244 {
245 fProfileResult->PrintResults(this);
246 }
247
248
249 int32
CountImages() const250 Thread::CountImages() const
251 {
252 return fImages.Count() + fOldImages.Count();
253 }
254
255
256 ImageProfileResult*
VisitImages(Visitor & visitor) const257 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*
FindImage(addr_t address,addr_t & _loadDelta) const276 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
_SynchronizeImages(int32 event)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