From: Maria Matejka Date: Thu, 29 Aug 2024 08:10:37 +0000 (+0200) Subject: Displaced show threads command to its own file X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7ff111e97b71dde0a600c538acbd74f4d7f18554;p=thirdparty%2Fbird.git Displaced show threads command to its own file --- diff --git a/lib/io-loop.h b/lib/io-loop.h index 9f08420a6..1923af4e6 100644 --- a/lib/io-loop.h +++ b/lib/io-loop.h @@ -7,15 +7,17 @@ #ifndef _BIRD_IO_LOOP_H_ #define _BIRD_IO_LOOP_H_ +extern struct birdloop main_birdloop; + #include "nest/bird.h" #include "lib/lists.h" #include "lib/locking.h" #include "lib/resource.h" +#include "lib/buffer.h" #include "lib/event.h" +#include "lib/timer.h" #include "lib/socket.h" -extern struct birdloop main_birdloop; - /* Currently running birdloop */ extern _Thread_local struct birdloop *this_birdloop; diff --git a/lib/timer.h b/lib/timer.h index 84a6bac5d..91015622b 100644 --- a/lib/timer.h +++ b/lib/timer.h @@ -120,6 +120,10 @@ void timers_fire(struct timeloop *loop); /* For extra fine precision */ u64 ns_now(void); +#define NSEC_IN_SEC ((u64) (1000 * 1000 * 1000)) +#define NSEC_TO_SEC(x) ((x) / NSEC_IN_SEC) +#define CURRENT_SEC NSEC_TO_SEC(ns_now()) + struct timeformat { const char *fmt1, *fmt2; btime limit; diff --git a/sysdep/unix/Makefile b/sysdep/unix/Makefile index dba128772..574d19bdf 100644 --- a/sysdep/unix/Makefile +++ b/sysdep/unix/Makefile @@ -1,4 +1,4 @@ -src := alloc.c io.c io-loop.c krt.c log.c main.c random.c domain.c socket.c file.c time.c +src := alloc.c io.c io-cli.c io-loop.c krt.c log.c main.c random.c domain.c socket.c file.c time.c obj := $(src-o-files) $(all-daemon) $(cf-local) diff --git a/sysdep/unix/io-cli.c b/sysdep/unix/io-cli.c new file mode 100644 index 000000000..7188a52f1 --- /dev/null +++ b/sysdep/unix/io-cli.c @@ -0,0 +1,175 @@ +/* + * CLI: Show threads + */ + +#include "nest/bird.h" + +#include "lib/io-loop.h" +#include "sysdep/unix/io-loop.h" +#include "nest/cli.h" +#include "conf/conf.h" + + +struct bird_thread_show_data { + struct bird_thread_syncer sync; + cli *cli; + linpool *lp; + u8 show_loops; + uint line_pos; + uint line_max; + const char **lines; +}; + +#define tsd_append(...) do { \ + if (!tsd->lines) \ + tsd->lines = mb_allocz(tsd->sync.pool, sizeof(const char *) * tsd->line_max); \ + if (tsd->line_pos >= tsd->line_max) \ + tsd->lines = mb_realloc(tsd->lines, sizeof (const char *) * (tsd->line_max *= 2)); \ + tsd->lines[tsd->line_pos++] = lp_sprintf(tsd->lp, __VA_ARGS__); \ +} while (0) + +static void +bird_thread_show_cli_cont(struct cli *c UNUSED) +{ + /* Explicitly do nothing to prevent CLI from trying to parse another command. */ +} + +static bool +bird_thread_show_cli_cleanup(struct cli *c UNUSED) +{ + /* Defer the cleanup until the writeout is finished. */ + return false; +} + +static void +bird_thread_show_spent_time(struct bird_thread_show_data *tsd, const char *name, struct spent_time *st) +{ + char b[TIME_BY_SEC_SIZE * sizeof("1234567890, ")], *bptr = b, *bend = b + sizeof(b); + uint cs = CURRENT_SEC; + uint fs = NSEC_TO_SEC(st->last_written_ns); + + for (uint i = 0; i <= cs && i < TIME_BY_SEC_SIZE; i++) + bptr += bsnprintf(bptr, bend - bptr, "% 10lu ", + (cs - i > fs) ? 0 : st->by_sec_ns[(cs - i) % TIME_BY_SEC_SIZE]); + bptr[-1] = 0; /* Drop the trailing space */ + + tsd_append(" %s total time: % 9t s; last %d secs [ns]: %s", name, st->total_ns NS, MIN(CURRENT_SEC+1, TIME_BY_SEC_SIZE), b); +} + +static void +bird_thread_show_loop(struct bird_thread_show_data *tsd, struct birdloop *loop) +{ + tsd_append(" Loop %s", domain_name(loop->time.domain)); + bird_thread_show_spent_time(tsd, "Working ", &loop->working); + bird_thread_show_spent_time(tsd, "Locking ", &loop->locking); +} + +static void +bird_thread_show(struct bird_thread_syncer *sync) +{ + SKIP_BACK_DECLARE(struct bird_thread_show_data, tsd, sync, sync); + + if (!tsd->lp) + tsd->lp = lp_new(tsd->sync.pool); + + if (tsd->show_loops) + tsd_append("Thread %04x %s (busy counter %d)", THIS_THREAD_ID, this_thread->busy_active ? " [busy]" : "", this_thread->busy_counter); + + u64 total_time_ns = 0; + struct birdloop *loop; + WALK_LIST(loop, this_thread->loops) + { + if (tsd->show_loops) + bird_thread_show_loop(tsd, loop); + + total_time_ns += loop->working.total_ns + loop->locking.total_ns; + } + + if (tsd->show_loops) + { + tsd_append(" Total working time: %t", total_time_ns NS); + bird_thread_show_spent_time(tsd, "Overhead", &this_thread->overhead); + bird_thread_show_spent_time(tsd, "Idle ", &this_thread->idle); + } + else + tsd_append("%04x%s % 9.3t s % 9.3t s % 9.3t s", + THIS_THREAD_ID, this_thread->busy_active ? " [busy]" : " ", + total_time_ns NS, this_thread->overhead.total_ns NS, + (ns_now() - this_thread->meta->last_transition_ns) NS); +} + +static void +cmd_show_threads_done(struct bird_thread_syncer *sync) +{ + SKIP_BACK_DECLARE(struct bird_thread_show_data, tsd, sync, sync); + ASSERT_DIE(birdloop_inside(&main_birdloop)); + + /* The client lost their patience and dropped the session early. */ + if (!tsd->cli->sock) + { + mb_free(tsd); + rp_free(tsd->cli->pool); + return; + } + + tsd->cli->cont = NULL; + tsd->cli->cleanup = NULL; + + for (int i=0; i<2; i++) + { + struct birdloop_pickup_group *group = &pickup_groups[i]; + + LOCK_DOMAIN(attrs, group->domain); + uint count = 0; + u64 total_time_ns = 0; + if (!EMPTY_LIST(group->loops)) + { + if (tsd->show_loops) + tsd_append("Unassigned loops in group %d:", i); + + struct birdloop *loop; + WALK_LIST(loop, group->loops) + { + if (tsd->show_loops) + bird_thread_show_loop(tsd, loop); + + total_time_ns += loop->working.total_ns + loop->locking.total_ns; + count++; + } + + if (tsd->show_loops) + tsd_append(" Total working time: %t", total_time_ns NS); + else + tsd_append("Unassigned %d loops in group %d, total time %t", count, i, total_time_ns NS); + } + else + tsd_append("All loops in group %d are assigned.", i); + + UNLOCK_DOMAIN(attrs, group->domain); + } + + if (!tsd->show_loops) + cli_printf(tsd->cli, -1027, "Thread ID Working Overhead Last Pickup/Drop"); + + for (uint i = 0; i < tsd->line_pos - 1; i++) + cli_printf(tsd->cli, -1027, "%s", tsd->lines[i]); + + cli_printf(tsd->cli, 1027, "%s", tsd->lines[tsd->line_pos-1]); + cli_write_trigger(tsd->cli); + mb_free(tsd); +} + +void +cmd_show_threads(int show_loops) +{ + struct bird_thread_show_data *tsd = mb_allocz(&root_pool, sizeof(struct bird_thread_show_data)); + tsd->cli = this_cli; + tsd->show_loops = show_loops; + tsd->line_pos = 0; + tsd->line_max = 64; + + this_cli->cont = bird_thread_show_cli_cont; + this_cli->cleanup = bird_thread_show_cli_cleanup; + + bird_thread_sync_all(&tsd->sync, bird_thread_show, cmd_show_threads_done, "Show Threads"); +} diff --git a/sysdep/unix/io-loop.c b/sysdep/unix/io-loop.c index a45813940..438373a70 100644 --- a/sysdep/unix/io-loop.c +++ b/sysdep/unix/io-loop.c @@ -28,7 +28,6 @@ #include "lib/io-loop.h" #include "sysdep/unix/io-loop.h" #include "conf/conf.h" -#include "nest/cli.h" #define THREAD_STACK_SIZE 65536 /* To be lowered in near future */ @@ -54,8 +53,6 @@ static void ns_init(void) bug("clock_gettime: %m"); } -#define NSEC_IN_SEC ((u64) (1000 * 1000 * 1000)) - u64 ns_now(void) { struct timespec ts; @@ -65,9 +62,6 @@ u64 ns_now(void) return (u64) (ts.tv_sec - ns_begin.tv_sec) * NSEC_IN_SEC + ts.tv_nsec - ns_begin.tv_nsec; } -#define NSEC_TO_SEC(x) ((x) / NSEC_IN_SEC) -#define CURRENT_SEC NSEC_TO_SEC(ns_now()) - static _Thread_local struct spent_time *account_target_spent_time; static _Thread_local u64 *account_target_total; static _Thread_local u64 account_last; @@ -571,17 +565,7 @@ sockets_fire(struct birdloop *loop, bool read, bool write) static void bird_thread_start_event(void *_data); static void bird_thread_busy_set(struct bird_thread *thr, int val); -struct birdloop_pickup_group { - DOMAIN(attrs) domain; - list loops; - list threads; - uint thread_count; - uint thread_busy_count; - uint loop_count; - uint loop_unassigned_count; - btime max_latency; - event start_threads; -} pickup_groups[2] = { +struct birdloop_pickup_group pickup_groups[2] = { { /* all zeroes */ }, @@ -593,7 +577,7 @@ struct birdloop_pickup_group { }, }; -static _Thread_local struct bird_thread *this_thread; +_Thread_local struct bird_thread *this_thread; static void birdloop_set_thread(struct birdloop *loop, struct bird_thread *thr, struct birdloop_pickup_group *group) @@ -1235,170 +1219,6 @@ bird_thread_sync_all(struct bird_thread_syncer *sync, } -struct bird_thread_show_data { - struct bird_thread_syncer sync; - cli *cli; - linpool *lp; - u8 show_loops; - uint line_pos; - uint line_max; - const char **lines; -}; - -#define tsd_append(...) do { \ - if (!tsd->lines) \ - tsd->lines = mb_allocz(tsd->sync.pool, sizeof(const char *) * tsd->line_max); \ - if (tsd->line_pos >= tsd->line_max) \ - tsd->lines = mb_realloc(tsd->lines, sizeof (const char *) * (tsd->line_max *= 2)); \ - tsd->lines[tsd->line_pos++] = lp_sprintf(tsd->lp, __VA_ARGS__); \ -} while (0) - -static void -bird_thread_show_cli_cont(struct cli *c UNUSED) -{ - /* Explicitly do nothing to prevent CLI from trying to parse another command. */ -} - -static bool -bird_thread_show_cli_cleanup(struct cli *c UNUSED) -{ - /* Defer the cleanup until the writeout is finished. */ - return false; -} - -static void -bird_thread_show_spent_time(struct bird_thread_show_data *tsd, const char *name, struct spent_time *st) -{ - char b[TIME_BY_SEC_SIZE * sizeof("1234567890, ")], *bptr = b, *bend = b + sizeof(b); - uint cs = CURRENT_SEC; - uint fs = NSEC_TO_SEC(st->last_written_ns); - - for (uint i = 0; i <= cs && i < TIME_BY_SEC_SIZE; i++) - bptr += bsnprintf(bptr, bend - bptr, "% 10lu ", - (cs - i > fs) ? 0 : st->by_sec_ns[(cs - i) % TIME_BY_SEC_SIZE]); - bptr[-1] = 0; /* Drop the trailing space */ - - tsd_append(" %s total time: % 9t s; last %d secs [ns]: %s", name, st->total_ns NS, MIN(CURRENT_SEC+1, TIME_BY_SEC_SIZE), b); -} - -static void -bird_thread_show_loop(struct bird_thread_show_data *tsd, struct birdloop *loop) -{ - tsd_append(" Loop %s", domain_name(loop->time.domain)); - bird_thread_show_spent_time(tsd, "Working ", &loop->working); - bird_thread_show_spent_time(tsd, "Locking ", &loop->locking); -} - -static void -bird_thread_show(struct bird_thread_syncer *sync) -{ - SKIP_BACK_DECLARE(struct bird_thread_show_data, tsd, sync, sync); - - if (!tsd->lp) - tsd->lp = lp_new(tsd->sync.pool); - - if (tsd->show_loops) - tsd_append("Thread %04x %s (busy counter %d)", THIS_THREAD_ID, this_thread->busy_active ? " [busy]" : "", this_thread->busy_counter); - - u64 total_time_ns = 0; - struct birdloop *loop; - WALK_LIST(loop, this_thread->loops) - { - if (tsd->show_loops) - bird_thread_show_loop(tsd, loop); - - total_time_ns += loop->working.total_ns + loop->locking.total_ns; - } - - if (tsd->show_loops) - { - tsd_append(" Total working time: %t", total_time_ns NS); - bird_thread_show_spent_time(tsd, "Overhead", &this_thread->overhead); - bird_thread_show_spent_time(tsd, "Idle ", &this_thread->idle); - } - else - tsd_append("%04x%s % 9.3t s % 9.3t s % 9.3t s", - THIS_THREAD_ID, this_thread->busy_active ? " [busy]" : " ", - total_time_ns NS, this_thread->overhead.total_ns NS, - (ns_now() - this_thread->meta->last_transition_ns) NS); -} - -static void -cmd_show_threads_done(struct bird_thread_syncer *sync) -{ - SKIP_BACK_DECLARE(struct bird_thread_show_data, tsd, sync, sync); - ASSERT_DIE(birdloop_inside(&main_birdloop)); - - /* The client lost their patience and dropped the session early. */ - if (!tsd->cli->sock) - { - mb_free(tsd); - rp_free(tsd->cli->pool); - return; - } - - tsd->cli->cont = NULL; - tsd->cli->cleanup = NULL; - - for (int i=0; i<2; i++) - { - struct birdloop_pickup_group *group = &pickup_groups[i]; - - LOCK_DOMAIN(attrs, group->domain); - uint count = 0; - u64 total_time_ns = 0; - if (!EMPTY_LIST(group->loops)) - { - if (tsd->show_loops) - tsd_append("Unassigned loops in group %d:", i); - - struct birdloop *loop; - WALK_LIST(loop, group->loops) - { - if (tsd->show_loops) - bird_thread_show_loop(tsd, loop); - - total_time_ns += loop->working.total_ns + loop->locking.total_ns; - count++; - } - - if (tsd->show_loops) - tsd_append(" Total working time: %t", total_time_ns NS); - else - tsd_append("Unassigned %d loops in group %d, total time %t", count, i, total_time_ns NS); - } - else - tsd_append("All loops in group %d are assigned.", i); - - UNLOCK_DOMAIN(attrs, group->domain); - } - - if (!tsd->show_loops) - cli_printf(tsd->cli, -1027, "Thread ID Working Overhead Last Pickup/Drop"); - - for (uint i = 0; i < tsd->line_pos - 1; i++) - cli_printf(tsd->cli, -1027, "%s", tsd->lines[i]); - - cli_printf(tsd->cli, 1027, "%s", tsd->lines[tsd->line_pos-1]); - cli_write_trigger(tsd->cli); - mb_free(tsd); -} - -void -cmd_show_threads(int show_loops) -{ - struct bird_thread_show_data *tsd = mb_allocz(&root_pool, sizeof(struct bird_thread_show_data)); - tsd->cli = this_cli; - tsd->show_loops = show_loops; - tsd->line_pos = 0; - tsd->line_max = 64; - - this_cli->cont = bird_thread_show_cli_cont; - this_cli->cleanup = bird_thread_show_cli_cleanup; - - bird_thread_sync_all(&tsd->sync, bird_thread_show, cmd_show_threads_done, "Show Threads"); -} - bool task_still_in_limit(void) { static u64 main_counter = 0; diff --git a/sysdep/unix/io-loop.h b/sysdep/unix/io-loop.h index f7fde411b..a017244c1 100644 --- a/sysdep/unix/io-loop.h +++ b/sysdep/unix/io-loop.h @@ -103,6 +103,7 @@ struct bird_thread struct spent_time overhead, idle; }; +extern _Thread_local struct bird_thread *this_thread; struct bird_thread_syncer { pool *pool; @@ -117,4 +118,18 @@ void bird_thread_sync_all(struct bird_thread_syncer *sync, void (*hook)(struct bird_thread_syncer *), void (*done)(struct bird_thread_syncer *), const char *name); +struct birdloop_pickup_group { + DOMAIN(attrs) domain; + list loops; + list threads; + uint thread_count; + uint thread_busy_count; + uint loop_count; + uint loop_unassigned_count; + btime max_latency; + event start_threads; +}; + +extern struct birdloop_pickup_group pickup_groups[2]; + #endif