diff --git a/src/tools/pw-top.c b/src/tools/pw-top.c index bc9fbb730..b430244bf 100644 --- a/src/tools/pw-top.c +++ b/src/tools/pw-top.c @@ -82,6 +82,9 @@ struct data { unsigned pending_refresh:1; WINDOW *win; + + unsigned int batch_mode:1; + int iterations; }; struct point { @@ -89,6 +92,22 @@ struct point { struct driver info; }; +static SPA_PRINTF_FUNC(4, 5) void print_mode_dependent(struct data *d, int y, int x, const char *fmt, ...) +{ + va_list argp; + if (!d->batch_mode) + mvwprintw(d->win, y, x, "%s", ""); + + va_start(argp, fmt); + if (d->batch_mode) { + vprintf(fmt, argp); + printf("\n"); + } else + vw_printw(d->win, fmt, argp); + va_end(argp); +} + + static int process_info(struct data *d, const struct spa_pod *pod, struct driver *info) { return spa_pod_parse_struct(pod, @@ -144,7 +163,7 @@ static const struct pw_proxy_events proxy_events = { .destroy = on_node_destroy, }; -static void do_refresh(struct data *d); +static void do_refresh(struct data *d, bool force_refresh); static void node_info(void *data, const struct pw_node_info *info) { @@ -152,7 +171,7 @@ static void node_info(void *data, const struct pw_node_info *info) if (n->state != info->state) { n->state = info->state; - do_refresh(n->data); + do_refresh(n->data, !n->data->batch_mode); } } @@ -259,7 +278,7 @@ static void node_param(void *data, int seq, break; } done: - do_refresh(n->data); + do_refresh(n->data, !n->data->batch_mode); } static const struct pw_node_events node_events = { @@ -296,7 +315,8 @@ static struct node *add_node(struct data *d, uint32_t id, const char *name) } spa_list_append(&d->node_list, &n->link); d->n_nodes++; - d->pending_refresh = true; + if (!d->batch_mode) + d->pending_refresh = true; return n; } @@ -307,7 +327,8 @@ static void remove_node(struct data *d, struct node *n) pw_proxy_destroy(n->proxy); spa_list_remove(&n->link); d->n_nodes--; - d->pending_refresh = true; + if (!d->batch_mode) + d->pending_refresh = true; free(n); } @@ -462,7 +483,7 @@ static void print_node(struct data *d, struct driver *i, struct node *n, int y) else busy = -1; - mvwprintw(d->win, y, 0, "%s %4.1u %6.1u %6.1u %s %s %s %s %3.1u %16.16s %s%s", + print_mode_dependent(d, y, 0, "%s %4.1u %6.1u %6.1u %s %s %s %s %3.1u %16.16s %s%s", state_as_string(n->state), n->id, frac.num, frac.denom, @@ -484,23 +505,31 @@ static void clear_node(struct node *n) spa_zero(n->info); } -static void do_refresh(struct data *d) +#define HEADER "S ID QUANT RATE WAIT BUSY W/Q B/Q ERR FORMAT NAME " + +static void do_refresh(struct data *d, bool force_refresh) { struct node *n, *t, *f; int y = 1; - wclear(d->win); - wattron(d->win, A_REVERSE); - wprintw(d->win, "%-*.*s", COLS, COLS, "S ID QUANT RATE WAIT BUSY W/Q B/Q ERR FORMAT NAME "); - wattroff(d->win, A_REVERSE); - wprintw(d->win, "\n"); + if (!d->pending_refresh && !force_refresh) + return; + + if (!d->batch_mode) { + wclear(d->win); + wattron(d->win, A_REVERSE); + wprintw(d->win, "%-*.*s", COLS, COLS, HEADER); + wattroff(d->win, A_REVERSE); + wprintw(d->win, "\n"); + } else + printf(HEADER "\n"); spa_list_for_each_safe(n, t, &d->node_list, link) { if (n->driver != n) continue; print_node(d, &n->info, n, y++); - if(y > LINES) + if(!d->batch_mode && y > LINES) break; spa_list_for_each(f, &d->node_list, link) { @@ -517,19 +546,28 @@ static void do_refresh(struct data *d) } } - // Clear from last line to the end of the window to hide text wrapping from the last node - wmove(d->win, y, 0); - wclrtobot(d->win); + if (!d->batch_mode) { + // Clear from last line to the end of the window to hide text wrapping from the last node + wmove(d->win, y, 0); + wclrtobot(d->win); + + wrefresh(d->win); + } - wrefresh(d->win); d->pending_refresh = false; + + if (d->iterations > 0) + d->iterations--; + + if (d->iterations == 0) + pw_main_loop_quit(d->loop); } static void do_timeout(void *data, uint64_t expirations) { struct data *d = data; d->generation++; - do_refresh(d); + do_refresh(d, true); } static void profiler_profile(void *data, const struct spa_pod *pod) @@ -568,8 +606,8 @@ static void profiler_profile(void *data, const struct spa_pod *pod) if (res < 0) continue; } - if (d->pending_refresh) - do_refresh(d); + + do_refresh(d, false); } static const struct pw_profiler_events profiler_events = { @@ -608,8 +646,8 @@ static void registry_event_global(void *data, uint32_t id, d->profiler = proxy; pw_proxy_add_object_listener(proxy, &d->profiler_listener, &profiler_events, d); } - if (d->pending_refresh) - do_refresh(d); + + do_refresh(d, false); return; error_proxy: @@ -623,8 +661,8 @@ static void registry_event_global_remove(void *data, uint32_t id) struct node *n; if ((n = find_node(d, id)) != NULL) remove_node(d, n); - if (d->pending_refresh) - do_refresh(d); + + do_refresh(d, false); } static const struct pw_registry_events registry_events = { @@ -662,7 +700,7 @@ static void on_core_done(void *_data, uint32_t id, int seq) pw_log_error("no Profiler Interface found, please load one in the server"); pw_main_loop_quit(d->loop); } else { - do_refresh(d); + do_refresh(d, true); } } } @@ -683,6 +721,8 @@ static void show_help(const char *name, bool error) { fprintf(error ? stderr : stdout, "Usage:\n%s [options]\n\n" "Options:\n" + " -b, --batch-mode run in non-interactive batch_mode mode\n" + " -n, --iterations = NUMBER exit on maximum iterations NUMBER\n" " -r, --remote Remote daemon name\n" "\n" " -h, --help Show this help\n" @@ -715,7 +755,7 @@ static void do_handle_io(void *data, int fd, uint32_t mask) pw_main_loop_quit(d->loop); break; default: - do_refresh(d); + do_refresh(d, !d->batch_mode); break; } } @@ -727,9 +767,11 @@ int main(int argc, char *argv[]) struct pw_loop *l; const char *opt_remote = NULL; static const struct option long_options[] = { + { "batch-mode", no_argument, NULL, 'b' }, + { "iterations", required_argument, NULL, 'n' }, + { "remote", required_argument, NULL, 'r' }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, - { "remote", required_argument, NULL, 'r' }, { NULL, 0, NULL, 0} }; int c; @@ -739,9 +781,11 @@ int main(int argc, char *argv[]) setlocale(LC_ALL, ""); pw_init(&argc, &argv); + data.iterations = -1; + spa_list_init(&data.node_list); - while ((c = getopt_long(argc, argv, "hVr:o:", long_options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "hVr:o:bn:", long_options, NULL)) != -1) { switch (c) { case 'h': show_help(argv[0], false); @@ -757,6 +801,12 @@ int main(int argc, char *argv[]) case 'r': opt_remote = optarg; break; + case 'b': + data.batch_mode = 1; + break; + case 'n': + spa_atoi32(optarg, &data.iterations, 10); + break; default: show_help(argv[0], true); return -1; @@ -769,6 +819,9 @@ int main(int argc, char *argv[]) return -1; } + if (!data.batch_mode) + data.iterations = -1; + l = pw_main_loop_get_loop(data.loop); pw_loop_add_signal(l, SIGINT, do_quit, &data); pw_loop_add_signal(l, SIGTERM, do_quit, &data); @@ -802,9 +855,10 @@ int main(int argc, char *argv[]) data.check_profiler = pw_core_sync(data.core, 0, 0); - terminal_start(); - - data.win = newwin(LINES, COLS, 0, 0); + if (!data.batch_mode) { + terminal_start(); + data.win = newwin(LINES, COLS, 0, 0); + } data.timer = pw_loop_add_timer(l, do_timeout, &data); value.tv_sec = 1; @@ -813,15 +867,16 @@ int main(int argc, char *argv[]) interval.tv_nsec = 0; pw_loop_update_timer(l, data.timer, &value, &interval, false); - pw_loop_add_io(l, fileno(stdin), SPA_IO_IN, false, do_handle_io, &data); + if (!data.batch_mode) + pw_loop_add_io(l, fileno(stdin), SPA_IO_IN, false, do_handle_io, &data); pw_main_loop_run(data.loop); - terminal_stop(); + if (!data.batch_mode) + terminal_stop(); spa_list_consume(n, &data.node_list, link) remove_node(&data, n); - if (data.profiler) { spa_hook_remove(&data.profiler_listener); pw_proxy_destroy((struct pw_proxy*)data.profiler);