xref: /haiku/src/bin/debug/profile/Thread.cpp (revision 909af08f4328301fbdef1ffb41f566c3b5bec0c7)
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