xref: /haiku/src/apps/debuganalyzer/model/Model.cpp (revision 2222d0559df303a9846a2fad53741f8b20b14d7c)
1 /*
2  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "Model.h"
7 
8 #include <new>
9 
10 #include <stdio.h>
11 #include <stdlib.h>
12 
13 #include <AutoDeleter.h>
14 
15 
16 // #pragma mark - WaitObject
17 
18 
19 Model::WaitObject::WaitObject(const system_profiler_wait_object_info* event)
20 	:
21 	fEvent(event)
22 {
23 }
24 
25 
26 Model::WaitObject::~WaitObject()
27 {
28 }
29 
30 
31 // #pragma mark - WaitObjectGroup
32 
33 
34 Model::WaitObjectGroup::WaitObjectGroup(WaitObject* waitObject)
35 {
36 	fWaitObjects.Add(waitObject);
37 }
38 
39 
40 Model::WaitObjectGroup::~WaitObjectGroup()
41 {
42 }
43 
44 
45 // #pragma mark - ThreadWaitObject
46 
47 
48 Model::ThreadWaitObject::ThreadWaitObject(WaitObject* waitObject)
49 	:
50 	fWaitObject(waitObject),
51 	fWaits(0),
52 	fTotalWaitTime(0)
53 {
54 }
55 
56 
57 Model::ThreadWaitObject::~ThreadWaitObject()
58 {
59 }
60 
61 
62 void
63 Model::ThreadWaitObject::AddWait(bigtime_t waitTime)
64 {
65 	fWaits++;
66 	fTotalWaitTime += waitTime;
67 }
68 
69 
70 // #pragma mark - ThreadWaitObjectGroup
71 
72 
73 Model::ThreadWaitObjectGroup::ThreadWaitObjectGroup(
74 	ThreadWaitObject* threadWaitObject)
75 {
76 	fWaitObjects.Add(threadWaitObject);
77 }
78 
79 
80 Model::ThreadWaitObjectGroup::~ThreadWaitObjectGroup()
81 {
82 }
83 
84 
85 bool
86 Model::ThreadWaitObjectGroup::GetThreadWaitObjects(
87 	BObjectList<ThreadWaitObject>& objects)
88 {
89 	ThreadWaitObjectList::Iterator it = fWaitObjects.GetIterator();
90 	while (ThreadWaitObject* object = it.Next()) {
91 		if (!objects.AddItem(object))
92 			return false;
93 	}
94 
95 	return true;
96 }
97 
98 
99 // #pragma mark - Team
100 
101 
102 Model::Team::Team(const system_profiler_team_added* event, bigtime_t time)
103 	:
104 	fCreationEvent(event),
105 	fCreationTime(time),
106 	fDeletionTime(-1),
107 	fThreads(10)
108 {
109 }
110 
111 
112 Model::Team::~Team()
113 {
114 }
115 
116 
117 bool
118 Model::Team::AddThread(Thread* thread)
119 {
120 	return fThreads.BinaryInsert(thread, &Thread::CompareByCreationTimeID);
121 }
122 
123 
124 // #pragma mark - Thread
125 
126 
127 Model::Thread::Thread(Team* team, const system_profiler_thread_added* event,
128 	bigtime_t time)
129 	:
130 	fTeam(team),
131 	fCreationEvent(event),
132 	fCreationTime(time),
133 	fDeletionTime(-1),
134 	fRuns(0),
135 	fTotalRunTime(0),
136 	fMinRunTime(-1),
137 	fMaxRunTime(-1),
138 	fLatencies(0),
139 	fTotalLatency(0),
140 	fMinLatency(-1),
141 	fMaxLatency(-1),
142 	fReruns(0),
143 	fTotalRerunTime(0),
144 	fMinRerunTime(-1),
145 	fMaxRerunTime(-1),
146 	fWaits(0),
147 	fTotalWaitTime(0),
148 	fUnspecifiedWaitTime(0),
149 	fPreemptions(0),
150 	fIndex(-1),
151 	fWaitObjectGroups(20, true)
152 {
153 }
154 
155 
156 Model::Thread::~Thread()
157 {
158 }
159 
160 
161 Model::ThreadWaitObjectGroup*
162 Model::Thread::ThreadWaitObjectGroupFor(uint32 type, addr_t object) const
163 {
164 	type_and_object key;
165 	key.type = type;
166 	key.object = object;
167 
168 	return fWaitObjectGroups.BinarySearchByKey(key,
169 		&ThreadWaitObjectGroup::CompareWithTypeObject);
170 }
171 
172 
173 void
174 Model::Thread::AddRun(bigtime_t runTime)
175 {
176 	fRuns++;
177 	fTotalRunTime += runTime;
178 
179 	if (fMinRunTime < 0 || runTime < fMinRunTime)
180 		fMinRunTime = runTime;
181 	if (runTime > fMaxRunTime)
182 		fMaxRunTime = runTime;
183 }
184 
185 
186 void
187 Model::Thread::AddRerun(bigtime_t runTime)
188 {
189 	fReruns++;
190 	fTotalRerunTime += runTime;
191 
192 	if (fMinRerunTime < 0 || runTime < fMinRerunTime)
193 		fMinRerunTime = runTime;
194 	if (runTime > fMaxRerunTime)
195 		fMaxRerunTime = runTime;
196 }
197 
198 
199 void
200 Model::Thread::AddLatency(bigtime_t latency)
201 {
202 	fLatencies++;
203 	fTotalLatency += latency;
204 
205 	if (fMinLatency < 0 || latency < fMinLatency)
206 		fMinLatency = latency;
207 	if (latency > fMaxLatency)
208 		fMaxLatency = latency;
209 }
210 
211 
212 void
213 Model::Thread::AddPreemption(bigtime_t runTime)
214 {
215 	fPreemptions++;
216 }
217 
218 
219 void
220 Model::Thread::AddWait(bigtime_t waitTime)
221 {
222 	fWaits++;
223 	fTotalWaitTime += waitTime;
224 }
225 
226 
227 void
228 Model::Thread::AddUnspecifiedWait(bigtime_t waitTime)
229 {
230 	fUnspecifiedWaitTime += waitTime;
231 }
232 
233 
234 Model::ThreadWaitObject*
235 Model::Thread::AddThreadWaitObject(WaitObject* waitObject,
236 	ThreadWaitObjectGroup** _threadWaitObjectGroup)
237 {
238 	// create a thread wait object
239 	ThreadWaitObject* threadWaitObject
240 		= new(std::nothrow) ThreadWaitObject(waitObject);
241 	if (threadWaitObject == NULL)
242 		return NULL;
243 
244 	// find the thread wait object group
245 	ThreadWaitObjectGroup* threadWaitObjectGroup
246 		= ThreadWaitObjectGroupFor(waitObject->Type(), waitObject->Object());
247 	if (threadWaitObjectGroup == NULL) {
248 		// doesn't exist yet -- create
249 		threadWaitObjectGroup = new(std::nothrow) ThreadWaitObjectGroup(
250 			threadWaitObject);
251 		if (threadWaitObjectGroup == NULL) {
252 			delete threadWaitObject;
253 			return NULL;
254 		}
255 
256 		// add to the list
257 		if (!fWaitObjectGroups.BinaryInsert(threadWaitObjectGroup,
258 				&ThreadWaitObjectGroup::CompareByTypeObject)) {
259 			delete threadWaitObjectGroup;
260 			return NULL;
261 		}
262 	} else {
263 		// exists -- just add the object
264 		threadWaitObjectGroup->AddWaitObject(threadWaitObject);
265 	}
266 
267 	if (_threadWaitObjectGroup != NULL)
268 		*_threadWaitObjectGroup = threadWaitObjectGroup;
269 
270 	return threadWaitObject;
271 }
272 
273 
274 // #pragma mark - SchedulingState
275 
276 
277 Model::SchedulingState::~SchedulingState()
278 {
279 	Clear();
280 }
281 
282 
283 status_t
284 Model::SchedulingState::Init()
285 {
286 	status_t error = fThreadStates.Init();
287 	if (error != B_OK)
288 		return error;
289 
290 	return B_OK;
291 }
292 
293 
294 status_t
295 Model::SchedulingState::Init(const CompactSchedulingState* state)
296 {
297 	status_t error = Init();
298 	if (error != B_OK)
299 		return error;
300 
301 	if (state == NULL)
302 		return B_OK;
303 
304 	fLastEventTime = state->LastEventTime();
305 	for (int32 i = 0; const CompactThreadSchedulingState* compactThreadState
306 			= state->ThreadStateAt(i); i++) {
307 		ThreadSchedulingState* threadState
308 			= new(std::nothrow) ThreadSchedulingState(*compactThreadState);
309 		if (threadState == NULL)
310 			return B_NO_MEMORY;
311 
312 		fThreadStates.Insert(threadState);
313 	}
314 
315 	return B_OK;
316 }
317 
318 
319 void
320 Model::SchedulingState::Clear()
321 {
322 	ThreadSchedulingState* state = fThreadStates.Clear(true);
323 	while (state != NULL) {
324 		ThreadSchedulingState* next = state->next;
325 		delete state;
326 		state = next;
327 	}
328 
329 	fLastEventTime = -1;
330 }
331 
332 
333 // #pragma mark - CompactSchedulingState
334 
335 
336 /*static*/ Model::CompactSchedulingState*
337 Model::CompactSchedulingState::Create(const SchedulingState& state,
338 	off_t eventOffset)
339 {
340 	bigtime_t lastEventTime = state.LastEventTime();
341 
342 	// count the active threads
343 	int32 threadCount = 0;
344 	for (ThreadSchedulingStateTable::Iterator it
345 				= state.ThreadStates().GetIterator();
346 			ThreadSchedulingState* threadState = it.Next();) {
347 		Thread* thread = threadState->thread;
348 		if (thread->CreationTime() <= lastEventTime
349 			&& (thread->DeletionTime() == -1
350 				|| thread->DeletionTime() >= lastEventTime)) {
351 			threadCount++;
352 		}
353 	}
354 
355 	CompactSchedulingState* compactState = (CompactSchedulingState*)malloc(
356 		sizeof(CompactSchedulingState)
357 			+ threadCount * sizeof(CompactThreadSchedulingState));
358 	if (compactState == NULL)
359 		return NULL;
360 
361 	// copy the state info
362 	compactState->fEventOffset = eventOffset;
363 	compactState->fThreadCount = threadCount;
364 	compactState->fLastEventTime = lastEventTime;
365 
366 	int32 threadIndex = 0;
367 	for (ThreadSchedulingStateTable::Iterator it
368 				= state.ThreadStates().GetIterator();
369 			ThreadSchedulingState* threadState = it.Next();) {
370 		Thread* thread = threadState->thread;
371 		if (thread->CreationTime() <= lastEventTime
372 			&& (thread->DeletionTime() == -1
373 				|| thread->DeletionTime() >= lastEventTime)) {
374 			compactState->fThreadStates[threadIndex++] = *threadState;
375 		}
376 	}
377 
378 	return compactState;
379 }
380 
381 
382 void
383 Model::CompactSchedulingState::Delete()
384 {
385 	free(this);
386 }
387 
388 
389 // #pragma mark - Model
390 
391 
392 Model::Model(const char* dataSourceName, void* eventData, size_t eventDataSize)
393 	:
394 	fDataSourceName(dataSourceName),
395 	fEventData(eventData),
396 	fEventDataSize(eventDataSize),
397 	fBaseTime(0),
398 	fLastEventTime(0),
399 	fTeams(20, true),
400 	fThreads(20, true),
401 	fWaitObjectGroups(20, true),
402 	fSchedulingStates(100)
403 {
404 }
405 
406 
407 Model::~Model()
408 {
409 	for (int32 i = 0; CompactSchedulingState* state
410 		= fSchedulingStates.ItemAt(i); i++) {
411 		state->Delete();
412 	}
413 
414 	free(fEventData);
415 }
416 
417 
418 void
419 Model::LoadingFinished()
420 {
421 	for (int32 i = 0; Thread* thread = fThreads.ItemAt(i); i++)
422 		thread->SetIndex(i);
423 }
424 
425 
426 void
427 Model::SetBaseTime(bigtime_t time)
428 {
429 	fBaseTime = time;
430 }
431 
432 
433 void
434 Model::SetLastEventTime(bigtime_t time)
435 {
436 	fLastEventTime = time;
437 }
438 
439 
440 int32
441 Model::CountTeams() const
442 {
443 		return fTeams.CountItems();
444 }
445 
446 
447 Model::Team*
448 Model::TeamAt(int32 index) const
449 {
450 	return fTeams.ItemAt(index);
451 }
452 
453 
454 Model::Team*
455 Model::TeamByID(team_id id) const
456 {
457 	return fTeams.BinarySearchByKey(id, &Team::CompareWithID);
458 }
459 
460 
461 Model::Team*
462 Model::AddTeam(const system_profiler_team_added* event, bigtime_t time)
463 {
464 	Team* team = TeamByID(event->team);
465 	if (team != NULL) {
466 		fprintf(stderr, "Duplicate team: %ld\n", event->team);
467 		// TODO: User feedback!
468 		return team;
469 	}
470 
471 	team = new(std::nothrow) Team(event, time);
472 	if (team == NULL)
473 		return NULL;
474 
475 	if (!fTeams.BinaryInsert(team, &Team::CompareByID)) {
476 		delete team;
477 		return NULL;
478 	}
479 
480 	return team;
481 }
482 
483 
484 int32
485 Model::CountThreads() const
486 {
487 	return fThreads.CountItems();
488 }
489 
490 
491 Model::Thread*
492 Model::ThreadAt(int32 index) const
493 {
494 	return fThreads.ItemAt(index);
495 }
496 
497 
498 Model::Thread*
499 Model::ThreadByID(thread_id id) const
500 {
501 	return fThreads.BinarySearchByKey(id, &Thread::CompareWithID);
502 }
503 
504 
505 Model::Thread*
506 Model::AddThread(const system_profiler_thread_added* event, bigtime_t time)
507 {
508 	// check whether we do already know the thread
509 	Thread* thread = ThreadByID(event->thread);
510 	if (thread != NULL) {
511 		fprintf(stderr, "Duplicate thread: %ld\n", event->thread);
512 		// TODO: User feedback!
513 		return thread;
514 	}
515 
516 	// get its team
517 	Team* team = TeamByID(event->team);
518 	if (team == NULL) {
519 		fprintf(stderr, "No team for thread: %ld\n", event->thread);
520 		return NULL;
521 	}
522 
523 	// create the thread and add it
524 	thread = new(std::nothrow) Thread(team, event, time);
525 	if (thread == NULL)
526 		return NULL;
527 	ObjectDeleter<Thread> threadDeleter(thread);
528 
529 	if (!fThreads.BinaryInsert(thread, &Thread::CompareByID))
530 		return NULL;
531 
532 	if (!team->AddThread(thread)) {
533 		fThreads.RemoveItem(thread);
534 		return NULL;
535 	}
536 
537 	threadDeleter.Detach();
538 	return thread;
539 }
540 
541 
542 Model::WaitObject*
543 Model::AddWaitObject(const system_profiler_wait_object_info* event,
544 	WaitObjectGroup** _waitObjectGroup)
545 {
546 	// create a wait object
547 	WaitObject* waitObject = new(std::nothrow) WaitObject(event);
548 	if (waitObject == NULL)
549 		return NULL;
550 
551 	// find the wait object group
552 	WaitObjectGroup* waitObjectGroup
553 		= WaitObjectGroupFor(waitObject->Type(), waitObject->Object());
554 	if (waitObjectGroup == NULL) {
555 		// doesn't exist yet -- create
556 		waitObjectGroup = new(std::nothrow) WaitObjectGroup(waitObject);
557 		if (waitObjectGroup == NULL) {
558 			delete waitObject;
559 			return NULL;
560 		}
561 
562 		// add to the list
563 		if (!fWaitObjectGroups.BinaryInsert(waitObjectGroup,
564 				&WaitObjectGroup::CompareByTypeObject)) {
565 			delete waitObjectGroup;
566 			return NULL;
567 		}
568 	} else {
569 		// exists -- just add the object
570 		waitObjectGroup->AddWaitObject(waitObject);
571 	}
572 
573 	if (_waitObjectGroup != NULL)
574 		*_waitObjectGroup = waitObjectGroup;
575 
576 	return waitObject;
577 }
578 
579 
580 Model::WaitObjectGroup*
581 Model::WaitObjectGroupFor(uint32 type, addr_t object) const
582 {
583 	type_and_object key;
584 	key.type = type;
585 	key.object = object;
586 
587 	return fWaitObjectGroups.BinarySearchByKey(key,
588 		&WaitObjectGroup::CompareWithTypeObject);
589 }
590 
591 
592 Model::ThreadWaitObject*
593 Model::AddThreadWaitObject(thread_id threadID, WaitObject* waitObject,
594 	ThreadWaitObjectGroup** _threadWaitObjectGroup)
595 {
596 	Thread* thread = ThreadByID(threadID);
597 	if (thread == NULL)
598 		return NULL;
599 
600 	return thread->AddThreadWaitObject(waitObject, _threadWaitObjectGroup);
601 }
602 
603 
604 Model::ThreadWaitObjectGroup*
605 Model::ThreadWaitObjectGroupFor(thread_id threadID, uint32 type, addr_t object) const
606 {
607 	Thread* thread = ThreadByID(threadID);
608 	if (thread == NULL)
609 		return NULL;
610 
611 	return thread->ThreadWaitObjectGroupFor(type, object);
612 }
613 
614 
615 bool
616 Model::AddSchedulingStateSnapshot(const SchedulingState& state,
617 	off_t eventOffset)
618 {
619 	CompactSchedulingState* compactState = CompactSchedulingState::Create(state,
620 		eventOffset);
621 	if (compactState == NULL)
622 		return false;
623 
624 	if (!fSchedulingStates.AddItem(compactState)) {
625 		compactState->Delete();
626 		return false;
627 	}
628 
629 	return true;
630 }
631 
632 
633 const Model::CompactSchedulingState*
634 Model::ClosestSchedulingState(bigtime_t eventTime) const
635 {
636 	int32 index = fSchedulingStates.BinarySearchIndexByKey(eventTime,
637 		&_CompareEventTimeSchedulingState);
638 	if (index >= 0)
639 		return fSchedulingStates.ItemAt(index);
640 
641 	// no exact match
642 	index = -index - 1;
643 	return index > 0 ? fSchedulingStates.ItemAt(index - 1) : NULL;
644 }
645 
646 
647 /*static*/ int
648 Model::_CompareEventTimeSchedulingState(const bigtime_t* time,
649 	const CompactSchedulingState* state)
650 {
651 	if (*time < state->LastEventTime())
652 		return -1;
653 	return *time == state->LastEventTime() ? 0 : 1;
654 }
655 
656