2 * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
15 #include <AutoDeleter.h>
17 #include <scheduler_defs.h>
19 #include <thread_defs.h>
21 #include "time_stats.h"
24 struct wait_object_group
{
25 scheduling_analysis_thread_wait_object
** objects
;
32 struct ThreadRunTimeComparator
{
33 inline bool operator()(const scheduling_analysis_thread
* a
,
34 const scheduling_analysis_thread
* b
)
36 return a
->total_run_time
> b
->total_run_time
;
41 struct WaitObjectGroupingComparator
{
42 inline bool operator()(const scheduling_analysis_thread_wait_object
* a
,
43 const scheduling_analysis_thread_wait_object
* b
)
45 return a
->wait_object
->type
< b
->wait_object
->type
46 || (a
->wait_object
->type
== b
->wait_object
->type
47 && strcmp(a
->wait_object
->name
, b
->wait_object
->name
) < 0);
52 struct WaitObjectTimeComparator
{
53 inline bool operator()(const scheduling_analysis_thread_wait_object
* a
,
54 const scheduling_analysis_thread_wait_object
* b
)
56 return a
->wait_time
> b
->wait_time
;
61 struct WaitObjectGroupTimeComparator
{
62 inline bool operator()(const wait_object_group
& a
,
63 const wait_object_group
& b
)
65 return a
.wait_time
> b
.wait_time
;
71 wait_object_to_string(scheduling_analysis_wait_object
* waitObject
, char* buffer
,
72 bool nameOnly
= false)
74 uint32 type
= waitObject
->type
;
75 void* object
= waitObject
->object
;
78 case THREAD_BLOCK_TYPE_SEMAPHORE
:
80 sprintf(buffer
, "sem \"%s\"", waitObject
->name
);
82 sprintf(buffer
, "sem %ld (%s)", (sem_id
)(addr_t
)object
,
86 case THREAD_BLOCK_TYPE_CONDITION_VARIABLE
:
88 sprintf(buffer
, "cvar \"%s\"", waitObject
->name
);
90 sprintf(buffer
, "cvar %p (%s %p)", object
, waitObject
->name
,
91 waitObject
->referenced_object
);
94 case THREAD_BLOCK_TYPE_SNOOZE
:
95 strcpy(buffer
, "snooze");
97 case THREAD_BLOCK_TYPE_SIGNAL
:
98 strcpy(buffer
, "signal");
100 case THREAD_BLOCK_TYPE_MUTEX
:
102 sprintf(buffer
, "mutex \"%s\"", waitObject
->name
);
104 sprintf(buffer
, "mutex %p (%s)", object
, waitObject
->name
);
106 case THREAD_BLOCK_TYPE_RW_LOCK
:
108 sprintf(buffer
, "rwlock \"%s\"", waitObject
->name
);
110 sprintf(buffer
, "rwlock %p (%s)", object
, waitObject
->name
);
112 case THREAD_BLOCK_TYPE_OTHER
:
113 sprintf(buffer
, "other %p (%s)", object
, waitObject
->name
);
116 sprintf(buffer
, "unknown %p", object
);
125 do_scheduling_analysis(bigtime_t startTime
, bigtime_t endTime
,
130 // allocate a chunk of memory for the scheduling analysis
131 void* buffer
= malloc(bufferSize
);
132 if (buffer
== NULL
) {
133 fprintf(stderr
, "Error: Failed to allocate memory for the scheduling "
137 MemoryDeleter
_(buffer
);
139 // do the scheduling analysis
140 scheduling_analysis analysis
;
141 status_t error
= _kern_analyze_scheduling(startTime
, endTime
, buffer
,
142 bufferSize
, &analysis
);
144 fprintf(stderr
, "Error: Scheduling analysis failed: %s\n",
149 // allocate arrays for grouping and sorting the wait objects
150 scheduling_analysis_thread_wait_object
** waitObjects
151 = new(std::nothrow
) scheduling_analysis_thread_wait_object
*[
152 analysis
.thread_wait_object_count
];
153 ArrayDeleter
<scheduling_analysis_thread_wait_object
*> _2(waitObjects
);
155 wait_object_group
* waitObjectGroups
= new(std::nothrow
) wait_object_group
[
156 analysis
.thread_wait_object_count
];
157 ArrayDeleter
<wait_object_group
> _3(waitObjectGroups
);
159 if (waitObjects
== NULL
|| waitObjectGroups
== NULL
) {
160 fprintf(stderr
, "Error: Out of memory\n");
164 printf("scheduling analysis: %lu threads, %llu wait objects, "
165 "%llu thread wait objects\n", analysis
.thread_count
,
166 analysis
.wait_object_count
, analysis
.thread_wait_object_count
);
168 // sort the thread by run time
169 std::sort(analysis
.threads
, analysis
.threads
+ analysis
.thread_count
,
170 ThreadRunTimeComparator());
172 for (uint32 i
= 0; i
< analysis
.thread_count
; i
++) {
173 scheduling_analysis_thread
* thread
= analysis
.threads
[i
];
175 // compute total wait time and prepare the objects for sorting
176 int32 waitObjectCount
= 0;
177 bigtime_t waitTime
= 0;
178 scheduling_analysis_thread_wait_object
* threadWaitObject
179 = thread
->wait_objects
;
180 while (threadWaitObject
!= NULL
) {
181 waitObjects
[waitObjectCount
++] = threadWaitObject
;
182 waitTime
+= threadWaitObject
->wait_time
;
183 threadWaitObject
= threadWaitObject
->next_in_list
;
186 // sort the wait objects by type + name
187 std::sort(waitObjects
, waitObjects
+ waitObjectCount
,
188 WaitObjectGroupingComparator());
191 wait_object_group
* group
= NULL
;
192 int32 groupCount
= 0;
193 for (int32 i
= 0; i
< waitObjectCount
; i
++) {
194 scheduling_analysis_thread_wait_object
* threadWaitObject
196 scheduling_analysis_wait_object
* waitObject
197 = threadWaitObject
->wait_object
;
199 if (groupCount
== 0 || strcmp(waitObject
->name
, "?") == 0
200 || waitObject
->type
!= group
->objects
[0]->wait_object
->type
201 || strcmp(waitObject
->name
,
202 group
->objects
[0]->wait_object
->name
) != 0) {
203 // create a new group
204 group
= &waitObjectGroups
[groupCount
++];
205 group
->objects
= waitObjects
+ i
;
207 group
->wait_time
= 0;
212 group
->wait_time
+= threadWaitObject
->wait_time
;
213 group
->waits
+= threadWaitObject
->waits
;
216 // sort the groups by wait time
217 std::sort(waitObjectGroups
, waitObjectGroups
+ groupCount
,
218 WaitObjectGroupTimeComparator());
220 printf("\nthread %ld \"%s\":\n", thread
->id
, thread
->name
);
221 printf(" run time: %lld us (%lld runs)\n", thread
->total_run_time
,
223 printf(" wait time: %lld us\n", waitTime
);
224 printf(" latencies: %lld us (%lld)\n", thread
->total_latency
,
226 printf(" preemptions: %lld us (%lld)\n", thread
->total_rerun_time
,
228 printf(" unspecified: %lld us\n", thread
->unspecified_wait_time
);
230 printf(" waited on:\n");
231 for (int32 i
= 0; i
< groupCount
; i
++) {
232 wait_object_group
& group
= waitObjectGroups
[i
];
235 if (group
.count
== 1) {
236 // only one element -- just print it
237 scheduling_analysis_thread_wait_object
* threadWaitObject
239 scheduling_analysis_wait_object
* waitObject
240 = threadWaitObject
->wait_object
;
241 wait_object_to_string(waitObject
, buffer
);
242 printf(" %s: %lld us (%lld)\n", buffer
,
243 threadWaitObject
->wait_time
, threadWaitObject
->waits
);
245 // sort the wait objects by wait time
246 std::sort(group
.objects
, group
.objects
+ group
.count
,
247 WaitObjectTimeComparator());
249 // print the group line
250 wait_object_to_string(group
.objects
[0]->wait_object
, buffer
,
252 printf(" group %s: %lld us (%lld)\n", buffer
,
253 group
.wait_time
, group
.waits
);
255 // print the wait objects
256 for (int32 k
= 0; k
< group
.count
; k
++) {
257 scheduling_analysis_thread_wait_object
* threadWaitObject
259 scheduling_analysis_wait_object
* waitObject
260 = threadWaitObject
->wait_object
;
261 wait_object_to_string(waitObject
, buffer
);
262 printf(" %s: %lld us (%lld)\n", buffer
,
263 threadWaitObject
->wait_time
, threadWaitObject
->waits
);