2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de.
4 * Distributed under the terms of the MIT License.
7 #include "scheduler_tracing.h"
14 namespace SchedulerTracing
{
16 // #pragma mark - EnqueueThread
20 EnqueueThread::AddDump(TraceOutput
& out
)
22 out
.Print("scheduler enqueue %ld \"%s\", effective priority %d, "
23 "real priority %d", fID
, fName
, fEffectivePriority
, fPriority
);
28 EnqueueThread::Name() const
34 // #pragma mark - RemoveThread
38 RemoveThread::AddDump(TraceOutput
& out
)
40 out
.Print("scheduler remove %ld, priority %d", fID
, fPriority
);
44 RemoveThread::Name() const
50 // #pragma mark - ScheduleThread
54 ScheduleThread::AddDump(TraceOutput
& out
)
56 out
.Print("schedule %ld \"%s\", priority %d, CPU %ld, "
57 "previous thread: %ld (", fID
, fName
, fPriority
, fCPU
, fPreviousID
);
58 if (fPreviousState
== B_THREAD_WAITING
) {
59 switch (fPreviousWaitObjectType
) {
60 case THREAD_BLOCK_TYPE_SEMAPHORE
:
61 out
.Print("sem %ld", (sem_id
)(addr_t
)fPreviousWaitObject
);
63 case THREAD_BLOCK_TYPE_CONDITION_VARIABLE
:
64 out
.Print("cvar %p", fPreviousWaitObject
);
66 case THREAD_BLOCK_TYPE_SNOOZE
:
67 out
.Print("snooze()");
69 case THREAD_BLOCK_TYPE_SIGNAL
:
72 case THREAD_BLOCK_TYPE_MUTEX
:
73 out
.Print("mutex %p", fPreviousWaitObject
);
75 case THREAD_BLOCK_TYPE_RW_LOCK
:
76 out
.Print("rwlock %p", fPreviousWaitObject
);
78 case THREAD_BLOCK_TYPE_OTHER
:
79 out
.Print("other (%p)", fPreviousWaitObject
);
80 // We could print the string, but it might come from a
81 // kernel module that has already been unloaded.
84 out
.Print("unknown (%p)", fPreviousWaitObject
);
87 #if SCHEDULER_TRACING >= 2
88 } else if (fPreviousState
== B_THREAD_READY
) {
89 out
.Print("ready at %p", fPreviousPC
);
92 out
.Print("%s", thread_state_to_text(NULL
, fPreviousState
));
99 ScheduleThread::Name() const
104 } // namespace SchedulerTracing
111 cmd_scheduler(int argc
, char** argv
)
113 using namespace SchedulerTracing
;
117 || !evaluate_debug_expression(argv
[1], (uint64
*)&threadID
, true)) {
118 print_debugger_command_usage(argv
[0]);
123 kprintf("Invalid thread ID: %lld\n", threadID
);
127 ScheduleState state
= UNKNOWN
;
128 bigtime_t lastTime
= 0;
131 bigtime_t totalRunTime
= 0;
132 bigtime_t minRunTime
= -1;
133 bigtime_t maxRunTime
= -1;
136 bigtime_t totalLatency
= 0;
137 bigtime_t minLatency
= -1;
138 bigtime_t maxLatency
= -1;
139 int32 maxLatencyEntry
= -1;
142 bigtime_t totalRerunTime
= 0;
143 bigtime_t minRerunTime
= -1;
144 bigtime_t maxRerunTime
= -1;
145 int32 maxRerunEntry
= -1;
147 int64 preemptions
= 0;
149 TraceEntryIterator iterator
;
150 while (TraceEntry
* _entry
= iterator
.Next()) {
151 if (dynamic_cast<SchedulerTraceEntry
*>(_entry
) == NULL
)
154 if (ScheduleThread
* entry
= dynamic_cast<ScheduleThread
*>(_entry
)) {
155 if (entry
->ThreadID() == threadID
) {
157 bigtime_t diffTime
= entry
->Time() - lastTime
;
159 if (state
== READY
) {
160 // thread scheduled after having been woken up
162 totalLatency
+= diffTime
;
163 if (minLatency
< 0 || diffTime
< minLatency
)
164 minLatency
= diffTime
;
165 if (diffTime
> maxLatency
) {
166 maxLatency
= diffTime
;
167 maxLatencyEntry
= iterator
.Index();
169 } else if (state
== PREEMPTED
) {
170 // thread scheduled after having been preempted before
172 totalRerunTime
+= diffTime
;
173 if (minRerunTime
< 0 || diffTime
< minRerunTime
)
174 minRerunTime
= diffTime
;
175 if (diffTime
> maxRerunTime
) {
176 maxRerunTime
= diffTime
;
177 maxRerunEntry
= iterator
.Index();
181 if (state
== STILL_RUNNING
) {
182 // Thread was running and continues to run.
186 if (state
!= RUNNING
) {
187 lastTime
= entry
->Time();
190 } else if (entry
->PreviousThreadID() == threadID
) {
191 // thread unscheduled
192 bigtime_t diffTime
= entry
->Time() - lastTime
;
194 if (state
== STILL_RUNNING
) {
198 totalRunTime
+= diffTime
;
199 if (minRunTime
< 0 || diffTime
< minRunTime
)
200 minRunTime
= diffTime
;
201 if (diffTime
> maxRunTime
)
202 maxRunTime
= diffTime
;
205 lastTime
= entry
->Time();
206 } else if (state
== RUNNING
) {
207 // thread starts waiting (it hadn't been added to the run
208 // queue before being unscheduled)
209 bigtime_t diffTime
= entry
->Time() - lastTime
;
211 totalRunTime
+= diffTime
;
212 if (minRunTime
< 0 || diffTime
< minRunTime
)
213 minRunTime
= diffTime
;
214 if (diffTime
> maxRunTime
)
215 maxRunTime
= diffTime
;
218 lastTime
= entry
->Time();
221 } else if (EnqueueThread
* entry
222 = dynamic_cast<EnqueueThread
*>(_entry
)) {
223 if (entry
->ThreadID() != threadID
)
226 // thread enqueued in run queue
228 if (state
== RUNNING
|| state
== STILL_RUNNING
) {
229 // Thread was running and is reentered into the run queue. This
230 // is done by the scheduler, if the thread remains ready.
231 state
= STILL_RUNNING
;
233 // Thread was waiting and is ready now.
234 lastTime
= entry
->Time();
237 } else if (RemoveThread
* entry
= dynamic_cast<RemoveThread
*>(_entry
)) {
238 if (entry
->ThreadID() != threadID
)
241 // thread removed from run queue
243 // This really only happens when the thread priority is changed
244 // while the thread is ready.
246 if (state
== RUNNING
) {
247 // This should never happen.
248 bigtime_t diffTime
= entry
->Time() - lastTime
;
250 totalRunTime
+= diffTime
;
251 if (minRunTime
< 0 || diffTime
< minRunTime
)
252 minRunTime
= diffTime
;
253 if (diffTime
> maxRunTime
)
254 maxRunTime
= diffTime
;
263 kprintf("thread %lld never ran.\n", threadID
);
267 kprintf("scheduling statistics for thread %lld:\n", threadID
);
269 kprintf(" total #: %lld\n", runs
);
270 kprintf(" total: %lld us\n", totalRunTime
);
271 kprintf(" average: %#.2f us\n", (double)totalRunTime
/ runs
);
272 kprintf(" min: %lld us\n", minRunTime
);
273 kprintf(" max: %lld us\n", maxRunTime
);
276 kprintf("scheduling latency after wake up:\n");
277 kprintf(" total #: %lld\n", latencies
);
278 kprintf(" total: %lld us\n", totalLatency
);
279 kprintf(" average: %#.2f us\n", (double)totalLatency
/ latencies
);
280 kprintf(" min: %lld us\n", minLatency
);
281 kprintf(" max: %lld us\n", maxLatency
);
282 kprintf(" max: %lld us (at tracing entry %ld)\n", maxLatency
,
285 kprintf("thread was never run after having been woken up\n");
288 kprintf("scheduling latency after preemption:\n");
289 kprintf(" total #: %lld\n", reruns
);
290 kprintf(" total: %lld us\n", totalRerunTime
);
291 kprintf(" average: %#.2f us\n", (double)totalRerunTime
/ reruns
);
292 kprintf(" min: %lld us\n", minRerunTime
);
293 kprintf(" max: %lld us (at tracing entry %ld)\n", maxRerunTime
,
296 kprintf("thread was never rerun after preemption\n");
299 kprintf("thread was preempted %lld times\n", preemptions
);
301 kprintf("thread was never preempted\n");
306 #endif // SCHEDULER_TRACING