Skip to content

Commit

Permalink
[kernel][thread] Track per-thread scheduling statistics
Browse files Browse the repository at this point in the history
Track per-thread runtime, last scheduled time, and count of times
scheduled. Query via existing threadstats CLI.
  • Loading branch information
aaron-odell authored and travisg committed Jun 1, 2023
1 parent 08111d4 commit b8e102e
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 2 deletions.
1 change: 1 addition & 0 deletions kernel/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ static int cmd_threadstats(int argc, const console_cmd_args *argv) {
printf("\ttimers: %lu\n", thread_stats[i].timers);
}

dump_threads_stats();
return 0;
}

Expand Down
13 changes: 13 additions & 0 deletions kernel/include/kernel/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ enum thread_tls_list {

#define THREAD_MAGIC (0x74687264) // 'thrd'

#if THREAD_STATS
struct thread_specific_stats {
lk_bigtime_t total_run_time;
lk_bigtime_t last_run_timestamp;
ulong schedules; // times this thread is scheduled to run.
};
#endif

typedef struct thread {
int magic;
struct list_node thread_list_node;
Expand Down Expand Up @@ -110,6 +118,10 @@ typedef struct thread {
uintptr_t tls[MAX_TLS_ENTRY];

char name[32];

#if THREAD_STATS
struct thread_specific_stats stats;
#endif
} thread_t;

#if WITH_SMP
Expand Down Expand Up @@ -163,6 +175,7 @@ void dump_thread(thread_t *t);
void arch_dump_thread(thread_t *t);
void dump_all_threads(void);
void dump_all_threads_unlocked(void);
void dump_threads_stats(void);

/* scheduler routines */
void thread_yield(void); /* give up the cpu voluntarily */
Expand Down
35 changes: 33 additions & 2 deletions kernel/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -516,12 +516,17 @@ void thread_resched(void) {
#if THREAD_STATS
THREAD_STATS_INC(context_switches);

lk_bigtime_t now = current_time_hires();
if (thread_is_idle(oldthread)) {
lk_bigtime_t now = current_time_hires();
thread_stats[cpu].idle_time += now - thread_stats[cpu].last_idle_timestamp;
} else {
oldthread->stats.total_run_time += now - oldthread->stats.last_run_timestamp;
}
if (thread_is_idle(newthread)) {
thread_stats[cpu].last_idle_timestamp = current_time_hires();
thread_stats[cpu].last_idle_timestamp = now;
} else {
newthread->stats.last_run_timestamp = now;
newthread->stats.schedules++;
}
#endif

Expand Down Expand Up @@ -1010,6 +1015,32 @@ void dump_all_threads(void) {
THREAD_UNLOCK(state);
}

#if THREAD_STATS
void dump_threads_stats(void) {
thread_t *t;

THREAD_LOCK(state);
list_for_every_entry (&thread_list, t, thread_t, thread_list_node) {
if (t->magic != THREAD_MAGIC) {
dprintf(INFO, "bad magic on thread struct %p, aborting.\n", t);
hexdump(t, sizeof(thread_t));
break;
}
if (thread_is_idle(t)) {
continue;
}
// thread specific stats
dprintf(INFO, "\t(%s):\n", t->name);
dprintf(INFO, "\t\tScheduled: %ld\n", t->stats.schedules);
uint percent = (t->stats.total_run_time * 10000) / current_time_hires();
dprintf(INFO, "\t\tTotal run time: %lld, %u.%02u%%\n", t->stats.total_run_time,
percent / 100, percent % 100);
dprintf(INFO, "\t\tLast time run: %lld\n", t->stats.last_run_timestamp);
}
THREAD_UNLOCK(state);
}
#endif

/** @} */


Expand Down

0 comments on commit b8e102e

Please sign in to comment.