docs/ikteam: Delete most files.
[haiku.git] / src / bin / debug / time_stats / scheduling_analysis.cpp
blob6069f96d4e93f17508fd886f944e72bfc870b812
1 /*
2 * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
6 #include <errno.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
11 #include <algorithm>
13 #include <OS.h>
15 #include <AutoDeleter.h>
17 #include <scheduler_defs.h>
18 #include <syscalls.h>
19 #include <thread_defs.h>
21 #include "time_stats.h"
24 struct wait_object_group {
25 scheduling_analysis_thread_wait_object** objects;
26 int32 count;
27 bigtime_t wait_time;
28 int64 waits;
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;
70 static const char*
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;
77 switch (type) {
78 case THREAD_BLOCK_TYPE_SEMAPHORE:
79 if (nameOnly) {
80 sprintf(buffer, "sem \"%s\"", waitObject->name);
81 } else {
82 sprintf(buffer, "sem %ld (%s)", (sem_id)(addr_t)object,
83 waitObject->name);
85 break;
86 case THREAD_BLOCK_TYPE_CONDITION_VARIABLE:
87 if (nameOnly) {
88 sprintf(buffer, "cvar \"%s\"", waitObject->name);
89 } else {
90 sprintf(buffer, "cvar %p (%s %p)", object, waitObject->name,
91 waitObject->referenced_object);
93 break;
94 case THREAD_BLOCK_TYPE_SNOOZE:
95 strcpy(buffer, "snooze");
96 break;
97 case THREAD_BLOCK_TYPE_SIGNAL:
98 strcpy(buffer, "signal");
99 break;
100 case THREAD_BLOCK_TYPE_MUTEX:
101 if (nameOnly)
102 sprintf(buffer, "mutex \"%s\"", waitObject->name);
103 else
104 sprintf(buffer, "mutex %p (%s)", object, waitObject->name);
105 break;
106 case THREAD_BLOCK_TYPE_RW_LOCK:
107 if (nameOnly)
108 sprintf(buffer, "rwlock \"%s\"", waitObject->name);
109 else
110 sprintf(buffer, "rwlock %p (%s)", object, waitObject->name);
111 break;
112 case THREAD_BLOCK_TYPE_OTHER:
113 sprintf(buffer, "other %p (%s)", object, waitObject->name);
114 break;
115 default:
116 sprintf(buffer, "unknown %p", object);
117 break;
120 return buffer;
124 void
125 do_scheduling_analysis(bigtime_t startTime, bigtime_t endTime,
126 size_t bufferSize)
128 printf("\n");
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 "
134 "analysis.\n");
135 exit(1);
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);
143 if (error != B_OK) {
144 fprintf(stderr, "Error: Scheduling analysis failed: %s\n",
145 strerror(error));
146 exit(1);
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");
161 exit(1);
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());
190 // create the groups
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
195 = waitObjects[i];
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;
206 group->count = 0;
207 group->wait_time = 0;
208 group->waits = 0;
211 group->count++;
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,
222 thread->runs);
223 printf(" wait time: %lld us\n", waitTime);
224 printf(" latencies: %lld us (%lld)\n", thread->total_latency,
225 thread->latencies);
226 printf(" preemptions: %lld us (%lld)\n", thread->total_rerun_time,
227 thread->reruns);
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];
233 char buffer[1024];
235 if (group.count == 1) {
236 // only one element -- just print it
237 scheduling_analysis_thread_wait_object* threadWaitObject
238 = group.objects[0];
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);
244 } else {
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,
251 true);
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
258 = group.objects[k];
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);