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