* In the timing table user and kernel time were swapped.

* Scheduling analysis output:
  - Sort the threads by total run time.
  - Group the locking primitives a thread has waited on by common type
    and name. E.g. all "I/O request finished" condition variables are
    put in a single group. The sum wait time and wait count is printed
    for the group, so it is easy to see how often and how long the
    thread had waited for I/O.
  - Both the groups and their elements are sorted by wait time.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27313 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2008-09-04 00:13:53 +00:00
parent e032a7f50e
commit f88e298ec7

View File

@ -60,6 +60,51 @@ struct UsageInfoTimeComparator {
}; };
struct wait_object_group {
scheduling_analysis_thread_wait_object** objects;
int32 count;
bigtime_t wait_time;
int64 waits;
};
struct ThreadRunTimeComparator {
inline bool operator()(const scheduling_analysis_thread* a,
const scheduling_analysis_thread* b)
{
return a->total_run_time > b->total_run_time;
}
};
struct WaitObjectGroupingComparator {
inline bool operator()(const scheduling_analysis_thread_wait_object* a,
const scheduling_analysis_thread_wait_object* b)
{
return a->wait_object->type < b->wait_object->type
|| a->wait_object->type == b->wait_object->type
&& strcmp(a->wait_object->name, b->wait_object->name) < 0;
}
};
struct WaitObjectTimeComparator {
inline bool operator()(const scheduling_analysis_thread_wait_object* a,
const scheduling_analysis_thread_wait_object* b)
{
return a->wait_time > b->wait_time;
}
};
struct WaitObjectGroupTimeComparator {
inline bool operator()(const wait_object_group& a,
const wait_object_group& b)
{
return a.wait_time > b.wait_time;
}
};
static int32 static int32
get_usage_infos(thread_info* infos) get_usage_infos(thread_info* infos)
{ {
@ -104,19 +149,28 @@ run_child(int argc, const char* const* argv)
static const char* static const char*
wait_object_to_string(scheduling_analysis_wait_object* waitObject, char* buffer) wait_object_to_string(scheduling_analysis_wait_object* waitObject, char* buffer,
bool nameOnly = false)
{ {
uint32 type = waitObject->type; uint32 type = waitObject->type;
void* object = waitObject->object; void* object = waitObject->object;
switch (type) { switch (type) {
case THREAD_BLOCK_TYPE_SEMAPHORE: case THREAD_BLOCK_TYPE_SEMAPHORE:
sprintf(buffer, "sem %ld (%s)", (sem_id)(addr_t)object, if (nameOnly) {
waitObject->name); sprintf(buffer, "sem \"%s\"", waitObject->name);
} else {
sprintf(buffer, "sem %ld (%s)", (sem_id)(addr_t)object,
waitObject->name);
}
break; break;
case THREAD_BLOCK_TYPE_CONDITION_VARIABLE: case THREAD_BLOCK_TYPE_CONDITION_VARIABLE:
sprintf(buffer, "cvar %p (%s %p)", object, waitObject->name, if (nameOnly) {
waitObject->referenced_object); sprintf(buffer, "cvar \"%s\"", waitObject->name);
} else {
sprintf(buffer, "cvar %p (%s %p)", object, waitObject->name,
waitObject->referenced_object);
}
break; break;
case THREAD_BLOCK_TYPE_SNOOZE: case THREAD_BLOCK_TYPE_SNOOZE:
strcpy(buffer, "snooze"); strcpy(buffer, "snooze");
@ -125,13 +179,19 @@ wait_object_to_string(scheduling_analysis_wait_object* waitObject, char* buffer)
strcpy(buffer, "signal"); strcpy(buffer, "signal");
break; break;
case THREAD_BLOCK_TYPE_MUTEX: case THREAD_BLOCK_TYPE_MUTEX:
sprintf(buffer, "mutex %p (%s)", object, waitObject->name); if (nameOnly)
sprintf(buffer, "mutex \"%s\"", waitObject->name);
else
sprintf(buffer, "mutex %p (%s)", object, waitObject->name);
break; break;
case THREAD_BLOCK_TYPE_RW_LOCK: case THREAD_BLOCK_TYPE_RW_LOCK:
sprintf(buffer, "rwlock %p (%s)", object, waitObject->name); if (nameOnly)
sprintf(buffer, "rwlock \"%s\"", waitObject->name);
else
sprintf(buffer, "rwlock %p (%s)", object, waitObject->name);
break; break;
case THREAD_BLOCK_TYPE_OTHER: case THREAD_BLOCK_TYPE_OTHER:
sprintf(buffer, "other %p", object); sprintf(buffer, "other %p (%s)", object, waitObject->name);
break; break;
default: default:
sprintf(buffer, "unknown %p", object); sprintf(buffer, "unknown %p", object);
@ -166,22 +226,77 @@ do_scheduling_analysis(bigtime_t startTime, bigtime_t endTime)
exit(1); exit(1);
} }
// allocate arrays for grouping and sorting the wait objects
scheduling_analysis_thread_wait_object** waitObjects
= new(std::nothrow) scheduling_analysis_thread_wait_object*[
analysis.thread_wait_object_count];
ArrayDeleter<scheduling_analysis_thread_wait_object*> _2(waitObjects);
wait_object_group* waitObjectGroups = new(std::nothrow) wait_object_group[
analysis.thread_wait_object_count];
ArrayDeleter<wait_object_group> _3(waitObjectGroups);
if (waitObjects == NULL || waitObjectGroups == NULL) {
fprintf(stderr, "Error: Out of memory\n");
exit(1);
}
printf("scheduling analysis: %lu threads, %llu wait objects, " printf("scheduling analysis: %lu threads, %llu wait objects, "
"%llu thread wait objects\n", analysis.thread_count, "%llu thread wait objects\n", analysis.thread_count,
analysis.wait_object_count, analysis.thread_wait_object_count); analysis.wait_object_count, analysis.thread_wait_object_count);
// sort the thread by run time
std::sort(analysis.threads, analysis.threads + analysis.thread_count,
ThreadRunTimeComparator());
for (uint32 i = 0; i < analysis.thread_count; i++) { for (uint32 i = 0; i < analysis.thread_count; i++) {
scheduling_analysis_thread* thread = analysis.threads[i]; scheduling_analysis_thread* thread = analysis.threads[i];
// compute total wait time // compute total wait time and prepare the objects for sorting
int32 waitObjectCount = 0;
bigtime_t waitTime = 0; bigtime_t waitTime = 0;
scheduling_analysis_thread_wait_object* threadWaitObject scheduling_analysis_thread_wait_object* threadWaitObject
= thread->wait_objects; = thread->wait_objects;
while (threadWaitObject != NULL) { while (threadWaitObject != NULL) {
waitObjects[waitObjectCount++] = threadWaitObject;
waitTime += threadWaitObject->wait_time; waitTime += threadWaitObject->wait_time;
threadWaitObject = threadWaitObject->next_in_list; threadWaitObject = threadWaitObject->next_in_list;
} }
// sort the wait objects by type + name
std::sort(waitObjects, waitObjects + waitObjectCount,
WaitObjectGroupingComparator());
// create the groups
wait_object_group* group = NULL;
int32 groupCount = 0;
for (int32 i = 0; i < waitObjectCount; i++) {
scheduling_analysis_thread_wait_object* threadWaitObject
= waitObjects[i];
scheduling_analysis_wait_object* waitObject
= threadWaitObject->wait_object;
if (groupCount == 0 || strcmp(waitObject->name, "?") == 0
|| waitObject->type != group->objects[0]->wait_object->type
|| strcmp(waitObject->name,
group->objects[0]->wait_object->name) != 0) {
// create a new group
group = &waitObjectGroups[groupCount++];
group->objects = waitObjects + i;
group->count = 0;
group->wait_time = 0;
group->waits = 0;
}
group->count++;
group->wait_time += threadWaitObject->wait_time;
group->waits += threadWaitObject->waits;
}
// sort the groups by wait time
std::sort(waitObjectGroups, waitObjectGroups + groupCount,
WaitObjectGroupTimeComparator());
printf("\nthread %ld \"%s\":\n", thread->id, thread->name); printf("\nthread %ld \"%s\":\n", thread->id, thread->name);
printf(" run time: %lld us (%lld runs)\n", thread->total_run_time, printf(" run time: %lld us (%lld runs)\n", thread->total_run_time,
thread->runs); thread->runs);
@ -191,16 +306,43 @@ do_scheduling_analysis(bigtime_t startTime, bigtime_t endTime)
printf(" preemptions: %lld us (%lld)\n", thread->total_rerun_time, printf(" preemptions: %lld us (%lld)\n", thread->total_rerun_time,
thread->reruns); thread->reruns);
printf(" unspecified: %lld us\n", thread->unspecified_wait_time); printf(" unspecified: %lld us\n", thread->unspecified_wait_time);
printf(" waited on:\n");
threadWaitObject = thread->wait_objects;
while (threadWaitObject != NULL) {
scheduling_analysis_wait_object* waitObject
= threadWaitObject->wait_object;
char buffer[1024];
wait_object_to_string(waitObject, buffer);
printf(" %s: %lld us\n", buffer, threadWaitObject->wait_time);
threadWaitObject = threadWaitObject->next_in_list; printf(" waited on:\n");
for (int32 i = 0; i < groupCount; i++) {
wait_object_group& group = waitObjectGroups[i];
char buffer[1024];
if (group.count == 1) {
// only one element -- just print it
scheduling_analysis_thread_wait_object* threadWaitObject
= group.objects[0];
scheduling_analysis_wait_object* waitObject
= threadWaitObject->wait_object;
wait_object_to_string(waitObject, buffer);
printf(" %s: %lld us (%lld)\n", buffer,
threadWaitObject->wait_time, threadWaitObject->waits);
} else {
// sort the wait objects by wait time
std::sort(group.objects, group.objects + group.count,
WaitObjectTimeComparator());
// print the group line
wait_object_to_string(group.objects[0]->wait_object, buffer,
true);
printf(" group %s: %lld us (%lld)\n", buffer,
group.wait_time, group.waits);
// print the wait objects
for (int32 k = 0; k < group.count; k++) {
scheduling_analysis_thread_wait_object* threadWaitObject
= group.objects[k];
scheduling_analysis_wait_object* waitObject
= threadWaitObject->wait_object;
wait_object_to_string(waitObject, buffer);
printf(" %s: %lld us (%lld)\n", buffer,
threadWaitObject->wait_time, threadWaitObject->waits);
}
}
} }
} }
} }
@ -314,7 +456,7 @@ do_timing_analysis(int argc, const char* const* argv, bool schedulingAnalysis,
bigtime_t total = info.user_time + info.kernel_time; bigtime_t total = info.user_time + info.kernel_time;
printf("%7ld %-32s %10lld %10lld %10lld %6.2f\n", info.thread, printf("%7ld %-32s %10lld %10lld %10lld %6.2f\n", info.thread,
info.name, info.user_time, info.kernel_time, total, info.name, info.kernel_time, info.user_time, total,
(double)total / runTime * 100); (double)total / runTime * 100);
if (highlight) if (highlight)