[kernel][thread] Track per-thread scheduling statistics

Track per-thread runtime, last scheduled time, and count of times
scheduled. Query via existing threadstats CLI.
This commit is contained in:
Aaron Odell
2023-04-04 22:14:32 -07:00
committed by Travis Geiselbrecht
parent 08111d4a37
commit b8e102ecb7
3 changed files with 47 additions and 2 deletions

View File

@@ -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;
}

View File

@@ -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;
@@ -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
@@ -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 */

View File

@@ -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
@@ -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
/** @} */