xref: /haiku/src/apps/debuganalyzer/model_loader/ThreadModelLoader.cpp (revision b671e9bbdbd10268a042b4f4cc4317ccd03d105e)
1 /*
2  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "ThreadModelLoader.h"
7 
8 #include <stdio.h>
9 
10 #include <new>
11 
12 #include <AutoLocker.h>
13 #include <DebugEventStream.h>
14 
15 #include "ThreadModel.h"
16 
17 
18 static int
19 compare_by_type_and_name(const Model::ThreadWaitObject* a,
20 	const Model::ThreadWaitObject* b)
21 {
22 	if (a->Type() != b->Type())
23 		return a->Type() < b->Type() ? -1 : 1;
24 
25 	return strcmp(a->Name(), b->Name());
26 }
27 
28 
29 // #pragma mark -
30 
31 
32 ThreadModelLoader::ThreadModelLoader(Model* model, Model::Thread* thread,
33 	const BMessenger& target, void* targetCookie)
34 	:
35 	AbstractModelLoader(target, targetCookie),
36 	fModel(model),
37 	fThread(thread),
38 	fThreadModel(NULL)
39 {
40 }
41 
42 
43 ThreadModelLoader::~ThreadModelLoader()
44 {
45 	delete fThreadModel;
46 }
47 
48 
49 ThreadModel*
50 ThreadModelLoader::DetachModel()
51 {
52 	AutoLocker<BLocker> locker(fLock);
53 
54 	if (fThreadModel == NULL || fLoading)
55 		return NULL;
56 
57 	ThreadModel* model = fThreadModel;
58 	fThreadModel = NULL;
59 
60 	return model;
61 }
62 
63 
64 status_t
65 ThreadModelLoader::PrepareForLoading()
66 {
67 	return B_OK;
68 }
69 
70 
71 status_t
72 ThreadModelLoader::Load()
73 {
74 	try {
75 		return _Load();
76 	} catch(...) {
77 		return B_ERROR;
78 	}
79 }
80 
81 
82 void
83 ThreadModelLoader::FinishLoading(bool success)
84 {
85 	if (!success) {
86 		delete fThreadModel;
87 		fThreadModel = NULL;
88 	}
89 }
90 
91 
92 status_t
93 ThreadModelLoader::_Load()
94 {
95 	// create a model
96 	fThreadModel = new(std::nothrow) ThreadModel(fModel, fThread);
97 	if (fThreadModel == NULL)
98 		return B_NO_MEMORY;
99 
100 	// collect all wait objects
101 	BObjectList<Model::ThreadWaitObject> waitObjects;
102 
103 	int32 groupCount = fThread->CountThreadWaitObjectGroups();
104 	for (int32 i = 0; i < groupCount; i++) {
105 		Model::ThreadWaitObjectGroup* group
106 			= fThread->ThreadWaitObjectGroupAt(i);
107 
108 		if (!group->GetThreadWaitObjects(waitObjects))
109 			return B_NO_MEMORY;
110 	}
111 
112 	// sort them by type and name
113 	waitObjects.SortItems(&compare_by_type_and_name);
114 
115 	// create the groups
116 	int32 waitObjectCount = waitObjects.CountItems();
117 printf("%ld wait objects\n", waitObjectCount);
118 	for (int32 i = 0; i < waitObjectCount;) {
119 printf("new wait object group at %ld\n", i);
120 		// collect the objects for this group
121 		Model::ThreadWaitObject* firstObject = waitObjects.ItemAt(i);
122 		int32 k = i + 1;
123 		for (; k < waitObjectCount; k++) {
124 			if (compare_by_type_and_name(firstObject, waitObjects.ItemAt(k))
125 					!= 0) {
126 				break;
127 			}
128 		}
129 
130 		if (fThreadModel->AddWaitObjectGroup(waitObjects, i, k) == NULL)
131 			return B_NO_MEMORY;
132 
133 		i = k;
134 	}
135 
136 	// create a debug input stream
137 	BDebugEventInputStream input;
138 	uint8* eventData = (uint8*)fModel->EventData();
139 	status_t error = input.SetTo(eventData, fModel->EventDataSize(), false);
140 	if (error != B_OK)
141 		return error;
142 
143 	// process the events
144 	thread_id threadID = fThread->ID();
145 	bool done = false;
146 	uint32 count = 0;
147 
148 	while (!done) {
149 		// get next event
150 		uint32 eventType;
151 		uint32 cpu;
152 		const void* buffer;
153 		off_t streamOffset;
154 		ssize_t bufferSize = input.ReadNextEvent(&eventType, &cpu, &buffer,
155 			&streamOffset);
156 		if (bufferSize < 0)
157 			return bufferSize;
158 		if (buffer == NULL)
159 			break;
160 
161 		// process the event
162 		bool keepEvent = false;
163 
164 		switch (eventType) {
165 			case B_SYSTEM_PROFILER_THREAD_REMOVED:
166 			{
167 				system_profiler_thread_removed* event
168 					= (system_profiler_thread_removed*)buffer;
169 				if (event->thread == threadID)
170 					done = true;
171 				break;
172 			}
173 
174 			case B_SYSTEM_PROFILER_THREAD_SCHEDULED:
175 			{
176 				system_profiler_thread_scheduled* event
177 					= (system_profiler_thread_scheduled*)buffer;
178 				keepEvent = event->thread == threadID
179 					|| event->previous_thread == threadID ;
180 				break;
181 			}
182 
183 			case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE:
184 			{
185 				thread_enqueued_in_run_queue* event
186 					= (thread_enqueued_in_run_queue*)buffer;
187 				keepEvent = event->thread == threadID;
188 				break;
189 			}
190 
191 			case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE:
192 			{
193 				thread_removed_from_run_queue* event
194 					= (thread_removed_from_run_queue*)buffer;
195 				keepEvent = event->thread == threadID;
196 				break;
197 			}
198 
199 			default:
200 				break;
201 		}
202 
203 		if (keepEvent) {
204 			fThreadModel->AddSchedulingEvent(
205 				(system_profiler_event_header*)(eventData + streamOffset));
206 		}
207 
208 		// periodically check whether we're supposed to abort
209 		if (++count % 32 == 0) {
210 			AutoLocker<BLocker> locker(fLock);
211 			if (fAborted)
212 				return B_ERROR;
213 		}
214 	}
215 
216 	return B_OK;
217 }
218