/* * Copyright (c) 2008 Travis Geiselbrecht * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #if defined(WITH_LIB_CONSOLE) #include static int cmd_threads(int argc, const cmd_args *argv); static int cmd_threadstats(int argc, const cmd_args *argv); static int cmd_threadload(int argc, const cmd_args *argv); STATIC_COMMAND_START #if DEBUGLEVEL > 1 { "threads", "list kernel threads", &cmd_threads }, #endif #if THREAD_STATS { "threadstats", "thread level statistics", &cmd_threadstats }, { "threadload", "toggle thread load display", &cmd_threadload }, #endif STATIC_COMMAND_END(kernel); #if DEBUGLEVEL > 1 static int cmd_threads(int argc, const cmd_args *argv) { printf("thread list:\n"); dump_all_threads(); return 0; } #endif #if THREAD_STATS static int cmd_threadstats(int argc, const cmd_args *argv) { printf("thread stats:\n"); printf("\ttotal idle time: %lld\n", thread_stats.idle_time); printf("\ttotal busy time: %lld\n", current_time_hires() - thread_stats.idle_time); printf("\treschedules: %d\n", thread_stats.reschedules); printf("\tcontext_switches: %d\n", thread_stats.context_switches); printf("\tpreempts: %d\n", thread_stats.preempts); printf("\tyields: %d\n", thread_stats.yields); printf("\tinterrupts: %d\n", thread_stats.interrupts); printf("\ttimer interrupts: %d\n", thread_stats.timer_ints); printf("\ttimers: %d\n", thread_stats.timers); return 0; } static enum handler_return threadload(struct timer *t, time_t now, void *arg) { static struct thread_stats old_stats; static bigtime_t last_idle_time; timer_set_oneshot(t, 1000, &threadload, NULL); bigtime_t idle_time = thread_stats.idle_time; if (current_thread == idle_thread) { idle_time += current_time_hires() - thread_stats.last_idle_timestamp; } bigtime_t busy_time = 1000000ULL - (idle_time - last_idle_time); uint busypercent = (busy_time * 10000) / (1000000); // printf("idle_time %lld, busytime %lld\n", idle_time - last_idle_time, busy_time); printf("LOAD: %d.%02d%%, cs %d, ints %d, timer ints %d, timers %d\n", busypercent / 100, busypercent % 100, thread_stats.context_switches - old_stats.context_switches, thread_stats.interrupts - old_stats.interrupts, thread_stats.timer_ints - old_stats.timer_ints, thread_stats.timers - old_stats.timers); old_stats = thread_stats; last_idle_time = idle_time; return INT_NO_RESCHEDULE; } static int cmd_threadload(int argc, const cmd_args *argv) { static bool showthreadload = false; static timer_t tltimer; enter_critical_section(); if (showthreadload == false) { // start the display timer_initialize(&tltimer); timer_set_oneshot(&tltimer, 1000, &threadload, NULL); showthreadload = true; } else { timer_cancel(&tltimer); showthreadload = false; } exit_critical_section(); return 0; } #endif #endif