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
24ThreadImage::ThreadImage(Image* image, ImageProfileResult* result)
25	:
26	fImage(image),
27	fResult(result)
28{
29	fImage->AcquireReference();
30	fResult->AcquireReference();
31}
32
33
34ThreadImage::~ThreadImage()
35{
36	fImage->ReleaseReference();
37	fResult->ReleaseReference();
38}
39
40
41// #pragma mark - ThreadI
42
43
44Thread::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
58Thread::~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
75int32
76Thread::EntityID() const
77{
78	return ID();
79}
80
81
82const char*
83Thread::EntityName() const
84{
85	return Name();
86}
87
88
89const char*
90Thread::EntityType() const
91{
92	return "thread";
93}
94
95
96void
97Thread::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
110void
111Thread::UpdateInfo(const char* name)
112{
113	fName = name;
114}
115
116
117void
118Thread::SetSampleArea(area_id area, addr_t* samples)
119{
120	fSampleArea = area;
121	fSamples = samples;
122}
123
124
125void
126Thread::SetInterval(bigtime_t interval)
127{
128	fProfileResult->SetInterval(interval);
129}
130
131
132void
133Thread::SetLazyImages(bool lazy)
134{
135	fLazyImages = lazy;
136}
137
138
139status_t
140Thread::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
163void
164Thread::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
180void
181Thread::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
223void
224Thread::AddSamples(addr_t* samples, int32 sampleCount)
225{
226	fProfileResult->AddSamples(this, samples, sampleCount);
227}
228
229
230void
231Thread::PrintResults()
232{
233	fProfileResult->PrintResults(this);
234}
235
236
237int32
238Thread::CountImages() const
239{
240	return fImages.Count() + fOldImages.Count();
241}
242
243
244ImageProfileResult*
245Thread::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
263ImageProfileResult*
264Thread::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
277void
278Thread::_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