13dc9bfd1SIngo Weinhold/*
23dc9bfd1SIngo Weinhold * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
33dc9bfd1SIngo Weinhold * Distributed under the terms of the MIT License.
43dc9bfd1SIngo Weinhold */
53dc9bfd1SIngo Weinhold
6d4d63490SIngo Weinhold
74f1804a1SIngo Weinhold#include "ModelLoader.h"
83dc9bfd1SIngo Weinhold
9c442235eSIngo Weinhold#include <stdio.h>
10c442235eSIngo Weinhold#include <string.h>
11c442235eSIngo Weinhold
12c2354448SIngo Weinhold#include <algorithm>
133dc9bfd1SIngo Weinhold#include <new>
143dc9bfd1SIngo Weinhold
153dc9bfd1SIngo Weinhold#include <AutoDeleter.h>
163dc9bfd1SIngo Weinhold#include <AutoLocker.h>
173dc9bfd1SIngo Weinhold#include <DebugEventStream.h>
183dc9bfd1SIngo Weinhold
19c442235eSIngo Weinhold#include <system_profiler_defs.h>
201e336ebaSIngo Weinhold#include <thread_defs.h>
21c442235eSIngo Weinhold
22c442235eSIngo Weinhold#include "DataSource.h"
233dc9bfd1SIngo Weinhold#include "MessageCodes.h"
244f1804a1SIngo Weinhold#include "Model.h"
253dc9bfd1SIngo Weinhold
263dc9bfd1SIngo Weinhold
27d4d63490SIngo Weinhold// add a scheduling state snapshot every x events
28d4d63490SIngo Weinholdstatic const uint32 kSchedulingSnapshotInterval = 1024;
29d4d63490SIngo Weinhold
30bea40bcdSIngo Weinholdstatic const uint32 kMaxCPUCount = 1024;
31bea40bcdSIngo Weinhold
32d4d63490SIngo Weinhold
331e336ebaSIngo Weinholdstruct SimpleWaitObjectInfo : system_profiler_wait_object_info {
341e336ebaSIngo Weinhold	SimpleWaitObjectInfo(uint32 type)
351e336ebaSIngo Weinhold	{
361e336ebaSIngo Weinhold		this->type = type;
371e336ebaSIngo Weinhold		object = 0;
381e336ebaSIngo Weinhold		referenced_object = 0;
391e336ebaSIngo Weinhold		name[0] = '\0';
401e336ebaSIngo Weinhold	}
411e336ebaSIngo Weinhold};
421e336ebaSIngo Weinhold
431e336ebaSIngo Weinhold
441e336ebaSIngo Weinholdstatic const SimpleWaitObjectInfo kSnoozeWaitObjectInfo(
451e336ebaSIngo Weinhold	THREAD_BLOCK_TYPE_SNOOZE);
461e336ebaSIngo Weinholdstatic const SimpleWaitObjectInfo kSignalWaitObjectInfo(
471e336ebaSIngo Weinhold	THREAD_BLOCK_TYPE_SIGNAL);
481e336ebaSIngo Weinhold
491e336ebaSIngo Weinhold
50a63809d3SIngo Weinhold// #pragma mark - CPUInfo
51a63809d3SIngo Weinhold
52a63809d3SIngo Weinhold
53bea40bcdSIngo Weinholdstruct ModelLoader::CPUInfo {
54bea40bcdSIngo Weinhold	nanotime_t	idleTime;
55bea40bcdSIngo Weinhold
56bea40bcdSIngo Weinhold	CPUInfo()
57bea40bcdSIngo Weinhold		:
58bea40bcdSIngo Weinhold		idleTime(0)
59bea40bcdSIngo Weinhold	{
60bea40bcdSIngo Weinhold	}
61bea40bcdSIngo Weinhold};
62bea40bcdSIngo Weinhold
63bea40bcdSIngo Weinhold
64c2354448SIngo Weinhold// #pragma mark - IOOperation
65c2354448SIngo Weinhold
66c2354448SIngo Weinhold
67c2354448SIngo Weinholdstruct ModelLoader::IOOperation : DoublyLinkedListLinkImpl<IOOperation> {
68c2354448SIngo Weinhold	io_operation_started*	startedEvent;
69c2354448SIngo Weinhold	io_operation_finished*	finishedEvent;
70c2354448SIngo Weinhold
71c2354448SIngo Weinhold	IOOperation(io_operation_started* startedEvent)
72c2354448SIngo Weinhold		:
73c2354448SIngo Weinhold		startedEvent(startedEvent),
74c2354448SIngo Weinhold		finishedEvent(NULL)
75c2354448SIngo Weinhold	{
76c2354448SIngo Weinhold	}
77c2354448SIngo Weinhold};
78c2354448SIngo Weinhold
79c2354448SIngo Weinhold
80c2354448SIngo Weinhold// #pragma mark - IORequest
81c2354448SIngo Weinhold
82c2354448SIngo Weinhold
83c2354448SIngo Weinholdstruct ModelLoader::IORequest : DoublyLinkedListLinkImpl<IORequest> {
84c2354448SIngo Weinhold	io_request_scheduled*	scheduledEvent;
85c2354448SIngo Weinhold	io_request_finished*	finishedEvent;
86c2354448SIngo Weinhold	IOOperationList			operations;
87c2354448SIngo Weinhold	size_t					operationCount;
88c2354448SIngo Weinhold	IORequest*				hashNext;
89c2354448SIngo Weinhold
90c2354448SIngo Weinhold	IORequest(io_request_scheduled* scheduledEvent)
91c2354448SIngo Weinhold		:
92c2354448SIngo Weinhold		scheduledEvent(scheduledEvent),
93c2354448SIngo Weinhold		finishedEvent(NULL),
94c2354448SIngo Weinhold		operationCount(0)
95c2354448SIngo Weinhold	{
96c2354448SIngo Weinhold	}
97c2354448SIngo Weinhold
98c2354448SIngo Weinhold	~IORequest()
99c2354448SIngo Weinhold	{
100c2354448SIngo Weinhold		while (IOOperation* operation = operations.RemoveHead())
101c2354448SIngo Weinhold			delete operation;
102c2354448SIngo Weinhold	}
103c2354448SIngo Weinhold
104c2354448SIngo Weinhold	void AddOperation(IOOperation* operation)
105c2354448SIngo Weinhold	{
106c2354448SIngo Weinhold		operations.Add(operation);
107c2354448SIngo Weinhold		operationCount++;
108c2354448SIngo Weinhold	}
109c2354448SIngo Weinhold
110c2354448SIngo Weinhold	IOOperation* FindOperation(void* address) const
111c2354448SIngo Weinhold	{
112c2354448SIngo Weinhold		for (IOOperationList::ConstReverseIterator it
113c2354448SIngo Weinhold				= operations.GetReverseIterator();
114c2354448SIngo Weinhold			IOOperation* operation = it.Next();) {
115c2354448SIngo Weinhold			if (operation->startedEvent->operation == address)
116c2354448SIngo Weinhold				return operation;
117c2354448SIngo Weinhold		}
118c2354448SIngo Weinhold
119c2354448SIngo Weinhold		return NULL;
120c2354448SIngo Weinhold	}
121c2354448SIngo Weinhold
122c2354448SIngo Weinhold	Model::IORequest* CreateModelRequest() const
123c2354448SIngo Weinhold	{
124c2354448SIngo Weinhold		size_t operationCount = operations.Count();
125c2354448SIngo Weinhold
126c2354448SIngo Weinhold		Model::IORequest* modelRequest = Model::IORequest::Create(
127c2354448SIngo Weinhold			scheduledEvent, finishedEvent, operationCount);
128c2354448SIngo Weinhold		if (modelRequest == NULL)
129c2354448SIngo Weinhold			return NULL;
130c2354448SIngo Weinhold
131c2354448SIngo Weinhold		size_t index = 0;
132c2354448SIngo Weinhold		for (IOOperationList::ConstIterator it = operations.GetIterator();
133c2354448SIngo Weinhold				IOOperation* operation = it.Next();) {
134c2354448SIngo Weinhold			Model::IOOperation& modelOperation
135c2354448SIngo Weinhold				= modelRequest->operations[index++];
136c2354448SIngo Weinhold			modelOperation.startedEvent = operation->startedEvent;
137c2354448SIngo Weinhold			modelOperation.finishedEvent = operation->finishedEvent;
138c2354448SIngo Weinhold		}
139c2354448SIngo Weinhold
140c2354448SIngo Weinhold		return modelRequest;
141c2354448SIngo Weinhold	}
142c2354448SIngo Weinhold};
143c2354448SIngo Weinhold
144c2354448SIngo Weinhold
145c2354448SIngo Weinhold// #pragma mark - IORequestHashDefinition
146c2354448SIngo Weinhold
147c2354448SIngo Weinhold
148c2354448SIngo Weinholdstruct ModelLoader::IORequestHashDefinition {
149c2354448SIngo Weinhold	typedef void*		KeyType;
150c2354448SIngo Weinhold	typedef	IORequest	ValueType;
151c2354448SIngo Weinhold
152c2354448SIngo Weinhold	size_t HashKey(KeyType key) const
153c2354448SIngo Weinhold		{ return (size_t)key; }
154c2354448SIngo Weinhold
155c2354448SIngo Weinhold	size_t Hash(const IORequest* value) const
156c2354448SIngo Weinhold		{ return HashKey(value->scheduledEvent->request); }
157c2354448SIngo Weinhold
158c2354448SIngo Weinhold	bool Compare(KeyType key, const IORequest* value) const
159c2354448SIngo Weinhold		{ return key == value->scheduledEvent->request; }
160c2354448SIngo Weinhold
161c2354448SIngo Weinhold	IORequest*& GetLink(IORequest* value) const
162c2354448SIngo Weinhold		{ return value->hashNext; }
163c2354448SIngo Weinhold};
164c2354448SIngo Weinhold
165c2354448SIngo Weinhold
166a63809d3SIngo Weinhold// #pragma mark - ExtendedThreadSchedulingState
167a63809d3SIngo Weinhold
168a63809d3SIngo Weinhold
169a63809d3SIngo Weinholdstruct ModelLoader::ExtendedThreadSchedulingState
170a63809d3SIngo Weinhold		: Model::ThreadSchedulingState {
171a63809d3SIngo Weinhold
172a63809d3SIngo Weinhold	ExtendedThreadSchedulingState(Model::Thread* thread)
173a63809d3SIngo Weinhold		:
174a63809d3SIngo Weinhold		Model::ThreadSchedulingState(thread),
175a63809d3SIngo Weinhold		fEvents(NULL),
176a63809d3SIngo Weinhold		fEventIndex(0),
177a63809d3SIngo Weinhold		fEventCount(0)
178a63809d3SIngo Weinhold	{
179a63809d3SIngo Weinhold	}
180a63809d3SIngo Weinhold
181a63809d3SIngo Weinhold	~ExtendedThreadSchedulingState()
182a63809d3SIngo Weinhold	{
183a63809d3SIngo Weinhold		delete[] fEvents;
184c2354448SIngo Weinhold
185c2354448SIngo Weinhold		while (IORequest* request = fIORequests.RemoveHead())
186c2354448SIngo Weinhold			delete request;
187c2354448SIngo Weinhold		while (IORequest* request = fPendingIORequests.RemoveHead())
188c2354448SIngo Weinhold			delete request;
189a63809d3SIngo Weinhold	}
190a63809d3SIngo Weinhold
191a63809d3SIngo Weinhold	system_profiler_event_header** Events() const
192a63809d3SIngo Weinhold	{
193a63809d3SIngo Weinhold		return fEvents;
194a63809d3SIngo Weinhold	}
195a63809d3SIngo Weinhold
196a63809d3SIngo Weinhold	size_t CountEvents() const
197a63809d3SIngo Weinhold	{
198a63809d3SIngo Weinhold		return fEventCount;
199a63809d3SIngo Weinhold	}
200a63809d3SIngo Weinhold
201a63809d3SIngo Weinhold	system_profiler_event_header** DetachEvents()
202a63809d3SIngo Weinhold	{
203a63809d3SIngo Weinhold		system_profiler_event_header** events = fEvents;
204a63809d3SIngo Weinhold		fEvents = NULL;
205a63809d3SIngo Weinhold		return events;
206a63809d3SIngo Weinhold	}
207a63809d3SIngo Weinhold
208a63809d3SIngo Weinhold	void IncrementEventCount()
209a63809d3SIngo Weinhold	{
210a63809d3SIngo Weinhold		fEventCount++;
211a63809d3SIngo Weinhold	}
212a63809d3SIngo Weinhold
213a63809d3SIngo Weinhold	void AddEvent(system_profiler_event_header* event)
214a63809d3SIngo Weinhold	{
215a63809d3SIngo Weinhold		fEvents[fEventIndex++] = event;
216a63809d3SIngo Weinhold	}
217a63809d3SIngo Weinhold
218a63809d3SIngo Weinhold	bool AllocateEventArray()
219a63809d3SIngo Weinhold	{
220a63809d3SIngo Weinhold		if (fEventCount == 0)
221a63809d3SIngo Weinhold			return true;
222a63809d3SIngo Weinhold
223a63809d3SIngo Weinhold		fEvents = new(std::nothrow) system_profiler_event_header*[fEventCount];
224a63809d3SIngo Weinhold		if (fEvents == NULL)
225a63809d3SIngo Weinhold			return false;
226a63809d3SIngo Weinhold
227a63809d3SIngo Weinhold		return true;
228a63809d3SIngo Weinhold	}
229a63809d3SIngo Weinhold
230c2354448SIngo Weinhold	void AddIORequest(IORequest* request)
231c2354448SIngo Weinhold	{
232c2354448SIngo Weinhold		fPendingIORequests.Add(request);
233c2354448SIngo Weinhold	}
234c2354448SIngo Weinhold
235c2354448SIngo Weinhold	void IORequestFinished(IORequest* request)
236c2354448SIngo Weinhold	{
237c2354448SIngo Weinhold		fPendingIORequests.Remove(request);
238c2354448SIngo Weinhold		fIORequests.Add(request);
239c2354448SIngo Weinhold	}
240c2354448SIngo Weinhold
241c2354448SIngo Weinhold	bool PrepareThreadIORequests(Model::IORequest**& _requests,
242c2354448SIngo Weinhold		size_t& _requestCount)
243c2354448SIngo Weinhold	{
244c2354448SIngo Weinhold		fIORequests.MoveFrom(&fPendingIORequests);
245c2354448SIngo Weinhold		size_t requestCount = fIORequests.Count();
246c2354448SIngo Weinhold
247c2354448SIngo Weinhold		if (requestCount == 0) {
248c2354448SIngo Weinhold			_requests = NULL;
249c2354448SIngo Weinhold			_requestCount = 0;
250c2354448SIngo Weinhold			return true;
251c2354448SIngo Weinhold		}
252c2354448SIngo Weinhold
253c2354448SIngo Weinhold		Model::IORequest** requests
254c2354448SIngo Weinhold			= new(std::nothrow) Model::IORequest*[requestCount];
255c2354448SIngo Weinhold		if (requests == NULL)
256c2354448SIngo Weinhold			return false;
257c2354448SIngo Weinhold
258c2354448SIngo Weinhold		size_t index = 0;
259c2354448SIngo Weinhold		while (IORequest* request = fIORequests.RemoveHead()) {
260c2354448SIngo Weinhold			ObjectDeleter<IORequest> requestDeleter(request);
261c2354448SIngo Weinhold
262c2354448SIngo Weinhold			Model::IORequest* modelRequest = request->CreateModelRequest();
263c2354448SIngo Weinhold			if (modelRequest == NULL) {
264c2354448SIngo Weinhold				for (size_t i = 0; i < index; i++)
265c2354448SIngo Weinhold					requests[i]->Delete();
26699400bbeSFredrik Holmqvist				delete requests;
267c2354448SIngo Weinhold				return false;
268c2354448SIngo Weinhold			}
269c2354448SIngo Weinhold
270c2354448SIngo Weinhold			requests[index++] = modelRequest;
271c2354448SIngo Weinhold		}
272c2354448SIngo Weinhold
273c2354448SIngo Weinhold		_requests = requests;
274c2354448SIngo Weinhold		_requestCount = requestCount;
275c2354448SIngo Weinhold		return true;
276c2354448SIngo Weinhold	}
277c2354448SIngo Weinhold
278a63809d3SIngo Weinholdprivate:
279a63809d3SIngo Weinhold	system_profiler_event_header**	fEvents;
280a63809d3SIngo Weinhold	size_t							fEventIndex;
281a63809d3SIngo Weinhold	size_t							fEventCount;
282c2354448SIngo Weinhold	IORequestList					fIORequests;
283c2354448SIngo Weinhold	IORequestList					fPendingIORequests;
284a63809d3SIngo Weinhold};
285a63809d3SIngo Weinhold
286a63809d3SIngo Weinhold
287a63809d3SIngo Weinhold// #pragma mark - ExtendedSchedulingState
288a63809d3SIngo Weinhold
289a63809d3SIngo Weinhold
290a63809d3SIngo Weinholdstruct ModelLoader::ExtendedSchedulingState : Model::SchedulingState {
291a63809d3SIngo Weinhold	inline ExtendedThreadSchedulingState* LookupThread(thread_id threadID) const
292a63809d3SIngo Weinhold	{
293a63809d3SIngo Weinhold		Model::ThreadSchedulingState* thread
294a63809d3SIngo Weinhold			= Model::SchedulingState::LookupThread(threadID);
295a63809d3SIngo Weinhold		return thread != NULL
296a63809d3SIngo Weinhold			? static_cast<ExtendedThreadSchedulingState*>(thread) : NULL;
297a63809d3SIngo Weinhold	}
298a63809d3SIngo Weinhold
299a63809d3SIngo Weinhold
300a63809d3SIngo Weinholdprotected:
301a63809d3SIngo Weinhold	virtual void DeleteThread(Model::ThreadSchedulingState* thread)
302a63809d3SIngo Weinhold	{
303a63809d3SIngo Weinhold		delete static_cast<ExtendedThreadSchedulingState*>(thread);
304a63809d3SIngo Weinhold	}
305a63809d3SIngo Weinhold};
306a63809d3SIngo Weinhold
307a63809d3SIngo Weinhold
308a63809d3SIngo Weinhold// #pragma mark - ModelLoader
3091e336ebaSIngo Weinhold
3101e336ebaSIngo Weinhold
3119d7f0c33SIngo Weinholdinline void
312d8d4b902SIngo WeinholdModelLoader::_UpdateLastEventTime(nanotime_t time)
3139d7f0c33SIngo Weinhold{
31431391fedSIngo Weinhold	if (fBaseTime < 0) {
3159d7f0c33SIngo Weinhold		fBaseTime = time;
31631391fedSIngo Weinhold		fModel->SetBaseTime(time);
31731391fedSIngo Weinhold	}
3189d7f0c33SIngo Weinhold
319a63809d3SIngo Weinhold	fState->SetLastEventTime(time - fBaseTime);
3209d7f0c33SIngo Weinhold}
3219d7f0c33SIngo Weinhold
3229d7f0c33SIngo Weinhold
3234f1804a1SIngo WeinholdModelLoader::ModelLoader(DataSource* dataSource,
324c442235eSIngo Weinhold	const BMessenger& target, void* targetCookie)
3253dc9bfd1SIngo Weinhold	:
32664d5660eSIngo Weinhold	AbstractModelLoader(target, targetCookie),
3273dc9bfd1SIngo Weinhold	fModel(NULL),
328bea40bcdSIngo Weinhold	fDataSource(dataSource),
329c2354448SIngo Weinhold	fCPUInfos(NULL),
330c2354448SIngo Weinhold	fState(NULL),
331c2354448SIngo Weinhold	fIORequests(NULL)
3323dc9bfd1SIngo Weinhold{
3333dc9bfd1SIngo Weinhold}
3343dc9bfd1SIngo Weinhold
3353dc9bfd1SIngo Weinhold
3364f1804a1SIngo WeinholdModelLoader::~ModelLoader()
3373dc9bfd1SIngo Weinhold{
338bea40bcdSIngo Weinhold	delete[] fCPUInfos;
339c442235eSIngo Weinhold	delete fDataSource;
3403dc9bfd1SIngo Weinhold	delete fModel;
341c2354448SIngo Weinhold	delete fState;
342c2354448SIngo Weinhold	delete fIORequests;
3433dc9bfd1SIngo Weinhold}
3443dc9bfd1SIngo Weinhold
3453dc9bfd1SIngo Weinhold
3464f1804a1SIngo WeinholdModel*
3474f1804a1SIngo WeinholdModelLoader::DetachModel()
3483dc9bfd1SIngo Weinhold{
3493dc9bfd1SIngo Weinhold	AutoLocker<BLocker> locker(fLock);
3503dc9bfd1SIngo Weinhold
3513dc9bfd1SIngo Weinhold	if (fModel == NULL || fLoading)
3523dc9bfd1SIngo Weinhold		return NULL;
3533dc9bfd1SIngo Weinhold
3544f1804a1SIngo Weinhold	Model* model = fModel;
3553dc9bfd1SIngo Weinhold	fModel = NULL;
3563dc9bfd1SIngo Weinhold
3573dc9bfd1SIngo Weinhold	return model;
3583dc9bfd1SIngo Weinhold}
3593dc9bfd1SIngo Weinhold
3603dc9bfd1SIngo Weinhold
36164d5660eSIngo Weinholdstatus_t
36264d5660eSIngo WeinholdModelLoader::PrepareForLoading()
3633dc9bfd1SIngo Weinhold{
36464d5660eSIngo Weinhold	if (fModel != NULL || fDataSource == NULL)
36564d5660eSIngo Weinhold		return B_BAD_VALUE;
36664d5660eSIngo Weinhold
367a63809d3SIngo Weinhold	// create and init the state
368a63809d3SIngo Weinhold	fState = new(std::nothrow) ExtendedSchedulingState;
369a63809d3SIngo Weinhold	if (fState == NULL)
370a63809d3SIngo Weinhold		return B_NO_MEMORY;
371a63809d3SIngo Weinhold
372a63809d3SIngo Weinhold	status_t error = fState->Init();
37364d5660eSIngo Weinhold	if (error != B_OK)
37464d5660eSIngo Weinhold		return error;
37564d5660eSIngo Weinhold
376c2354448SIngo Weinhold	// create CPU info array
377bea40bcdSIngo Weinhold	fCPUInfos = new(std::nothrow) CPUInfo[kMaxCPUCount];
378bea40bcdSIngo Weinhold	if (fCPUInfos == NULL)
379bea40bcdSIngo Weinhold		return B_NO_MEMORY;
380bea40bcdSIngo Weinhold
381c2354448SIngo Weinhold	// create IORequest hash table
382c2354448SIngo Weinhold	fIORequests = new(std::nothrow) IORequestTable;
383c2354448SIngo Weinhold	if (fIORequests == NULL || fIORequests->Init() != B_OK)
384c2354448SIngo Weinhold		return B_NO_MEMORY;
385c2354448SIngo Weinhold
38664d5660eSIngo Weinhold	return B_OK;
3873dc9bfd1SIngo Weinhold}
3883dc9bfd1SIngo Weinhold
3893dc9bfd1SIngo Weinhold
3903dc9bfd1SIngo Weinholdstatus_t
39164d5660eSIngo WeinholdModelLoader::Load()
3923dc9bfd1SIngo Weinhold{
3933dc9bfd1SIngo Weinhold	try {
39464d5660eSIngo Weinhold		return _Load();
395c442235eSIngo Weinhold	} catch(...) {
39664d5660eSIngo Weinhold		return B_ERROR;
3973dc9bfd1SIngo Weinhold	}
39864d5660eSIngo Weinhold}
39931391fedSIngo Weinhold
4003dc9bfd1SIngo Weinhold
40164d5660eSIngo Weinholdvoid
40264d5660eSIngo WeinholdModelLoader::FinishLoading(bool success)
40364d5660eSIngo Weinhold{
404a63809d3SIngo Weinhold	delete fState;
405a63809d3SIngo Weinhold	fState = NULL;
4061e336ebaSIngo Weinhold
40764d5660eSIngo Weinhold	if (!success) {
4083dc9bfd1SIngo Weinhold		delete fModel;
4093dc9bfd1SIngo Weinhold		fModel = NULL;
4103dc9bfd1SIngo Weinhold	}
411bea40bcdSIngo Weinhold
412bea40bcdSIngo Weinhold	delete[] fCPUInfos;
413bea40bcdSIngo Weinhold	fCPUInfos = NULL;
414c2354448SIngo Weinhold
415d4e7d2deSIngo Weinhold	delete fIORequests;
416d4e7d2deSIngo Weinhold	fIORequests = NULL;
4173dc9bfd1SIngo Weinhold}
4183dc9bfd1SIngo Weinhold
4193dc9bfd1SIngo Weinhold
420c442235eSIngo Weinholdstatus_t
4214f1804a1SIngo WeinholdModelLoader::_Load()
422c442235eSIngo Weinhold{
42308e34e27SIngo Weinhold	// read the complete data into memory
42408e34e27SIngo Weinhold	void* eventData;
42508e34e27SIngo Weinhold	size_t eventDataSize;
42608e34e27SIngo Weinhold	status_t error = _ReadDebugEvents(&eventData, &eventDataSize);
427c442235eSIngo Weinhold	if (error != B_OK)
428c442235eSIngo Weinhold		return error;
4296d5e661dSIngo Weinhold	MemoryDeleter eventDataDeleter(eventData);
4306d5e661dSIngo Weinhold
4316d5e661dSIngo Weinhold	// create a debug event array
4326d5e661dSIngo Weinhold	system_profiler_event_header** events;
4336d5e661dSIngo Weinhold	size_t eventCount;
4346d5e661dSIngo Weinhold	error = _CreateDebugEventArray(eventData, eventDataSize, events,
4356d5e661dSIngo Weinhold		eventCount);
4366d5e661dSIngo Weinhold	if (error != B_OK)
4376d5e661dSIngo Weinhold		return error;
4386d5e661dSIngo Weinhold	ArrayDeleter<system_profiler_event_header*> eventsDeleter(events);
43908e34e27SIngo Weinhold
44031391fedSIngo Weinhold	// get the data source name
44131391fedSIngo Weinhold	BString dataSourceName;
44231391fedSIngo Weinhold	fDataSource->GetName(dataSourceName);
44331391fedSIngo Weinhold
44408e34e27SIngo Weinhold	// create a model
44531391fedSIngo Weinhold	fModel = new(std::nothrow) Model(dataSourceName.String(), eventData,
4466d5e661dSIngo Weinhold		eventDataSize, events, eventCount);
4476d5e661dSIngo Weinhold	if (fModel == NULL)
44808e34e27SIngo Weinhold		return B_NO_MEMORY;
4496d5e661dSIngo Weinhold	eventDataDeleter.Detach();
4506d5e661dSIngo Weinhold	eventsDeleter.Detach();
451c442235eSIngo Weinhold
452c442235eSIngo Weinhold	// create a debug input stream
4536d5e661dSIngo Weinhold	BDebugEventInputStream input;
4546d5e661dSIngo Weinhold	error = input.SetTo(eventData, eventDataSize, false);
455c442235eSIngo Weinhold	if (error != B_OK)
456c442235eSIngo Weinhold		return error;
457c442235eSIngo Weinhold
4581e336ebaSIngo Weinhold	// add the snooze and signal wait objects to the model
4591e336ebaSIngo Weinhold	if (fModel->AddWaitObject(&kSnoozeWaitObjectInfo, NULL) == NULL
4601e336ebaSIngo Weinhold		|| fModel->AddWaitObject(&kSignalWaitObjectInfo, NULL) == NULL) {
4611e336ebaSIngo Weinhold		return B_NO_MEMORY;
4621e336ebaSIngo Weinhold	}
4631e336ebaSIngo Weinhold
464c442235eSIngo Weinhold	// process the events
465bea40bcdSIngo Weinhold	fMaxCPUIndex = 0;
466a63809d3SIngo Weinhold	fState->Clear();
4679d7f0c33SIngo Weinhold	fBaseTime = -1;
468d4d63490SIngo Weinhold	uint64 count = 0;
469c442235eSIngo Weinhold
470c442235eSIngo Weinhold	while (true) {
471c442235eSIngo Weinhold		// get next event
472c442235eSIngo Weinhold		uint32 event;
473c442235eSIngo Weinhold		uint32 cpu;
474c442235eSIngo Weinhold		const void* buffer;
475d4d63490SIngo Weinhold		off_t offset;
4766d5e661dSIngo Weinhold		ssize_t bufferSize = input.ReadNextEvent(&event, &cpu, &buffer,
477d4d63490SIngo Weinhold			&offset);
478c442235eSIngo Weinhold		if (bufferSize < 0)
479c442235eSIngo Weinhold			return bufferSize;
480c442235eSIngo Weinhold		if (buffer == NULL)
48131391fedSIngo Weinhold			break;
482c442235eSIngo Weinhold
483c442235eSIngo Weinhold		// process the event
484c442235eSIngo Weinhold		status_t error = _ProcessEvent(event, cpu, buffer, bufferSize);
485c442235eSIngo Weinhold		if (error != B_OK)
486c442235eSIngo Weinhold			return error;
487c442235eSIngo Weinhold
488bea40bcdSIngo Weinhold		if (cpu > fMaxCPUIndex) {
489bea40bcdSIngo Weinhold			if (cpu + 1 > kMaxCPUCount)
490bea40bcdSIngo Weinhold				return B_BAD_DATA;
491bea40bcdSIngo Weinhold			fMaxCPUIndex = cpu;
492bea40bcdSIngo Weinhold		}
493bea40bcdSIngo Weinhold
494c442235eSIngo Weinhold		// periodically check whether we're supposed to abort
495c442235eSIngo Weinhold		if (++count % 32 == 0) {
496c442235eSIngo Weinhold			AutoLocker<BLocker> locker(fLock);
497c442235eSIngo Weinhold			if (fAborted)
498c442235eSIngo Weinhold				return B_ERROR;
499c442235eSIngo Weinhold		}
500d4d63490SIngo Weinhold
501d4d63490SIngo Weinhold		// periodically add scheduling snapshots
502d4d63490SIngo Weinhold		if (count % kSchedulingSnapshotInterval == 0)
503a63809d3SIngo Weinhold			fModel->AddSchedulingStateSnapshot(*fState, offset);
504c442235eSIngo Weinhold	}
50531391fedSIngo Weinhold
506bea40bcdSIngo Weinhold	if (!fModel->SetCPUCount(fMaxCPUIndex + 1))
507bea40bcdSIngo Weinhold		return B_NO_MEMORY;
508bea40bcdSIngo Weinhold
509bea40bcdSIngo Weinhold	for (uint32 i = 0; i <= fMaxCPUIndex; i++)
510bea40bcdSIngo Weinhold		fModel->CPUAt(i)->SetIdleTime(fCPUInfos[i].idleTime);
511bea40bcdSIngo Weinhold
512a63809d3SIngo Weinhold	fModel->SetLastEventTime(fState->LastEventTime());
513a63809d3SIngo Weinhold
514c2354448SIngo Weinhold	if (!_SetThreadEvents() || !_SetThreadIORequests())
515a63809d3SIngo Weinhold		return B_NO_MEMORY;
516a63809d3SIngo Weinhold
517d4d63490SIngo Weinhold	fModel->LoadingFinished();
51831391fedSIngo Weinhold
51931391fedSIngo Weinhold	return B_OK;
520c442235eSIngo Weinhold}
521c442235eSIngo Weinhold
522c442235eSIngo Weinhold
52308e34e27SIngo Weinholdstatus_t
52408e34e27SIngo WeinholdModelLoader::_ReadDebugEvents(void** _eventData, size_t* _size)
52508e34e27SIngo Weinhold{
52608e34e27SIngo Weinhold	// get a BDataIO from the data source
52708e34e27SIngo Weinhold	BDataIO* io;
52808e34e27SIngo Weinhold	status_t error = fDataSource->CreateDataIO(&io);
52908e34e27SIngo Weinhold	if (error != B_OK)
53008e34e27SIngo Weinhold		return error;
53108e34e27SIngo Weinhold	ObjectDeleter<BDataIO> dataIOtDeleter(io);
53208e34e27SIngo Weinhold
53308e34e27SIngo Weinhold	// First we need to find out how large a buffer to allocate.
53408e34e27SIngo Weinhold	size_t size;
53508e34e27SIngo Weinhold
53608e34e27SIngo Weinhold	if (BPositionIO* positionIO = dynamic_cast<BPositionIO*>(io)) {
53708e34e27SIngo Weinhold		// it's a BPositionIO -- this makes things easier, since we know how
53808e34e27SIngo Weinhold		// many bytes to read
53908e34e27SIngo Weinhold		off_t currentPos = positionIO->Position();
54008e34e27SIngo Weinhold		if (currentPos < 0)
54108e34e27SIngo Weinhold			return currentPos;
54208e34e27SIngo Weinhold
54308e34e27SIngo Weinhold		off_t fileSize;
54408e34e27SIngo Weinhold		error = positionIO->GetSize(&fileSize);
54508e34e27SIngo Weinhold		if (error != B_OK)
54608e34e27SIngo Weinhold			return error;
54708e34e27SIngo Weinhold
54808e34e27SIngo Weinhold		size = fileSize - currentPos;
54908e34e27SIngo Weinhold	} else {
55008e34e27SIngo Weinhold		// no BPositionIO -- we need to determine the total size by iteratively
55108e34e27SIngo Weinhold		// reading the whole data one time
55208e34e27SIngo Weinhold
55308e34e27SIngo Weinhold		// allocate a dummy buffer for reading
55408e34e27SIngo Weinhold		const size_t kBufferSize = 1024 * 1024;
55508e34e27SIngo Weinhold		void* buffer = malloc(kBufferSize);
55608e34e27SIngo Weinhold		if (buffer == NULL)
55708e34e27SIngo Weinhold			return B_NO_MEMORY;
55808e34e27SIngo Weinhold		MemoryDeleter bufferDeleter(buffer);
55908e34e27SIngo Weinhold
56008e34e27SIngo Weinhold		size = 0;
56108e34e27SIngo Weinhold		while (true) {
56208e34e27SIngo Weinhold			ssize_t bytesRead = io->Read(buffer, kBufferSize);
56308e34e27SIngo Weinhold			if (bytesRead < 0)
56408e34e27SIngo Weinhold				return bytesRead;
56508e34e27SIngo Weinhold			if (bytesRead == 0)
56608e34e27SIngo Weinhold				break;
56708e34e27SIngo Weinhold
56808e34e27SIngo Weinhold			size += bytesRead;
56908e34e27SIngo Weinhold		}
57008e34e27SIngo Weinhold
57108e34e27SIngo Weinhold		// we've got the size -- recreate the BDataIO
57208e34e27SIngo Weinhold		dataIOtDeleter.Delete();
57308e34e27SIngo Weinhold		error = fDataSource->CreateDataIO(&io);
57408e34e27SIngo Weinhold		if (error != B_OK)
57508e34e27SIngo Weinhold			return error;
57608e34e27SIngo Weinhold		dataIOtDeleter.SetTo(io);
57708e34e27SIngo Weinhold	}
57808e34e27SIngo Weinhold
57908e34e27SIngo Weinhold	// allocate the data buffer
58008e34e27SIngo Weinhold	void* data = malloc(size);
58108e34e27SIngo Weinhold	if (data == NULL)
58208e34e27SIngo Weinhold		return B_NO_MEMORY;
58308e34e27SIngo Weinhold	MemoryDeleter dataDeleter(data);
58408e34e27SIngo Weinhold
58508e34e27SIngo Weinhold	// read the data
58608e34e27SIngo Weinhold	ssize_t bytesRead = io->Read(data, size);
58708e34e27SIngo Weinhold	if (bytesRead < 0)
58808e34e27SIngo Weinhold		return bytesRead;
58908e34e27SIngo Weinhold	if ((size_t)bytesRead != size)
59008e34e27SIngo Weinhold		return B_FILE_ERROR;
59108e34e27SIngo Weinhold
59208e34e27SIngo Weinhold	dataDeleter.Detach();
59308e34e27SIngo Weinhold	*_eventData = data;
59408e34e27SIngo Weinhold	*_size = size;
59508e34e27SIngo Weinhold	return B_OK;
59608e34e27SIngo Weinhold}
59708e34e27SIngo Weinhold
59808e34e27SIngo Weinhold
5996d5e661dSIngo Weinholdstatus_t
6006d5e661dSIngo WeinholdModelLoader::_CreateDebugEventArray(void* eventData, size_t eventDataSize,
6016d5e661dSIngo Weinhold	system_profiler_event_header**& _events, size_t& _eventCount)
6026d5e661dSIngo Weinhold{
6036d5e661dSIngo Weinhold	// count the events
6046d5e661dSIngo Weinhold	BDebugEventInputStream input;
6056d5e661dSIngo Weinhold	status_t error = input.SetTo(eventData, eventDataSize, false);
6066d5e661dSIngo Weinhold	if (error != B_OK)
6076d5e661dSIngo Weinhold		return error;
6086d5e661dSIngo Weinhold
6096d5e661dSIngo Weinhold	size_t eventCount = 0;
6106d5e661dSIngo Weinhold	while (true) {
6116d5e661dSIngo Weinhold		// get next event
6126d5e661dSIngo Weinhold		uint32 event;
6136d5e661dSIngo Weinhold		uint32 cpu;
6146d5e661dSIngo Weinhold		const void* buffer;
6156d5e661dSIngo Weinhold		ssize_t bufferSize = input.ReadNextEvent(&event, &cpu, &buffer, NULL);
6166d5e661dSIngo Weinhold		if (bufferSize < 0)
6176d5e661dSIngo Weinhold			return bufferSize;
6186d5e661dSIngo Weinhold		if (buffer == NULL)
6196d5e661dSIngo Weinhold			break;
6206d5e661dSIngo Weinhold
6216d5e661dSIngo Weinhold		eventCount++;
6226d5e661dSIngo Weinhold	}
6236d5e661dSIngo Weinhold
6246d5e661dSIngo Weinhold	// create the array
6256d5e661dSIngo Weinhold	system_profiler_event_header** events = new(std::nothrow)
6266d5e661dSIngo Weinhold		system_profiler_event_header*[eventCount];
6276d5e661dSIngo Weinhold	if (events == NULL)
6286d5e661dSIngo Weinhold		return B_NO_MEMORY;
6296d5e661dSIngo Weinhold
6306d5e661dSIngo Weinhold	// populate the array
6316d5e661dSIngo Weinhold	error = input.SetTo(eventData, eventDataSize, false);
6326d5e661dSIngo Weinhold	if (error != B_OK) {
6336d5e661dSIngo Weinhold		delete[] events;
6346d5e661dSIngo Weinhold		return error;
6356d5e661dSIngo Weinhold	}
6366d5e661dSIngo Weinhold
6376d5e661dSIngo Weinhold	size_t eventIndex = 0;
6386d5e661dSIngo Weinhold	while (true) {
6396d5e661dSIngo Weinhold		// get next event
6406d5e661dSIngo Weinhold		uint32 event;
6416d5e661dSIngo Weinhold		uint32 cpu;
6426d5e661dSIngo Weinhold		const void* buffer;
6436d5e661dSIngo Weinhold		off_t offset;
6446d5e661dSIngo Weinhold		input.ReadNextEvent(&event, &cpu, &buffer, &offset);
6456d5e661dSIngo Weinhold		if (buffer == NULL)
6466d5e661dSIngo Weinhold			break;
6476d5e661dSIngo Weinhold
6486d5e661dSIngo Weinhold		events[eventIndex++]
6496d5e661dSIngo Weinhold			= (system_profiler_event_header*)((uint8*)eventData + offset);
6506d5e661dSIngo Weinhold	}
6516d5e661dSIngo Weinhold
6526d5e661dSIngo Weinhold	_events = events;
6536d5e661dSIngo Weinhold	_eventCount = eventCount;
6546d5e661dSIngo Weinhold	return B_OK;
6556d5e661dSIngo Weinhold}
6566d5e661dSIngo Weinhold
6576d5e661dSIngo Weinhold
6583dc9bfd1SIngo Weinholdstatus_t
6594f1804a1SIngo WeinholdModelLoader::_ProcessEvent(uint32 event, uint32 cpu, const void* buffer,
6603dc9bfd1SIngo Weinhold	size_t size)
6613dc9bfd1SIngo Weinhold{
662c442235eSIngo Weinhold	switch (event) {
663c442235eSIngo Weinhold		case B_SYSTEM_PROFILER_TEAM_ADDED:
6641e336ebaSIngo Weinhold			_HandleTeamAdded((system_profiler_team_added*)buffer);
6651e336ebaSIngo Weinhold			break;
66608e34e27SIngo Weinhold
667c442235eSIngo Weinhold		case B_SYSTEM_PROFILER_TEAM_REMOVED:
6681e336ebaSIngo Weinhold			_HandleTeamRemoved((system_profiler_team_removed*)buffer);
669c442235eSIngo Weinhold			break;
67008e34e27SIngo Weinhold
671c442235eSIngo Weinhold		case B_SYSTEM_PROFILER_TEAM_EXEC:
6721e336ebaSIngo Weinhold			_HandleTeamExec((system_profiler_team_exec*)buffer);
673c442235eSIngo Weinhold			break;
67408e34e27SIngo Weinhold
675c442235eSIngo Weinhold		case B_SYSTEM_PROFILER_THREAD_ADDED:
6761e336ebaSIngo Weinhold			_HandleThreadAdded((system_profiler_thread_added*)buffer);
677c442235eSIngo Weinhold			break;
67808e34e27SIngo Weinhold
679c442235eSIngo Weinhold		case B_SYSTEM_PROFILER_THREAD_REMOVED:
6801e336ebaSIngo Weinhold			_HandleThreadRemoved((system_profiler_thread_removed*)buffer);
681c442235eSIngo Weinhold			break;
68208e34e27SIngo Weinhold
683c442235eSIngo Weinhold		case B_SYSTEM_PROFILER_THREAD_SCHEDULED:
684bea40bcdSIngo Weinhold			_HandleThreadScheduled(cpu,
685bea40bcdSIngo Weinhold				(system_profiler_thread_scheduled*)buffer);
686c442235eSIngo Weinhold			break;
6879d7f0c33SIngo Weinhold
688c442235eSIngo Weinhold		case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE:
6891e336ebaSIngo Weinhold			_HandleThreadEnqueuedInRunQueue(
6901e336ebaSIngo Weinhold				(thread_enqueued_in_run_queue*)buffer);
691c442235eSIngo Weinhold			break;
6929d7f0c33SIngo Weinhold
693c442235eSIngo Weinhold		case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE:
694bea40bcdSIngo Weinhold			_HandleThreadRemovedFromRunQueue(cpu,
6951e336ebaSIngo Weinhold				(thread_removed_from_run_queue*)buffer);
696c442235eSIngo Weinhold			break;
6979d7f0c33SIngo Weinhold
698c442235eSIngo Weinhold		case B_SYSTEM_PROFILER_WAIT_OBJECT_INFO:
6991e336ebaSIngo Weinhold			_HandleWaitObjectInfo((system_profiler_wait_object_info*)buffer);
700c442235eSIngo Weinhold			break;
7011e336ebaSIngo Weinhold
70283f19b67SIngo Weinhold		case B_SYSTEM_PROFILER_IO_SCHEDULER_ADDED:
703934a8d01SIngo Weinhold			_HandleIOSchedulerAdded(
704934a8d01SIngo Weinhold				(system_profiler_io_scheduler_added*)buffer);
705934a8d01SIngo Weinhold			break;
706934a8d01SIngo Weinhold
70783f19b67SIngo Weinhold		case B_SYSTEM_PROFILER_IO_SCHEDULER_REMOVED:
708934a8d01SIngo Weinhold			// not so interesting
709c2354448SIngo Weinhold			break;
710c2354448SIngo Weinhold
71183f19b67SIngo Weinhold		case B_SYSTEM_PROFILER_IO_REQUEST_SCHEDULED:
712c2354448SIngo Weinhold			_HandleIORequestScheduled((io_request_scheduled*)buffer);
713c2354448SIngo Weinhold			break;
71483f19b67SIngo Weinhold		case B_SYSTEM_PROFILER_IO_REQUEST_FINISHED:
715c2354448SIngo Weinhold			_HandleIORequestFinished((io_request_finished*)buffer);
716c2354448SIngo Weinhold			break;
71783f19b67SIngo Weinhold		case B_SYSTEM_PROFILER_IO_OPERATION_STARTED:
718c2354448SIngo Weinhold			_HandleIOOperationStarted((io_operation_started*)buffer);
719c2354448SIngo Weinhold			break;
72083f19b67SIngo Weinhold		case B_SYSTEM_PROFILER_IO_OPERATION_FINISHED:
721c2354448SIngo Weinhold			_HandleIOOperationFinished((io_operation_finished*)buffer);
72283f19b67SIngo Weinhold			break;
72383f19b67SIngo Weinhold
724c442235eSIngo Weinhold		default:
725883b3e1dSMichael Lotz			printf("unsupported event type %" B_PRIu32 ", size: %" B_PRIuSIZE
726883b3e1dSMichael Lotz				"\n", event, size);
727883b3e1dSMichael Lotz			return B_BAD_DATA;
728c442235eSIngo Weinhold	}
729c442235eSIngo Weinhold
730c442235eSIngo Weinhold	return B_OK;
7313dc9bfd1SIngo Weinhold}
7321e336ebaSIngo Weinhold
7331e336ebaSIngo Weinhold
734a63809d3SIngo Weinholdbool
735a63809d3SIngo WeinholdModelLoader::_SetThreadEvents()
736a63809d3SIngo Weinhold{
737a63809d3SIngo Weinhold	// allocate the threads' events arrays
738a63809d3SIngo Weinhold	for (int32 i = 0; Model::Thread* thread = fModel->ThreadAt(i); i++) {
739a63809d3SIngo Weinhold		ExtendedThreadSchedulingState* state
740a63809d3SIngo Weinhold			= fState->LookupThread(thread->ID());
741a63809d3SIngo Weinhold		if (!state->AllocateEventArray())
742a63809d3SIngo Weinhold			return false;
743a63809d3SIngo Weinhold	}
744a63809d3SIngo Weinhold
745a63809d3SIngo Weinhold	// fill the threads' event arrays
746a63809d3SIngo Weinhold	system_profiler_event_header** events = fModel->Events();
747a63809d3SIngo Weinhold	size_t eventCount = fModel->CountEvents();
748a63809d3SIngo Weinhold	for (size_t i = 0; i < eventCount; i++) {
749a63809d3SIngo Weinhold		system_profiler_event_header* header = events[i];
750a63809d3SIngo Weinhold		void* buffer = header + 1;
751a63809d3SIngo Weinhold
752a63809d3SIngo Weinhold		switch (header->event) {
753a63809d3SIngo Weinhold			case B_SYSTEM_PROFILER_THREAD_ADDED:
754a63809d3SIngo Weinhold			{
755a63809d3SIngo Weinhold				system_profiler_thread_added* event
756a63809d3SIngo Weinhold					= (system_profiler_thread_added*)buffer;
757a63809d3SIngo Weinhold				fState->LookupThread(event->thread)->AddEvent(header);
758a63809d3SIngo Weinhold				break;
759a63809d3SIngo Weinhold			}
760a63809d3SIngo Weinhold
761a63809d3SIngo Weinhold			case B_SYSTEM_PROFILER_THREAD_REMOVED:
762a63809d3SIngo Weinhold			{
763a63809d3SIngo Weinhold				system_profiler_thread_removed* event
764a63809d3SIngo Weinhold					= (system_profiler_thread_removed*)buffer;
765a63809d3SIngo Weinhold				fState->LookupThread(event->thread)->AddEvent(header);
766a63809d3SIngo Weinhold				break;
767a63809d3SIngo Weinhold			}
768a63809d3SIngo Weinhold
769a63809d3SIngo Weinhold			case B_SYSTEM_PROFILER_THREAD_SCHEDULED:
770a63809d3SIngo Weinhold			{
771a63809d3SIngo Weinhold				system_profiler_thread_scheduled* event
772a63809d3SIngo Weinhold					= (system_profiler_thread_scheduled*)buffer;
773a63809d3SIngo Weinhold				fState->LookupThread(event->thread)->AddEvent(header);
774a63809d3SIngo Weinhold
775a63809d3SIngo Weinhold				if (event->thread != event->previous_thread) {
776a63809d3SIngo Weinhold					fState->LookupThread(event->previous_thread)
777a63809d3SIngo Weinhold						->AddEvent(header);
778a63809d3SIngo Weinhold				}
779a63809d3SIngo Weinhold				break;
780a63809d3SIngo Weinhold			}
781a63809d3SIngo Weinhold
782a63809d3SIngo Weinhold			case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE:
783a63809d3SIngo Weinhold			{
784a63809d3SIngo Weinhold				thread_enqueued_in_run_queue* event
785a63809d3SIngo Weinhold					= (thread_enqueued_in_run_queue*)buffer;
786a63809d3SIngo Weinhold				fState->LookupThread(event->thread)->AddEvent(header);
787a63809d3SIngo Weinhold				break;
788a63809d3SIngo Weinhold			}
789a63809d3SIngo Weinhold
790a63809d3SIngo Weinhold			case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE:
791a63809d3SIngo Weinhold			{
792a63809d3SIngo Weinhold				thread_removed_from_run_queue* event
793a63809d3SIngo Weinhold					= (thread_removed_from_run_queue*)buffer;
794a63809d3SIngo Weinhold				fState->LookupThread(event->thread)->AddEvent(header);
795a63809d3SIngo Weinhold				break;
796a63809d3SIngo Weinhold			}
797a63809d3SIngo Weinhold
798a63809d3SIngo Weinhold			default:
799a63809d3SIngo Weinhold				break;
800a63809d3SIngo Weinhold		}
801a63809d3SIngo Weinhold	}
802a63809d3SIngo Weinhold
803a63809d3SIngo Weinhold	// transfer the events arrays from the scheduling states to the thread
804a63809d3SIngo Weinhold	// objects
805a63809d3SIngo Weinhold	for (int32 i = 0; Model::Thread* thread = fModel->ThreadAt(i); i++) {
806a63809d3SIngo Weinhold		ExtendedThreadSchedulingState* state
807a63809d3SIngo Weinhold			= fState->LookupThread(thread->ID());
808a63809d3SIngo Weinhold		thread->SetEvents(state->Events(), state->CountEvents());
809a63809d3SIngo Weinhold		state->DetachEvents();
810a63809d3SIngo Weinhold	}
811a63809d3SIngo Weinhold
812a63809d3SIngo Weinhold	return true;
813a63809d3SIngo Weinhold}
814a63809d3SIngo Weinhold
815a63809d3SIngo Weinhold
816c2354448SIngo Weinholdbool
817c2354448SIngo WeinholdModelLoader::_SetThreadIORequests()
818c2354448SIngo Weinhold{
819c2354448SIngo Weinhold	for (int32 i = 0; Model::Thread* thread = fModel->ThreadAt(i); i++) {
820c2354448SIngo Weinhold		ExtendedThreadSchedulingState* state
821c2354448SIngo Weinhold			= fState->LookupThread(thread->ID());
822c2354448SIngo Weinhold		Model::IORequest** requests;
823c2354448SIngo Weinhold		size_t requestCount;
824c2354448SIngo Weinhold		if (!state->PrepareThreadIORequests(requests, requestCount))
825c2354448SIngo Weinhold			return false;
826c2354448SIngo Weinhold		if (requestCount > 0)
827c2354448SIngo Weinhold			_SetThreadIORequests(thread, requests, requestCount);
828c2354448SIngo Weinhold	}
829c2354448SIngo Weinhold
830c2354448SIngo Weinhold	return true;
831c2354448SIngo Weinhold}
832c2354448SIngo Weinhold
833c2354448SIngo Weinhold
834c2354448SIngo Weinholdvoid
835c2354448SIngo WeinholdModelLoader::_SetThreadIORequests(Model::Thread* thread,
836c2354448SIngo Weinhold	Model::IORequest** requests, size_t requestCount)
837c2354448SIngo Weinhold{
838c2354448SIngo Weinhold	// compute some totals
839c2354448SIngo Weinhold	int64 ioCount = 0;
840c2354448SIngo Weinhold	nanotime_t ioTime = 0;
841c2354448SIngo Weinhold
842c2354448SIngo Weinhold	// sort requests by scheduler and start time
843c2354448SIngo Weinhold	std::sort(requests, requests + requestCount,
844c2354448SIngo Weinhold		Model::IORequest::SchedulerTimeLess);
845c2354448SIngo Weinhold
846c2354448SIngo Weinhold	nanotime_t endTime = fBaseTime + fModel->LastEventTime();
847c2354448SIngo Weinhold
848c2354448SIngo Weinhold	// compute the summed up I/O times
849c2354448SIngo Weinhold	nanotime_t ioStart = requests[0]->scheduledEvent->time;
850c2354448SIngo Weinhold	nanotime_t previousEnd = requests[0]->finishedEvent != NULL
851c2354448SIngo Weinhold		? requests[0]->finishedEvent->time : endTime;
852c2354448SIngo Weinhold	int32 scheduler = requests[0]->scheduledEvent->scheduler;
853c2354448SIngo Weinhold
854c2354448SIngo Weinhold	for (size_t i = 1; i < requestCount; i++) {
855c2354448SIngo Weinhold		system_profiler_io_request_scheduled* scheduledEvent
856c2354448SIngo Weinhold			= requests[i]->scheduledEvent;
857c2354448SIngo Weinhold		if (scheduledEvent->scheduler != scheduler
858c2354448SIngo Weinhold			|| scheduledEvent->time >= previousEnd) {
859c2354448SIngo Weinhold			ioCount++;
860c2354448SIngo Weinhold			ioTime += previousEnd - ioStart;
861c2354448SIngo Weinhold			ioStart = scheduledEvent->time;
862c2354448SIngo Weinhold		}
863c2354448SIngo Weinhold
864c2354448SIngo Weinhold		previousEnd = requests[i]->finishedEvent != NULL
865c2354448SIngo Weinhold			? requests[i]->finishedEvent->time : endTime;
866c2354448SIngo Weinhold	}
867c2354448SIngo Weinhold
868c2354448SIngo Weinhold	ioCount++;
869c2354448SIngo Weinhold	ioTime += previousEnd - ioStart;
870c2354448SIngo Weinhold
871934a8d01SIngo Weinhold	// sort requests by start time
872934a8d01SIngo Weinhold	std::sort(requests, requests + requestCount, Model::IORequest::TimeLess);
873934a8d01SIngo Weinhold
874c2354448SIngo Weinhold	// set the computed values
875c2354448SIngo Weinhold	thread->SetIORequests(requests, requestCount);
876c2354448SIngo Weinhold	thread->SetIOs(ioCount, ioTime);
877c2354448SIngo Weinhold}
878c2354448SIngo Weinhold
879c2354448SIngo Weinhold
8801e336ebaSIngo Weinholdvoid
8811e336ebaSIngo WeinholdModelLoader::_HandleTeamAdded(system_profiler_team_added* event)
8821e336ebaSIngo Weinhold{
883a63809d3SIngo Weinhold	if (fModel->AddTeam(event, fState->LastEventTime()) == NULL)
8841e336ebaSIngo Weinhold		throw std::bad_alloc();
8851e336ebaSIngo Weinhold}
8861e336ebaSIngo Weinhold
8871e336ebaSIngo Weinhold
8881e336ebaSIngo Weinholdvoid
8891e336ebaSIngo WeinholdModelLoader::_HandleTeamRemoved(system_profiler_team_removed* event)
8901e336ebaSIngo Weinhold{
8911e336ebaSIngo Weinhold	if (Model::Team* team = fModel->TeamByID(event->team))
892a63809d3SIngo Weinhold		team->SetDeletionTime(fState->LastEventTime());
893883b3e1dSMichael Lotz	else {
894883b3e1dSMichael Lotz		printf("Warning: Removed event for unknown team: %" B_PRId32 "\n",
895883b3e1dSMichael Lotz			event->team);
896883b3e1dSMichael Lotz	}
8971e336ebaSIngo Weinhold}
8981e336ebaSIngo Weinhold
8991e336ebaSIngo Weinhold
9001e336ebaSIngo Weinholdvoid
9011e336ebaSIngo WeinholdModelLoader::_HandleTeamExec(system_profiler_team_exec* event)
9021e336ebaSIngo Weinhold{
9031e336ebaSIngo Weinhold	// TODO:...
9041e336ebaSIngo Weinhold}
9051e336ebaSIngo Weinhold
9061e336ebaSIngo Weinhold
9071e336ebaSIngo Weinholdvoid
9081e336ebaSIngo WeinholdModelLoader::_HandleThreadAdded(system_profiler_thread_added* event)
9091e336ebaSIngo Weinhold{
9105b78a987SIngo Weinhold	_AddThread(event)->IncrementEventCount();
9111e336ebaSIngo Weinhold}
9121e336ebaSIngo Weinhold
9131e336ebaSIngo Weinhold
9141e336ebaSIngo Weinholdvoid
9151e336ebaSIngo WeinholdModelLoader::_HandleThreadRemoved(system_profiler_thread_removed* event)
9161e336ebaSIngo Weinhold{
917a63809d3SIngo Weinhold	ExtendedThreadSchedulingState* thread = fState->LookupThread(event->thread);
9185b78a987SIngo Weinhold	if (thread == NULL) {
919883b3e1dSMichael Lotz		printf("Warning: Removed event for unknown thread: %" B_PRId32 "\n",
9205b78a987SIngo Weinhold			event->thread);
9215b78a987SIngo Weinhold		thread = _AddUnknownThread(event->thread);
9225b78a987SIngo Weinhold	}
9235b78a987SIngo Weinhold
9245b78a987SIngo Weinhold	thread->thread->SetDeletionTime(fState->LastEventTime());
9255b78a987SIngo Weinhold	thread->IncrementEventCount();
9261e336ebaSIngo Weinhold}
9271e336ebaSIngo Weinhold
9281e336ebaSIngo Weinhold
9291e336ebaSIngo Weinholdvoid
930bea40bcdSIngo WeinholdModelLoader::_HandleThreadScheduled(uint32 cpu,
931bea40bcdSIngo Weinhold	system_profiler_thread_scheduled* event)
9321e336ebaSIngo Weinhold{
9331e336ebaSIngo Weinhold	_UpdateLastEventTime(event->time);
9341e336ebaSIngo Weinhold
935a63809d3SIngo Weinhold	ExtendedThreadSchedulingState* thread = fState->LookupThread(event->thread);
9361e336ebaSIngo Weinhold	if (thread == NULL) {
937883b3e1dSMichael Lotz		printf("Warning: Schedule event for unknown thread: %" B_PRId32 "\n",
9385b78a987SIngo Weinhold			event->thread);
9395b78a987SIngo Weinhold		thread = _AddUnknownThread(event->thread);
9401e336ebaSIngo Weinhold		return;
9411e336ebaSIngo Weinhold	}
9421e336ebaSIngo Weinhold
943a63809d3SIngo Weinhold	nanotime_t diffTime = fState->LastEventTime() - thread->lastTime;
9441e336ebaSIngo Weinhold
9451e336ebaSIngo Weinhold	if (thread->state == READY) {
9461e336ebaSIngo Weinhold		// thread scheduled after having been woken up
9471e336ebaSIngo Weinhold		thread->thread->AddLatency(diffTime);
9481e336ebaSIngo Weinhold	} else if (thread->state == PREEMPTED) {
9491e336ebaSIngo Weinhold		// thread scheduled after having been preempted before
9501e336ebaSIngo Weinhold		thread->thread->AddRerun(diffTime);
9511e336ebaSIngo Weinhold	}
9521e336ebaSIngo Weinhold
9531e336ebaSIngo Weinhold	if (thread->state == STILL_RUNNING) {
9541e336ebaSIngo Weinhold		// Thread was running and continues to run.
9551e336ebaSIngo Weinhold		thread->state = RUNNING;
9561e336ebaSIngo Weinhold	}
9571e336ebaSIngo Weinhold
9581e336ebaSIngo Weinhold	if (thread->state != RUNNING) {
959a63809d3SIngo Weinhold		thread->lastTime = fState->LastEventTime();
9601e336ebaSIngo Weinhold		thread->state = RUNNING;
9611e336ebaSIngo Weinhold	}
9621e336ebaSIngo Weinhold
963a63809d3SIngo Weinhold	thread->IncrementEventCount();
964a63809d3SIngo Weinhold
9651e336ebaSIngo Weinhold	// unscheduled thread
9661e336ebaSIngo Weinhold
9671e336ebaSIngo Weinhold	if (event->thread == event->previous_thread)
9681e336ebaSIngo Weinhold		return;
9691e336ebaSIngo Weinhold
970a63809d3SIngo Weinhold	thread = fState->LookupThread(event->previous_thread);
9711e336ebaSIngo Weinhold	if (thread == NULL) {
972883b3e1dSMichael Lotz		printf("Warning: Schedule event for unknown previous thread: %" B_PRId32
973883b3e1dSMichael Lotz			"\n", event->previous_thread);
9745b78a987SIngo Weinhold		thread = _AddUnknownThread(event->previous_thread);
9751e336ebaSIngo Weinhold	}
9761e336ebaSIngo Weinhold
977a63809d3SIngo Weinhold	diffTime = fState->LastEventTime() - thread->lastTime;
9781e336ebaSIngo Weinhold
9791e336ebaSIngo Weinhold	if (thread->state == STILL_RUNNING) {
9801e336ebaSIngo Weinhold		// thread preempted
9811e336ebaSIngo Weinhold		thread->thread->AddPreemption(diffTime);
9821e336ebaSIngo Weinhold		thread->thread->AddRun(diffTime);
983bea40bcdSIngo Weinhold		if (thread->priority == 0)
984bea40bcdSIngo Weinhold			_AddIdleTime(cpu, diffTime);
9851e336ebaSIngo Weinhold
986a63809d3SIngo Weinhold		thread->lastTime = fState->LastEventTime();
9871e336ebaSIngo Weinhold		thread->state = PREEMPTED;
9881e336ebaSIngo Weinhold	} else if (thread->state == RUNNING) {
9891e336ebaSIngo Weinhold		// thread starts waiting (it hadn't been added to the run
9901e336ebaSIngo Weinhold		// queue before being unscheduled)
9911e336ebaSIngo Weinhold		thread->thread->AddRun(diffTime);
992bea40bcdSIngo Weinhold		if (thread->priority == 0)
993bea40bcdSIngo Weinhold			_AddIdleTime(cpu, diffTime);
9941e336ebaSIngo Weinhold
9951e336ebaSIngo Weinhold		if (event->previous_thread_state == B_THREAD_WAITING) {
9961e336ebaSIngo Weinhold			addr_t waitObject = event->previous_thread_wait_object;
9971e336ebaSIngo Weinhold			switch (event->previous_thread_wait_object_type) {
9981e336ebaSIngo Weinhold				case THREAD_BLOCK_TYPE_SNOOZE:
9991e336ebaSIngo Weinhold				case THREAD_BLOCK_TYPE_SIGNAL:
10001e336ebaSIngo Weinhold					waitObject = 0;
10011e336ebaSIngo Weinhold					break;
10021e336ebaSIngo Weinhold				case THREAD_BLOCK_TYPE_SEMAPHORE:
10031e336ebaSIngo Weinhold				case THREAD_BLOCK_TYPE_CONDITION_VARIABLE:
10041e336ebaSIngo Weinhold				case THREAD_BLOCK_TYPE_MUTEX:
10051e336ebaSIngo Weinhold				case THREAD_BLOCK_TYPE_RW_LOCK:
10061e336ebaSIngo Weinhold				case THREAD_BLOCK_TYPE_OTHER:
10071e336ebaSIngo Weinhold				default:
10081e336ebaSIngo Weinhold					break;
10091e336ebaSIngo Weinhold			}
10101e336ebaSIngo Weinhold
10111e336ebaSIngo Weinhold			_AddThreadWaitObject(thread,
10121e336ebaSIngo Weinhold				event->previous_thread_wait_object_type, waitObject);
10131e336ebaSIngo Weinhold		}
10141e336ebaSIngo Weinhold
1015a63809d3SIngo Weinhold		thread->lastTime = fState->LastEventTime();
10161e336ebaSIngo Weinhold		thread->state = WAITING;
10171e336ebaSIngo Weinhold	} else if (thread->state == UNKNOWN) {
10181e336ebaSIngo Weinhold		uint32 threadState = event->previous_thread_state;
10191e336ebaSIngo Weinhold		if (threadState == B_THREAD_WAITING
10201e336ebaSIngo Weinhold			|| threadState == B_THREAD_SUSPENDED) {
1021a63809d3SIngo Weinhold			thread->lastTime = fState->LastEventTime();
10221e336ebaSIngo Weinhold			thread->state = WAITING;
10231e336ebaSIngo Weinhold		} else if (threadState == B_THREAD_READY) {
1024a63809d3SIngo Weinhold			thread->lastTime = fState->LastEventTime();
10251e336ebaSIngo Weinhold			thread->state = PREEMPTED;
10261e336ebaSIngo Weinhold		}
10271e336ebaSIngo Weinhold	}
1028a63809d3SIngo Weinhold
1029a63809d3SIngo Weinhold	thread->IncrementEventCount();
10301e336ebaSIngo Weinhold}
10311e336ebaSIngo Weinhold
10321e336ebaSIngo Weinhold
10331e336ebaSIngo Weinholdvoid
10341e336ebaSIngo WeinholdModelLoader::_HandleThreadEnqueuedInRunQueue(
10351e336ebaSIngo Weinhold	thread_enqueued_in_run_queue* event)
10361e336ebaSIngo Weinhold{
10371e336ebaSIngo Weinhold	_UpdateLastEventTime(event->time);
10381e336ebaSIngo Weinhold
1039a63809d3SIngo Weinhold	ExtendedThreadSchedulingState* thread = fState->LookupThread(event->thread);
10401e336ebaSIngo Weinhold	if (thread == NULL) {
1041883b3e1dSMichael Lotz		printf("Warning: Enqueued in run queue event for unknown thread: %"
1042883b3e1dSMichael Lotz			B_PRId32 "\n", event->thread);
10435b78a987SIngo Weinhold		thread = _AddUnknownThread(event->thread);
10441e336ebaSIngo Weinhold	}
10451e336ebaSIngo Weinhold
10461e336ebaSIngo Weinhold	if (thread->state == RUNNING || thread->state == STILL_RUNNING) {
10471e336ebaSIngo Weinhold		// Thread was running and is reentered into the run queue. This
10481e336ebaSIngo Weinhold		// is done by the scheduler, if the thread remains ready.
10491e336ebaSIngo Weinhold		thread->state = STILL_RUNNING;
10501e336ebaSIngo Weinhold	} else {
10511e336ebaSIngo Weinhold		// Thread was waiting and is ready now.
1052a63809d3SIngo Weinhold		nanotime_t diffTime = fState->LastEventTime() - thread->lastTime;
10531e336ebaSIngo Weinhold		if (thread->waitObject != NULL) {