ModelLoader.cpp revision d8d4b902
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
123dc9bfd1SIngo Weinhold#include <new>
133dc9bfd1SIngo Weinhold
143dc9bfd1SIngo Weinhold#include <AutoDeleter.h>
153dc9bfd1SIngo Weinhold#include <AutoLocker.h>
163dc9bfd1SIngo Weinhold#include <DebugEventStream.h>
173dc9bfd1SIngo Weinhold
18c442235eSIngo Weinhold#include <system_profiler_defs.h>
191e336ebaSIngo Weinhold#include <thread_defs.h>
20c442235eSIngo Weinhold
21c442235eSIngo Weinhold#include "DataSource.h"
223dc9bfd1SIngo Weinhold#include "MessageCodes.h"
234f1804a1SIngo Weinhold#include "Model.h"
243dc9bfd1SIngo Weinhold
253dc9bfd1SIngo Weinhold
26d4d63490SIngo Weinhold// add a scheduling state snapshot every x events
27d4d63490SIngo Weinholdstatic const uint32 kSchedulingSnapshotInterval = 1024;
28d4d63490SIngo Weinhold
29d4d63490SIngo Weinhold
301e336ebaSIngo Weinholdstruct SimpleWaitObjectInfo : system_profiler_wait_object_info {
311e336ebaSIngo Weinhold	SimpleWaitObjectInfo(uint32 type)
321e336ebaSIngo Weinhold	{
331e336ebaSIngo Weinhold		this->type = type;
341e336ebaSIngo Weinhold		object = 0;
351e336ebaSIngo Weinhold		referenced_object = 0;
361e336ebaSIngo Weinhold		name[0] = '\0';
371e336ebaSIngo Weinhold	}
381e336ebaSIngo Weinhold};
391e336ebaSIngo Weinhold
401e336ebaSIngo Weinhold
411e336ebaSIngo Weinholdstatic const SimpleWaitObjectInfo kSnoozeWaitObjectInfo(
421e336ebaSIngo Weinhold	THREAD_BLOCK_TYPE_SNOOZE);
431e336ebaSIngo Weinholdstatic const SimpleWaitObjectInfo kSignalWaitObjectInfo(
441e336ebaSIngo Weinhold	THREAD_BLOCK_TYPE_SIGNAL);
451e336ebaSIngo Weinhold
461e336ebaSIngo Weinhold
471e336ebaSIngo Weinhold// #pragma mark -
481e336ebaSIngo Weinhold
491e336ebaSIngo Weinhold
509d7f0c33SIngo Weinholdinline void
51d8d4b902SIngo WeinholdModelLoader::_UpdateLastEventTime(nanotime_t time)
529d7f0c33SIngo Weinhold{
5331391fedSIngo Weinhold	if (fBaseTime < 0) {
549d7f0c33SIngo Weinhold		fBaseTime = time;
5531391fedSIngo Weinhold		fModel->SetBaseTime(time);
5631391fedSIngo Weinhold	}
579d7f0c33SIngo Weinhold
58d4d63490SIngo Weinhold	fState.SetLastEventTime(time - fBaseTime);
599d7f0c33SIngo Weinhold}
609d7f0c33SIngo Weinhold
619d7f0c33SIngo Weinhold
624f1804a1SIngo WeinholdModelLoader::ModelLoader(DataSource* dataSource,
63c442235eSIngo Weinhold	const BMessenger& target, void* targetCookie)
643dc9bfd1SIngo Weinhold	:
6564d5660eSIngo Weinhold	AbstractModelLoader(target, targetCookie),
663dc9bfd1SIngo Weinhold	fModel(NULL),
6764d5660eSIngo Weinhold	fDataSource(dataSource)
683dc9bfd1SIngo Weinhold{
693dc9bfd1SIngo Weinhold}
703dc9bfd1SIngo Weinhold
713dc9bfd1SIngo Weinhold
724f1804a1SIngo WeinholdModelLoader::~ModelLoader()
733dc9bfd1SIngo Weinhold{
74c442235eSIngo Weinhold	delete fDataSource;
753dc9bfd1SIngo Weinhold	delete fModel;
763dc9bfd1SIngo Weinhold}
773dc9bfd1SIngo Weinhold
783dc9bfd1SIngo Weinhold
794f1804a1SIngo WeinholdModel*
804f1804a1SIngo WeinholdModelLoader::DetachModel()
813dc9bfd1SIngo Weinhold{
823dc9bfd1SIngo Weinhold	AutoLocker<BLocker> locker(fLock);
833dc9bfd1SIngo Weinhold
843dc9bfd1SIngo Weinhold	if (fModel == NULL || fLoading)
853dc9bfd1SIngo Weinhold		return NULL;
863dc9bfd1SIngo Weinhold
874f1804a1SIngo Weinhold	Model* model = fModel;
883dc9bfd1SIngo Weinhold	fModel = NULL;
893dc9bfd1SIngo Weinhold
903dc9bfd1SIngo Weinhold	return model;
913dc9bfd1SIngo Weinhold}
923dc9bfd1SIngo Weinhold
933dc9bfd1SIngo Weinhold
9464d5660eSIngo Weinholdstatus_t
9564d5660eSIngo WeinholdModelLoader::PrepareForLoading()
963dc9bfd1SIngo Weinhold{
9764d5660eSIngo Weinhold	if (fModel != NULL || fDataSource == NULL)
9864d5660eSIngo Weinhold		return B_BAD_VALUE;
9964d5660eSIngo Weinhold
100d4d63490SIngo Weinhold	// init the state
101d4d63490SIngo Weinhold	status_t error = fState.Init();
10264d5660eSIngo Weinhold	if (error != B_OK)
10364d5660eSIngo Weinhold		return error;
10464d5660eSIngo Weinhold
10564d5660eSIngo Weinhold	return B_OK;
1063dc9bfd1SIngo Weinhold}
1073dc9bfd1SIngo Weinhold
1083dc9bfd1SIngo Weinhold
1093dc9bfd1SIngo Weinholdstatus_t
11064d5660eSIngo WeinholdModelLoader::Load()
1113dc9bfd1SIngo Weinhold{
1123dc9bfd1SIngo Weinhold	try {
11364d5660eSIngo Weinhold		return _Load();
114c442235eSIngo Weinhold	} catch(...) {
11564d5660eSIngo Weinhold		return B_ERROR;
1163dc9bfd1SIngo Weinhold	}
11764d5660eSIngo Weinhold}
11831391fedSIngo Weinhold
1193dc9bfd1SIngo Weinhold
12064d5660eSIngo Weinholdvoid
12164d5660eSIngo WeinholdModelLoader::FinishLoading(bool success)
12264d5660eSIngo Weinhold{
123d4d63490SIngo Weinhold	fState.Clear();
1241e336ebaSIngo Weinhold
12564d5660eSIngo Weinhold	if (!success) {
1263dc9bfd1SIngo Weinhold		delete fModel;
1273dc9bfd1SIngo Weinhold		fModel = NULL;
1283dc9bfd1SIngo Weinhold	}
1293dc9bfd1SIngo Weinhold}
1303dc9bfd1SIngo Weinhold
1313dc9bfd1SIngo Weinhold
132c442235eSIngo Weinholdstatus_t
1334f1804a1SIngo WeinholdModelLoader::_Load()
134c442235eSIngo Weinhold{
13508e34e27SIngo Weinhold	// read the complete data into memory
13608e34e27SIngo Weinhold	void* eventData;
13708e34e27SIngo Weinhold	size_t eventDataSize;
13808e34e27SIngo Weinhold	status_t error = _ReadDebugEvents(&eventData, &eventDataSize);
139c442235eSIngo Weinhold	if (error != B_OK)
140c442235eSIngo Weinhold		return error;
14108e34e27SIngo Weinhold
14231391fedSIngo Weinhold	// get the data source name
14331391fedSIngo Weinhold	BString dataSourceName;
14431391fedSIngo Weinhold	fDataSource->GetName(dataSourceName);
14531391fedSIngo Weinhold
14608e34e27SIngo Weinhold	// create a model
14731391fedSIngo Weinhold	fModel = new(std::nothrow) Model(dataSourceName.String(), eventData,
14831391fedSIngo Weinhold		eventDataSize);
14908e34e27SIngo Weinhold	if (fModel == NULL) {
15008e34e27SIngo Weinhold		free(eventData);
15108e34e27SIngo Weinhold		return B_NO_MEMORY;
15208e34e27SIngo Weinhold	}
153c442235eSIngo Weinhold
154c442235eSIngo Weinhold	// create a debug input stream
155c442235eSIngo Weinhold	BDebugEventInputStream* input = new(std::nothrow) BDebugEventInputStream;
156c442235eSIngo Weinhold	if (input == NULL)
157c442235eSIngo Weinhold		return B_NO_MEMORY;
158c442235eSIngo Weinhold	ObjectDeleter<BDebugEventInputStream> inputDeleter(input);
159c442235eSIngo Weinhold
16008e34e27SIngo Weinhold	error = input->SetTo(eventData, eventDataSize, false);
161c442235eSIngo Weinhold	if (error != B_OK)
162c442235eSIngo Weinhold		return error;
163c442235eSIngo Weinhold
1641e336ebaSIngo Weinhold	// add the snooze and signal wait objects to the model
1651e336ebaSIngo Weinhold	if (fModel->AddWaitObject(&kSnoozeWaitObjectInfo, NULL) == NULL
1661e336ebaSIngo Weinhold		|| fModel->AddWaitObject(&kSignalWaitObjectInfo, NULL) == NULL) {
1671e336ebaSIngo Weinhold		return B_NO_MEMORY;
1681e336ebaSIngo Weinhold	}
1691e336ebaSIngo Weinhold
170c442235eSIngo Weinhold	// process the events
171d4d63490SIngo Weinhold	fState.Clear();
1729d7f0c33SIngo Weinhold	fBaseTime = -1;
173d4d63490SIngo Weinhold	uint64 count = 0;
174c442235eSIngo Weinhold
175c442235eSIngo Weinhold	while (true) {
176c442235eSIngo Weinhold		// get next event
177c442235eSIngo Weinhold		uint32 event;
178c442235eSIngo Weinhold		uint32 cpu;
179c442235eSIngo Weinhold		const void* buffer;
180d4d63490SIngo Weinhold		off_t offset;
181d4d63490SIngo Weinhold		ssize_t bufferSize = input->ReadNextEvent(&event, &cpu, &buffer,
182d4d63490SIngo Weinhold			&offset);
183c442235eSIngo Weinhold		if (bufferSize < 0)
184c442235eSIngo Weinhold			return bufferSize;
185c442235eSIngo Weinhold		if (buffer == NULL)
18631391fedSIngo Weinhold			break;
187c442235eSIngo Weinhold
188c442235eSIngo Weinhold		// process the event
189c442235eSIngo Weinhold		status_t error = _ProcessEvent(event, cpu, buffer, bufferSize);
190c442235eSIngo Weinhold		if (error != B_OK)
191c442235eSIngo Weinhold			return error;
192c442235eSIngo Weinhold
193c442235eSIngo Weinhold		// periodically check whether we're supposed to abort
194c442235eSIngo Weinhold		if (++count % 32 == 0) {
195c442235eSIngo Weinhold			AutoLocker<BLocker> locker(fLock);
196c442235eSIngo Weinhold			if (fAborted)
197c442235eSIngo Weinhold				return B_ERROR;
198c442235eSIngo Weinhold		}
199d4d63490SIngo Weinhold
200d4d63490SIngo Weinhold		// periodically add scheduling snapshots
201d4d63490SIngo Weinhold		if (count % kSchedulingSnapshotInterval == 0)
202d4d63490SIngo Weinhold			fModel->AddSchedulingStateSnapshot(fState, offset);
203c442235eSIngo Weinhold	}
20431391fedSIngo Weinhold
205d4d63490SIngo Weinhold	fModel->SetLastEventTime(fState.LastEventTime());
206d4d63490SIngo Weinhold	fModel->LoadingFinished();
20731391fedSIngo Weinhold
20831391fedSIngo Weinhold	return B_OK;
209c442235eSIngo Weinhold}
210c442235eSIngo Weinhold
211c442235eSIngo Weinhold
21208e34e27SIngo Weinholdstatus_t
21308e34e27SIngo WeinholdModelLoader::_ReadDebugEvents(void** _eventData, size_t* _size)
21408e34e27SIngo Weinhold{
21508e34e27SIngo Weinhold	// get a BDataIO from the data source
21608e34e27SIngo Weinhold	BDataIO* io;
21708e34e27SIngo Weinhold	status_t error = fDataSource->CreateDataIO(&io);
21808e34e27SIngo Weinhold	if (error != B_OK)
21908e34e27SIngo Weinhold		return error;
22008e34e27SIngo Weinhold	ObjectDeleter<BDataIO> dataIOtDeleter(io);
22108e34e27SIngo Weinhold
22208e34e27SIngo Weinhold	// First we need to find out how large a buffer to allocate.
22308e34e27SIngo Weinhold	size_t size;
22408e34e27SIngo Weinhold
22508e34e27SIngo Weinhold	if (BPositionIO* positionIO = dynamic_cast<BPositionIO*>(io)) {
22608e34e27SIngo Weinhold		// it's a BPositionIO -- this makes things easier, since we know how
22708e34e27SIngo Weinhold		// many bytes to read
22808e34e27SIngo Weinhold		off_t currentPos = positionIO->Position();
22908e34e27SIngo Weinhold		if (currentPos < 0)
23008e34e27SIngo Weinhold			return currentPos;
23108e34e27SIngo Weinhold
23208e34e27SIngo Weinhold		off_t fileSize;
23308e34e27SIngo Weinhold		error = positionIO->GetSize(&fileSize);
23408e34e27SIngo Weinhold		if (error != B_OK)
23508e34e27SIngo Weinhold			return error;
23608e34e27SIngo Weinhold
23708e34e27SIngo Weinhold		size = fileSize - currentPos;
23808e34e27SIngo Weinhold	} else {
23908e34e27SIngo Weinhold		// no BPositionIO -- we need to determine the total size by iteratively
24008e34e27SIngo Weinhold		// reading the whole data one time
24108e34e27SIngo Weinhold
24208e34e27SIngo Weinhold		// allocate a dummy buffer for reading
24308e34e27SIngo Weinhold		const size_t kBufferSize = 1024 * 1024;
24408e34e27SIngo Weinhold		void* buffer = malloc(kBufferSize);
24508e34e27SIngo Weinhold		if (buffer == NULL)
24608e34e27SIngo Weinhold			return B_NO_MEMORY;
24708e34e27SIngo Weinhold		MemoryDeleter bufferDeleter(buffer);
24808e34e27SIngo Weinhold
24908e34e27SIngo Weinhold		size = 0;
25008e34e27SIngo Weinhold		while (true) {
25108e34e27SIngo Weinhold			ssize_t bytesRead = io->Read(buffer, kBufferSize);
25208e34e27SIngo Weinhold			if (bytesRead < 0)
25308e34e27SIngo Weinhold				return bytesRead;
25408e34e27SIngo Weinhold			if (bytesRead == 0)
25508e34e27SIngo Weinhold				break;
25608e34e27SIngo Weinhold
25708e34e27SIngo Weinhold			size += bytesRead;
25808e34e27SIngo Weinhold		}
25908e34e27SIngo Weinhold
26008e34e27SIngo Weinhold		// we've got the size -- recreate the BDataIO
26108e34e27SIngo Weinhold		dataIOtDeleter.Delete();
26208e34e27SIngo Weinhold		error = fDataSource->CreateDataIO(&io);
26308e34e27SIngo Weinhold		if (error != B_OK)
26408e34e27SIngo Weinhold			return error;
26508e34e27SIngo Weinhold		dataIOtDeleter.SetTo(io);
26608e34e27SIngo Weinhold	}
26708e34e27SIngo Weinhold
26808e34e27SIngo Weinhold	// allocate the data buffer
26908e34e27SIngo Weinhold	void* data = malloc(size);
27008e34e27SIngo Weinhold	if (data == NULL)
27108e34e27SIngo Weinhold		return B_NO_MEMORY;
27208e34e27SIngo Weinhold	MemoryDeleter dataDeleter(data);
27308e34e27SIngo Weinhold
27408e34e27SIngo Weinhold	// read the data
27508e34e27SIngo Weinhold	ssize_t bytesRead = io->Read(data, size);
27608e34e27SIngo Weinhold	if (bytesRead < 0)
27708e34e27SIngo Weinhold		return bytesRead;
27808e34e27SIngo Weinhold	if ((size_t)bytesRead != size)
27908e34e27SIngo Weinhold		return B_FILE_ERROR;
28008e34e27SIngo Weinhold
28108e34e27SIngo Weinhold	dataDeleter.Detach();
28208e34e27SIngo Weinhold	*_eventData = data;
28308e34e27SIngo Weinhold	*_size = size;
28408e34e27SIngo Weinhold	return B_OK;
28508e34e27SIngo Weinhold}
28608e34e27SIngo Weinhold
28708e34e27SIngo Weinhold
2883dc9bfd1SIngo Weinholdstatus_t
2894f1804a1SIngo WeinholdModelLoader::_ProcessEvent(uint32 event, uint32 cpu, const void* buffer,
2903dc9bfd1SIngo Weinhold	size_t size)
2913dc9bfd1SIngo Weinhold{
292c442235eSIngo Weinhold	switch (event) {
293c442235eSIngo Weinhold		case B_SYSTEM_PROFILER_TEAM_ADDED:
2941e336ebaSIngo Weinhold			_HandleTeamAdded((system_profiler_team_added*)buffer);
2951e336ebaSIngo Weinhold			break;
29608e34e27SIngo Weinhold
297c442235eSIngo Weinhold		case B_SYSTEM_PROFILER_TEAM_REMOVED:
2981e336ebaSIngo Weinhold			_HandleTeamRemoved((system_profiler_team_removed*)buffer);
299c442235eSIngo Weinhold			break;
30008e34e27SIngo Weinhold
301c442235eSIngo Weinhold		case B_SYSTEM_PROFILER_TEAM_EXEC:
3021e336ebaSIngo Weinhold			_HandleTeamExec((system_profiler_team_exec*)buffer);
303c442235eSIngo Weinhold			break;
30408e34e27SIngo Weinhold
305c442235eSIngo Weinhold		case B_SYSTEM_PROFILER_THREAD_ADDED:
3061e336ebaSIngo Weinhold			_HandleThreadAdded((system_profiler_thread_added*)buffer);
307c442235eSIngo Weinhold			break;
30808e34e27SIngo Weinhold
309c442235eSIngo Weinhold		case B_SYSTEM_PROFILER_THREAD_REMOVED:
3101e336ebaSIngo Weinhold			_HandleThreadRemoved((system_profiler_thread_removed*)buffer);
311c442235eSIngo Weinhold			break;
31208e34e27SIngo Weinhold
313c442235eSIngo Weinhold		case B_SYSTEM_PROFILER_THREAD_SCHEDULED:
3141e336ebaSIngo Weinhold			_HandleThreadScheduled((system_profiler_thread_scheduled*)buffer);
315c442235eSIngo Weinhold			break;
3169d7f0c33SIngo Weinhold
317c442235eSIngo Weinhold		case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE:
3181e336ebaSIngo Weinhold			_HandleThreadEnqueuedInRunQueue(
3191e336ebaSIngo Weinhold				(thread_enqueued_in_run_queue*)buffer);
320c442235eSIngo Weinhold			break;
3219d7f0c33SIngo Weinhold
322c442235eSIngo Weinhold		case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE:
3231e336ebaSIngo Weinhold			_HandleThreadRemovedFromRunQueue(
3241e336ebaSIngo Weinhold				(thread_removed_from_run_queue*)buffer);
325c442235eSIngo Weinhold			break;
3269d7f0c33SIngo Weinhold
327c442235eSIngo Weinhold		case B_SYSTEM_PROFILER_WAIT_OBJECT_INFO:
3281e336ebaSIngo Weinhold			_HandleWaitObjectInfo((system_profiler_wait_object_info*)buffer);
329c442235eSIngo Weinhold			break;
3301e336ebaSIngo Weinhold
331c442235eSIngo Weinhold		default:
332c442235eSIngo Weinholdprintf("unsupported event type %lu, size: %lu\n", event, size);
333c442235eSIngo Weinholdreturn B_BAD_DATA;
334c442235eSIngo Weinhold			break;
335c442235eSIngo Weinhold	}
336c442235eSIngo Weinhold
337c442235eSIngo Weinhold	return B_OK;
3383dc9bfd1SIngo Weinhold}
3391e336ebaSIngo Weinhold
3401e336ebaSIngo Weinhold
3411e336ebaSIngo Weinholdvoid
3421e336ebaSIngo WeinholdModelLoader::_HandleTeamAdded(system_profiler_team_added* event)
3431e336ebaSIngo Weinhold{
344d4d63490SIngo Weinhold	if (fModel->AddTeam(event, fState.LastEventTime()) == NULL)
3451e336ebaSIngo Weinhold		throw std::bad_alloc();
3461e336ebaSIngo Weinhold}
3471e336ebaSIngo Weinhold
3481e336ebaSIngo Weinhold
3491e336ebaSIngo Weinholdvoid
3501e336ebaSIngo WeinholdModelLoader::_HandleTeamRemoved(system_profiler_team_removed* event)
3511e336ebaSIngo Weinhold{
3521e336ebaSIngo Weinhold	if (Model::Team* team = fModel->TeamByID(event->team))
353d4d63490SIngo Weinhold		team->SetDeletionTime(fState.LastEventTime());
3541e336ebaSIngo Weinhold	else
3551e336ebaSIngo Weinhold		printf("Removed event for unknown team: %ld\n", event->team);
3561e336ebaSIngo Weinhold}
3571e336ebaSIngo Weinhold
3581e336ebaSIngo Weinhold
3591e336ebaSIngo Weinholdvoid
3601e336ebaSIngo WeinholdModelLoader::_HandleTeamExec(system_profiler_team_exec* event)
3611e336ebaSIngo Weinhold{
3621e336ebaSIngo Weinhold	// TODO:...
3631e336ebaSIngo Weinhold}
3641e336ebaSIngo Weinhold
3651e336ebaSIngo Weinhold
3661e336ebaSIngo Weinholdvoid
3671e336ebaSIngo WeinholdModelLoader::_HandleThreadAdded(system_profiler_thread_added* event)
3681e336ebaSIngo Weinhold{
3691e336ebaSIngo Weinhold	if (_AddThread(event) == NULL)
3701e336ebaSIngo Weinhold		throw std::bad_alloc();
3711e336ebaSIngo Weinhold}
3721e336ebaSIngo Weinhold
3731e336ebaSIngo Weinhold
3741e336ebaSIngo Weinholdvoid
3751e336ebaSIngo WeinholdModelLoader::_HandleThreadRemoved(system_profiler_thread_removed* event)
3761e336ebaSIngo Weinhold{
3771e336ebaSIngo Weinhold	if (Model::Thread* thread = fModel->ThreadByID(event->thread))
378d4d63490SIngo Weinhold		thread->SetDeletionTime(fState.LastEventTime());
3791e336ebaSIngo Weinhold	else
3801e336ebaSIngo Weinhold		printf("Removed event for unknown team: %ld\n", event->thread);
3811e336ebaSIngo Weinhold}
3821e336ebaSIngo Weinhold
3831e336ebaSIngo Weinhold
3841e336ebaSIngo Weinholdvoid
3851e336ebaSIngo WeinholdModelLoader::_HandleThreadScheduled(system_profiler_thread_scheduled* event)
3861e336ebaSIngo Weinhold{
3871e336ebaSIngo Weinhold	_UpdateLastEventTime(event->time);
3881e336ebaSIngo Weinhold
389d4d63490SIngo Weinhold	Model::ThreadSchedulingState* thread = fState.LookupThread(event->thread);
3901e336ebaSIngo Weinhold	if (thread == NULL) {
3911e336ebaSIngo Weinhold		printf("Schedule event for unknown thread: %ld\n", event->thread);
3921e336ebaSIngo Weinhold		return;
3931e336ebaSIngo Weinhold	}
3941e336ebaSIngo Weinhold
395d8d4b902SIngo Weinhold	nanotime_t diffTime = fState.LastEventTime() - thread->lastTime;
3961e336ebaSIngo Weinhold
3971e336ebaSIngo Weinhold	if (thread->state == READY) {
3981e336ebaSIngo Weinhold		// thread scheduled after having been woken up
3991e336ebaSIngo Weinhold		thread->thread->AddLatency(diffTime);
4001e336ebaSIngo Weinhold	} else if (thread->state == PREEMPTED) {
4011e336ebaSIngo Weinhold		// thread scheduled after having been preempted before
4021e336ebaSIngo Weinhold		thread->thread->AddRerun(diffTime);
4031e336ebaSIngo Weinhold	}
4041e336ebaSIngo Weinhold
4051e336ebaSIngo Weinhold	if (thread->state == STILL_RUNNING) {
4061e336ebaSIngo Weinhold		// Thread was running and continues to run.
4071e336ebaSIngo Weinhold		thread->state = RUNNING;
4081e336ebaSIngo Weinhold	}
4091e336ebaSIngo Weinhold
4101e336ebaSIngo Weinhold	if (thread->state != RUNNING) {
411d4d63490SIngo Weinhold		thread->lastTime = fState.LastEventTime();
4121e336ebaSIngo Weinhold		thread->state = RUNNING;
4131e336ebaSIngo Weinhold	}
4141e336ebaSIngo Weinhold
4151e336ebaSIngo Weinhold	// unscheduled thread
4161e336ebaSIngo Weinhold
4171e336ebaSIngo Weinhold	if (event->thread == event->previous_thread)
4181e336ebaSIngo Weinhold		return;
4191e336ebaSIngo Weinhold
420d4d63490SIngo Weinhold	thread = fState.LookupThread(event->previous_thread);
4211e336ebaSIngo Weinhold	if (thread == NULL) {
4221e336ebaSIngo Weinhold		printf("Schedule event for unknown previous thread: %ld\n",
4231e336ebaSIngo Weinhold			event->previous_thread);
4241e336ebaSIngo Weinhold		return;
4251e336ebaSIngo Weinhold	}
4261e336ebaSIngo Weinhold
427d4d63490SIngo Weinhold	diffTime = fState.LastEventTime() - thread->lastTime;
4281e336ebaSIngo Weinhold
4291e336ebaSIngo Weinhold	if (thread->state == STILL_RUNNING) {
4301e336ebaSIngo Weinhold		// thread preempted
4311e336ebaSIngo Weinhold		thread->thread->AddPreemption(diffTime);
4321e336ebaSIngo Weinhold		thread->thread->AddRun(diffTime);
4331e336ebaSIngo Weinhold
434d4d63490SIngo Weinhold		thread->lastTime = fState.LastEventTime();
4351e336ebaSIngo Weinhold		thread->state = PREEMPTED;
4361e336ebaSIngo Weinhold	} else if (thread->state == RUNNING) {
4371e336ebaSIngo Weinhold		// thread starts waiting (it hadn't been added to the run
4381e336ebaSIngo Weinhold		// queue before being unscheduled)
4391e336ebaSIngo Weinhold		thread->thread->AddRun(diffTime);
4401e336ebaSIngo Weinhold
4411e336ebaSIngo Weinhold		if (event->previous_thread_state == B_THREAD_WAITING) {
4421e336ebaSIngo Weinhold			addr_t waitObject = event->previous_thread_wait_object;
4431e336ebaSIngo Weinhold			switch (event->previous_thread_wait_object_type) {
4441e336ebaSIngo Weinhold				case THREAD_BLOCK_TYPE_SNOOZE:
4451e336ebaSIngo Weinhold				case THREAD_BLOCK_TYPE_SIGNAL:
4461e336ebaSIngo Weinhold					waitObject = 0;
4471e336ebaSIngo Weinhold					break;
4481e336ebaSIngo Weinhold				case THREAD_BLOCK_TYPE_SEMAPHORE:
4491e336ebaSIngo Weinhold				case THREAD_BLOCK_TYPE_CONDITION_VARIABLE:
4501e336ebaSIngo Weinhold				case THREAD_BLOCK_TYPE_MUTEX:
4511e336ebaSIngo Weinhold				case THREAD_BLOCK_TYPE_RW_LOCK:
4521e336ebaSIngo Weinhold				case THREAD_BLOCK_TYPE_OTHER:
4531e336ebaSIngo Weinhold				default:
4541e336ebaSIngo Weinhold					break;
4551e336ebaSIngo Weinhold			}
4561e336ebaSIngo Weinhold
4571e336ebaSIngo Weinhold			_AddThreadWaitObject(thread,
4581e336ebaSIngo Weinhold				event->previous_thread_wait_object_type, waitObject);
4591e336ebaSIngo Weinhold		}
4601e336ebaSIngo Weinhold
461d4d63490SIngo Weinhold		thread->lastTime = fState.LastEventTime();
4621e336ebaSIngo Weinhold		thread->state = WAITING;
4631e336ebaSIngo Weinhold	} else if (thread->state == UNKNOWN) {
4641e336ebaSIngo Weinhold		uint32 threadState = event->previous_thread_state;
4651e336ebaSIngo Weinhold		if (threadState == B_THREAD_WAITING
4661e336ebaSIngo Weinhold			|| threadState == B_THREAD_SUSPENDED) {
467d4d63490SIngo Weinhold			thread->lastTime = fState.LastEventTime();
4681e336ebaSIngo Weinhold			thread->state = WAITING;
4691e336ebaSIngo Weinhold		} else if (threadState == B_THREAD_READY) {
470d4d63490SIngo Weinhold			thread->lastTime = fState.LastEventTime();
4711e336ebaSIngo Weinhold			thread->state = PREEMPTED;
4721e336ebaSIngo Weinhold		}
4731e336ebaSIngo Weinhold	}
4741e336ebaSIngo Weinhold}
4751e336ebaSIngo Weinhold
4761e336ebaSIngo Weinhold
4771e336ebaSIngo Weinholdvoid
4781e336ebaSIngo WeinholdModelLoader::_HandleThreadEnqueuedInRunQueue(
4791e336ebaSIngo Weinhold	thread_enqueued_in_run_queue* event)
4801e336ebaSIngo Weinhold{
4811e336ebaSIngo Weinhold	_UpdateLastEventTime(event->time);
4821e336ebaSIngo Weinhold
483d4d63490SIngo Weinhold	Model::ThreadSchedulingState* thread = fState.LookupThread(event->thread);
4841e336ebaSIngo Weinhold	if (thread == NULL) {
4851e336ebaSIngo Weinhold		printf("Enqueued in run queue event for unknown thread: %ld\n",
4861e336ebaSIngo Weinhold			event->thread);
4871e336ebaSIngo Weinhold		return;
4881e336ebaSIngo Weinhold	}
4891e336ebaSIngo Weinhold
4901e336ebaSIngo Weinhold	if (thread->state == RUNNING || thread->state == STILL_RUNNING) {
4911e336ebaSIngo Weinhold		// Thread was running and is reentered into the run queue. This
4921e336ebaSIngo Weinhold		// is done by the scheduler, if the thread remains ready.
4931e336ebaSIngo Weinhold		thread->state = STILL_RUNNING;
4941e336ebaSIngo Weinhold	} else {
4951e336ebaSIngo Weinhold		// Thread was waiting and is ready now.
496d8d4b902SIngo Weinhold		nanotime_t diffTime = fState.LastEventTime() - thread->lastTime;
4971e336ebaSIngo Weinhold		if (thread->waitObject != NULL) {
4981e336ebaSIngo Weinhold			thread->waitObject->AddWait(diffTime);
4991e336ebaSIngo Weinhold			thread->waitObject = NULL;
500d1331844SIngo Weinhold			thread->thread->AddWait(diffTime);
5011e336ebaSIngo Weinhold		} else if (thread->state != UNKNOWN)
5021e336ebaSIngo Weinhold			thread->thread->AddUnspecifiedWait(diffTime);
5031e336ebaSIngo Weinhold
504d4d63490SIngo Weinhold		thread->lastTime = fState.LastEventTime();
5051e336ebaSIngo Weinhold		thread->state = READY;
5061e336ebaSIngo Weinhold	}
5071e336ebaSIngo Weinhold}
5081e336ebaSIngo Weinhold
5091e336ebaSIngo Weinhold
5101e336ebaSIngo Weinholdvoid
5111e336ebaSIngo WeinholdModelLoader::_HandleThreadRemovedFromRunQueue(
5121e336ebaSIngo Weinhold	thread_removed_from_run_queue* event)
5131e336ebaSIngo Weinhold{
5141e336ebaSIngo Weinhold	_UpdateLastEventTime(event->time);
5151e336ebaSIngo Weinhold
516d4d63490SIngo Weinhold	Model::ThreadSchedulingState* thread = fState.LookupThread(event->thread);
5171e336ebaSIngo Weinhold	if (thread == NULL) {
5181e336ebaSIngo Weinhold		printf("Removed from run queue event for unknown thread: %ld\n",
5191e336ebaSIngo Weinhold			event->thread);
5201e336ebaSIngo Weinhold		return;
5211e336ebaSIngo Weinhold	}
5221e336ebaSIngo Weinhold
5231e336ebaSIngo Weinhold	// This really only happens when the thread priority is changed
5241e336ebaSIngo Weinhold	// while the thread is ready.
5251e336ebaSIngo Weinhold
526d8d4b902SIngo Weinhold	nanotime_t diffTime = fState.LastEventTime() - thread->lastTime;
5271e336ebaSIngo Weinhold	if (thread->state == RUNNING) {
5281e336ebaSIngo Weinhold		// This should never happen.
5291e336ebaSIngo Weinhold		thread->thread->AddRun(diffTime);
5301e336ebaSIngo Weinhold	} else if (thread->state == READY || thread->state == PREEMPTED) {
5311e336ebaSIngo Weinhold		// Not really correct, but the case is rare and we keep it
5321e336ebaSIngo Weinhold		// simple.
5331e336ebaSIngo Weinhold		thread->thread->AddUnspecifiedWait(diffTime);
5341e336ebaSIngo Weinhold	}
5351e336ebaSIngo Weinhold
536d4d63490SIngo Weinhold	thread->lastTime = fState.LastEventTime();
5371e336ebaSIngo Weinhold	thread->state = WAITING;
5381e336ebaSIngo Weinhold}
5391e336ebaSIngo Weinhold
5401e336ebaSIngo Weinhold
5411e336ebaSIngo Weinholdvoid
5421e336ebaSIngo WeinholdModelLoader::_HandleWaitObjectInfo(system_profiler_wait_object_info* event)
5431e336ebaSIngo Weinhold{
5441e336ebaSIngo Weinhold	if (fModel->AddWaitObject(event, NULL) == NULL)
5451e336ebaSIngo Weinhold		throw std::bad_alloc();
5461e336ebaSIngo Weinhold}
5471e336ebaSIngo Weinhold
5481e336ebaSIngo Weinhold
549d4d63490SIngo WeinholdModel::ThreadSchedulingState*
5501e336ebaSIngo WeinholdModelLoader::_AddThread(system_profiler_thread_added* event)
5511e336ebaSIngo Weinhold{
5521e336ebaSIngo Weinhold	// do we know the thread already?
553d4d63490SIngo Weinhold	Model::ThreadSchedulingState* info = fState.LookupThread(event->thread);
5541e336ebaSIngo Weinhold	if (info != NULL) {
5551e336ebaSIngo Weinhold		// TODO: ?
5561e336ebaSIngo Weinhold		return info;
5571e336ebaSIngo Weinhold	}
5581e336ebaSIngo Weinhold
5591e336ebaSIngo Weinhold	// add the thread to the model
560d4d63490SIngo Weinhold	Model::Thread* thread = fModel->AddThread(event, fState.LastEventTime());
5611e336ebaSIngo Weinhold	if (thread == NULL)
5621e336ebaSIngo Weinhold		return NULL;
5631e336ebaSIngo Weinhold
564d4d63490SIngo Weinhold	// create and add a ThreadSchedulingState
565d4d63490SIngo Weinhold	info = new(std::nothrow) Model::ThreadSchedulingState(thread);
5661e336ebaSIngo Weinhold	if (info == NULL)
5671e336ebaSIngo Weinhold		return NULL;
5681e336ebaSIngo Weinhold
569d4d63490SIngo Weinhold	fState.InsertThread(info);
5701e336ebaSIngo Weinhold
5711e336ebaSIngo Weinhold	return info;
5721e336ebaSIngo Weinhold}
5731e336ebaSIngo Weinhold
5741e336ebaSIngo Weinhold
5751e336ebaSIngo Weinholdvoid
576d4d63490SIngo WeinholdModelLoader::_AddThreadWaitObject(Model::ThreadSchedulingState* thread,
577d4d63490SIngo Weinhold	uint32 type, addr_t object)
5781e336ebaSIngo Weinhold{
5791e336ebaSIngo Weinhold	Model::WaitObjectGroup* waitObjectGroup
5801e336ebaSIngo Weinhold		= fModel->WaitObjectGroupFor(type, object);
5811e336ebaSIngo Weinhold	if (waitObjectGroup == NULL) {
5821e336ebaSIngo Weinhold		// The algorithm should prevent this case.
5831e336ebaSIngo Weinholdprintf("ModelLoader::_AddThreadWaitObject(): Unknown wait object: type: %lu, "
5841e336ebaSIngo Weinhold"object: %#lx\n", type, object);
5851e336ebaSIngo Weinhold		return;
5861e336ebaSIngo Weinhold	}
5871e336ebaSIngo Weinhold
5881e336ebaSIngo Weinhold	Model::WaitObject* waitObject = waitObjectGroup->MostRecentWaitObject();
5891e336ebaSIngo Weinhold
5901e336ebaSIngo Weinhold	Model::ThreadWaitObjectGroup* threadWaitObjectGroup
5911e336ebaSIngo Weinhold		= fModel->ThreadWaitObjectGroupFor(thread->ID(), type, object);
5921e336ebaSIngo Weinhold
5931e336ebaSIngo Weinhold	if (threadWaitObjectGroup == NULL
5941e336ebaSIngo Weinhold		|| threadWaitObjectGroup->MostRecentWaitObject() != waitObject) {
5951e336ebaSIngo Weinhold		Model::ThreadWaitObject* threadWaitObject
5961e336ebaSIngo Weinhold			= fModel->AddThreadWaitObject(thread->ID(), waitObject,
5971e336ebaSIngo Weinhold				&threadWaitObjectGroup);
5981e336ebaSIngo Weinhold		if (threadWaitObject == NULL)
5991e336ebaSIngo Weinhold			throw std::bad_alloc();
6001e336ebaSIngo Weinhold	}
6011e336ebaSIngo Weinhold
6021e336ebaSIngo Weinhold	thread->waitObject = threadWaitObjectGroup->MostRecentThreadWaitObject();
6031e336ebaSIngo Weinhold}
604