]> Pileus Git - ~andy/linux/blobdiff - tools/perf/builtin-top.c
perf diff: Improve the help text
[~andy/linux] / tools / perf / builtin-top.c
index 89b7f68a1799ee8f45c5e601d9ae8fd1f33e6763..296e809c2538a7bc333dd82b2082d285629c0331 100644 (file)
@@ -20,8 +20,9 @@
 
 #include "perf.h"
 
-#include "util/symbol.h"
 #include "util/color.h"
+#include "util/session.h"
+#include "util/symbol.h"
 #include "util/thread.h"
 #include "util/util.h"
 #include <linux/rbtree.h>
@@ -78,6 +79,8 @@ static int                    dump_symtab                     =      0;
 
 static bool                    hide_kernel_symbols             =  false;
 static bool                    hide_user_symbols               =  false;
+static struct winsize          winsize;
+static struct symbol_conf      symbol_conf;
 
 /*
  * Source
@@ -100,58 +103,75 @@ static int                        display_weighted                =     -1;
  * Symbols
  */
 
+struct sym_entry_source {
+       struct source_line      *source;
+       struct source_line      *lines;
+       struct source_line      **lines_tail;
+       pthread_mutex_t         lock;
+};
+
 struct sym_entry {
        struct rb_node          rb_node;
        struct list_head        node;
-       unsigned long           count[MAX_COUNTERS];
        unsigned long           snap_count;
        double                  weight;
        int                     skip;
+       u16                     name_len;
        u8                      origin;
        struct map              *map;
-       struct source_line      *source;
-       struct source_line      *lines;
-       struct source_line      **lines_tail;
-       pthread_mutex_t         source_lock;
+       struct sym_entry_source *src;
+       unsigned long           count[0];
 };
 
 /*
  * Source functions
  */
 
-/* most GUI terminals set LINES (although some don't export it) */
-static int term_rows(void)
+static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
 {
-       char *lines_string = getenv("LINES");
-       int n_lines;
+       return ((void *)self) + symbol_conf.priv_size;
+}
 
-       if (lines_string && (n_lines = atoi(lines_string)) > 0)
-               return n_lines;
-#ifdef TIOCGWINSZ
-       else {
-               struct winsize ws;
-               if (!ioctl(1, TIOCGWINSZ, &ws) && ws.ws_row)
-                       return ws.ws_row;
+static void get_term_dimensions(struct winsize *ws)
+{
+       char *s = getenv("LINES");
+
+       if (s != NULL) {
+               ws->ws_row = atoi(s);
+               s = getenv("COLUMNS");
+               if (s != NULL) {
+                       ws->ws_col = atoi(s);
+                       if (ws->ws_row && ws->ws_col)
+                               return;
+               }
        }
+#ifdef TIOCGWINSZ
+       if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
+           ws->ws_row && ws->ws_col)
+               return;
 #endif
-       return 25;
+       ws->ws_row = 25;
+       ws->ws_col = 80;
 }
 
-static void update_print_entries(void)
+static void update_print_entries(struct winsize *ws)
 {
-       print_entries = term_rows();
+       print_entries = ws->ws_row;
+
        if (print_entries > 9)
                print_entries -= 9;
 }
 
 static void sig_winch_handler(int sig __used)
 {
-       update_print_entries();
+       get_term_dimensions(&winsize);
+       update_print_entries(&winsize);
 }
 
 static void parse_source(struct sym_entry *syme)
 {
        struct symbol *sym;
+       struct sym_entry_source *source;
        struct map *map;
        FILE *file;
        char command[PATH_MAX*2];
@@ -161,12 +181,21 @@ static void parse_source(struct sym_entry *syme)
        if (!syme)
                return;
 
-       if (syme->lines) {
-               pthread_mutex_lock(&syme->source_lock);
+       if (syme->src == NULL) {
+               syme->src = zalloc(sizeof(*source));
+               if (syme->src == NULL)
+                       return;
+               pthread_mutex_init(&syme->src->lock, NULL);
+       }
+
+       source = syme->src;
+
+       if (source->lines) {
+               pthread_mutex_lock(&source->lock);
                goto out_assign;
        }
 
-       sym = (struct symbol *)(syme + 1);
+       sym = sym_entry__symbol(syme);
        map = syme->map;
        path = map->dso->long_name;
 
@@ -182,8 +211,8 @@ static void parse_source(struct sym_entry *syme)
        if (!file)
                return;
 
-       pthread_mutex_lock(&syme->source_lock);
-       syme->lines_tail = &syme->lines;
+       pthread_mutex_lock(&source->lock);
+       source->lines_tail = &source->lines;
        while (!feof(file)) {
                struct source_line *src;
                size_t dummy = 0;
@@ -203,8 +232,8 @@ static void parse_source(struct sym_entry *syme)
                        *c = 0;
 
                src->next = NULL;
-               *syme->lines_tail = src;
-               syme->lines_tail = &src->next;
+               *source->lines_tail = src;
+               source->lines_tail = &src->next;
 
                if (strlen(src->line)>8 && src->line[8] == ':') {
                        src->eip = strtoull(src->line, NULL, 16);
@@ -218,7 +247,7 @@ static void parse_source(struct sym_entry *syme)
        pclose(file);
 out_assign:
        sym_filter_entry = syme;
-       pthread_mutex_unlock(&syme->source_lock);
+       pthread_mutex_unlock(&source->lock);
 }
 
 static void __zero_source_counters(struct sym_entry *syme)
@@ -226,7 +255,7 @@ static void __zero_source_counters(struct sym_entry *syme)
        int i;
        struct source_line *line;
 
-       line = syme->lines;
+       line = syme->src->lines;
        while (line) {
                for (i = 0; i < nr_counters; i++)
                        line->count[i] = 0;
@@ -241,13 +270,13 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
        if (syme != sym_filter_entry)
                return;
 
-       if (pthread_mutex_trylock(&syme->source_lock))
+       if (pthread_mutex_trylock(&syme->src->lock))
                return;
 
-       if (!syme->source)
+       if (syme->src == NULL || syme->src->source == NULL)
                goto out_unlock;
 
-       for (line = syme->lines; line; line = line->next) {
+       for (line = syme->src->lines; line; line = line->next) {
                if (line->eip == ip) {
                        line->count[counter]++;
                        break;
@@ -256,25 +285,25 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
                        break;
        }
 out_unlock:
-       pthread_mutex_unlock(&syme->source_lock);
+       pthread_mutex_unlock(&syme->src->lock);
 }
 
 static void lookup_sym_source(struct sym_entry *syme)
 {
-       struct symbol *symbol = (struct symbol *)(syme + 1);
+       struct symbol *symbol = sym_entry__symbol(syme);
        struct source_line *line;
        char pattern[PATH_MAX];
 
        sprintf(pattern, "<%s>:", symbol->name);
 
-       pthread_mutex_lock(&syme->source_lock);
-       for (line = syme->lines; line; line = line->next) {
+       pthread_mutex_lock(&syme->src->lock);
+       for (line = syme->src->lines; line; line = line->next) {
                if (strstr(line->line, pattern)) {
-                       syme->source = line;
+                       syme->src->source = line;
                        break;
                }
        }
-       pthread_mutex_unlock(&syme->source_lock);
+       pthread_mutex_unlock(&syme->src->lock);
 }
 
 static void show_lines(struct source_line *queue, int count, int total)
@@ -304,24 +333,24 @@ static void show_details(struct sym_entry *syme)
        if (!syme)
                return;
 
-       if (!syme->source)
+       if (!syme->src->source)
                lookup_sym_source(syme);
 
-       if (!syme->source)
+       if (!syme->src->source)
                return;
 
-       symbol = (struct symbol *)(syme + 1);
+       symbol = sym_entry__symbol(syme);
        printf("Showing %s for %s\n", event_name(sym_counter), symbol->name);
        printf("  Events  Pcnt (>=%d%%)\n", sym_pcnt_filter);
 
-       pthread_mutex_lock(&syme->source_lock);
-       line = syme->source;
+       pthread_mutex_lock(&syme->src->lock);
+       line = syme->src->source;
        while (line) {
                total += line->count[sym_counter];
                line = line->next;
        }
 
-       line = syme->source;
+       line = syme->src->source;
        while (line) {
                float pcnt = 0.0;
 
@@ -346,7 +375,7 @@ static void show_details(struct sym_entry *syme)
                line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8;
                line = line->next;
        }
-       pthread_mutex_unlock(&syme->source_lock);
+       pthread_mutex_unlock(&syme->src->lock);
        if (more)
                printf("%d lines not displayed, maybe increase display entries [e]\n", more);
 }
@@ -423,6 +452,8 @@ static void print_sym_table(void)
        struct sym_entry *syme, *n;
        struct rb_root tmp = RB_ROOT;
        struct rb_node *nd;
+       int sym_width = 0, dso_width = 0, max_dso_width;
+       const int win_width = winsize.ws_col - 1;
 
        samples = userspace_samples = 0;
 
@@ -434,6 +465,7 @@ static void print_sym_table(void)
        list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
                syme->snap_count = syme->count[snap];
                if (syme->snap_count != 0) {
+
                        if ((hide_user_symbols &&
                             syme->origin == PERF_RECORD_MISC_USER) ||
                            (hide_kernel_symbols &&
@@ -453,8 +485,7 @@ static void print_sym_table(void)
 
        puts(CONSOLE_CLEAR);
 
-       printf(
-"------------------------------------------------------------------------------\n");
+       printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
        printf( "   PerfTop:%8.0f irqs/sec  kernel:%4.1f%% [",
                samples_per_sec,
                100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec)));
@@ -492,13 +523,35 @@ static void print_sym_table(void)
                        printf(", %d CPUs)\n", nr_cpus);
        }
 
-       printf("------------------------------------------------------------------------------\n\n");
+       printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
 
        if (sym_filter_entry) {
                show_details(sym_filter_entry);
                return;
        }
 
+       /*
+        * Find the longest symbol name that will be displayed
+        */
+       for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
+               syme = rb_entry(nd, struct sym_entry, rb_node);
+               if (++printed > print_entries ||
+                   (int)syme->snap_count < count_filter)
+                       continue;
+
+               if (syme->map->dso->long_name_len > dso_width)
+                       dso_width = syme->map->dso->long_name_len;
+
+               if (syme->name_len > sym_width)
+                       sym_width = syme->name_len;
+       }
+
+       printed = 0;
+
+       max_dso_width = winsize.ws_col - sym_width - 29;
+       if (dso_width > max_dso_width)
+               dso_width = max_dso_width;
+       putchar('\n');
        if (nr_counters == 1)
                printf("             samples  pcnt");
        else
@@ -506,19 +559,21 @@ static void print_sym_table(void)
 
        if (verbose)
                printf("         RIP       ");
-       printf(" function                                 DSO\n");
+       printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
        printf("   %s    _______ _____",
               nr_counters == 1 ? "      " : "______");
        if (verbose)
                printf(" ________________");
-       printf(" ________________________________ ________________\n\n");
+       printf(" %-*.*s", sym_width, sym_width, graph_line);
+       printf(" %-*.*s", dso_width, dso_width, graph_line);
+       puts("\n");
 
        for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
                struct symbol *sym;
                double pcnt;
 
                syme = rb_entry(nd, struct sym_entry, rb_node);
-               sym = (struct symbol *)(syme + 1);
+               sym = sym_entry__symbol(syme);
 
                if (++printed > print_entries || (int)syme->snap_count < count_filter)
                        continue;
@@ -534,9 +589,11 @@ static void print_sym_table(void)
                percent_color_fprintf(stdout, "%4.1f%%", pcnt);
                if (verbose)
                        printf(" %016llx", sym->start);
-               printf(" %-32s", sym->name);
-               printf(" %s", syme->map->dso->short_name);
-               printf("\n");
+               printf(" %-*.*s", sym_width, sym_width, sym->name);
+               printf(" %-*.*s\n", dso_width, dso_width,
+                      dso_width >= syme->map->dso->long_name_len ?
+                                       syme->map->dso->long_name :
+                                       syme->map->dso->short_name);
        }
 }
 
@@ -583,10 +640,10 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
 
        /* zero counters of active symbol */
        if (syme) {
-               pthread_mutex_lock(&syme->source_lock);
+               pthread_mutex_lock(&syme->src->lock);
                __zero_source_counters(syme);
                *target = NULL;
-               pthread_mutex_unlock(&syme->source_lock);
+               pthread_mutex_unlock(&syme->src->lock);
        }
 
        fprintf(stdout, "\n%s: ", msg);
@@ -602,7 +659,7 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
        pthread_mutex_unlock(&active_symbols_lock);
 
        list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
-               struct symbol *sym = (struct symbol *)(syme + 1);
+               struct symbol *sym = sym_entry__symbol(syme);
 
                if (!strcmp(buf, sym->name)) {
                        found = syme;
@@ -626,7 +683,7 @@ static void print_mapped_keys(void)
        char *name = NULL;
 
        if (sym_filter_entry) {
-               struct symbol *sym = (struct symbol *)(sym_filter_entry+1);
+               struct symbol *sym = sym_entry__symbol(sym_filter_entry);
                name = sym->name;
        }
 
@@ -639,7 +696,7 @@ static void print_mapped_keys(void)
 
        fprintf(stdout, "\t[f]     profile display filter (count).    \t(%d)\n", count_filter);
 
-       if (vmlinux_name) {
+       if (symbol_conf.vmlinux_name) {
                fprintf(stdout, "\t[F]     annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter);
                fprintf(stdout, "\t[s]     annotate symbol.                   \t(%s)\n", name?: "NULL");
                fprintf(stdout, "\t[S]     stop annotation.\n");
@@ -676,7 +733,7 @@ static int key_mapped(int c)
                case 'F':
                case 's':
                case 'S':
-                       return vmlinux_name ? 1 : 0;
+                       return symbol_conf.vmlinux_name ? 1 : 0;
                default:
                        break;
        }
@@ -718,7 +775,7 @@ static void handle_keypress(int c)
                case 'e':
                        prompt_integer(&print_entries, "Enter display entries (lines)");
                        if (print_entries == 0) {
-                               update_print_entries();
+                               sig_winch_handler(SIGWINCH);
                                signal(SIGWINCH, sig_winch_handler);
                        } else
                                signal(SIGWINCH, SIG_DFL);
@@ -752,6 +809,8 @@ static void handle_keypress(int c)
                case 'q':
                case 'Q':
                        printf("exiting.\n");
+                       if (dump_symtab)
+                               dsos__fprintf(stderr);
                        exit(0);
                case 's':
                        prompt_symbol(&sym_filter_entry, "Enter details symbol");
@@ -762,10 +821,10 @@ static void handle_keypress(int c)
                        else {
                                struct sym_entry *syme = sym_filter_entry;
 
-                               pthread_mutex_lock(&syme->source_lock);
+                               pthread_mutex_lock(&syme->src->lock);
                                sym_filter_entry = NULL;
                                __zero_source_counters(syme);
-                               pthread_mutex_unlock(&syme->source_lock);
+                               pthread_mutex_unlock(&syme->src->lock);
                        }
                        break;
                case 'U':
@@ -851,7 +910,7 @@ static int symbol_filter(struct map *map, struct symbol *sym)
 
        syme = symbol__priv(sym);
        syme->map = map;
-       pthread_mutex_init(&syme->source_lock, NULL);
+       syme->src = NULL;
        if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter))
                sym_filter_entry = syme;
 
@@ -862,72 +921,38 @@ static int symbol_filter(struct map *map, struct symbol *sym)
                }
        }
 
-       return 0;
-}
-
-static int parse_symbols(void)
-{
-       if (dsos__load_kernel(vmlinux_name, symbol_filter, 1) <= 0)
-               return -1;
-
-       if (dump_symtab)
-               dsos__fprintf(stderr);
+       if (!syme->skip)
+               syme->name_len = strlen(sym->name);
 
        return 0;
 }
 
-static void event__process_sample(const event_t *self, int counter)
+static void event__process_sample(const event_t *self,
+                                struct perf_session *session, int counter)
 {
        u64 ip = self->ip.ip;
-       struct map *map;
        struct sym_entry *syme;
-       struct symbol *sym;
+       struct addr_location al;
        u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
 
        switch (origin) {
-       case PERF_RECORD_MISC_USER: {
-               struct thread *thread;
-
+       case PERF_RECORD_MISC_USER:
                if (hide_user_symbols)
                        return;
-
-               thread = threads__findnew(self->ip.pid);
-               if (thread == NULL)
-                       return;
-
-               map = thread__find_map(thread, ip);
-               if (map != NULL) {
-                       ip = map->map_ip(map, ip);
-                       sym = map__find_symbol(map, ip, symbol_filter);
-                       if (sym == NULL)
-                               return;
-                       userspace_samples++;
-                       break;
-               }
-       }
-               /*
-                * If this is outside of all known maps,
-                * and is a negative address, try to look it
-                * up in the kernel dso, as it might be a
-                * vsyscall or vdso (which executes in user-mode).
-                */
-               if ((long long)ip >= 0)
-                       return;
-               /* Fall thru */
+               break;
        case PERF_RECORD_MISC_KERNEL:
                if (hide_kernel_symbols)
                        return;
-
-               sym = kernel_maps__find_symbol(ip, &map);
-               if (sym == NULL)
-                       return;
                break;
        default:
                return;
        }
 
-       syme = symbol__priv(sym);
+       if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 ||
+           al.sym == NULL)
+               return;
 
+       syme = symbol__priv(al.sym);
        if (!syme->skip) {
                syme->count[counter]++;
                syme->origin = origin;
@@ -936,38 +961,20 @@ static void event__process_sample(const event_t *self, int counter)
                if (list_empty(&syme->node) || !syme->node.next)
                        __list_insert_active_sym(syme);
                pthread_mutex_unlock(&active_symbols_lock);
+               if (origin == PERF_RECORD_MISC_USER)
+                       ++userspace_samples;
                ++samples;
-               return;
-       }
-}
-
-static void event__process_mmap(event_t *self)
-{
-       struct thread *thread = threads__findnew(self->mmap.pid);
-
-       if (thread != NULL) {
-               struct map *map = map__new(&self->mmap, NULL, 0);
-               if (map != NULL)
-                       thread__insert_map(thread, map);
        }
 }
 
-static void event__process_comm(event_t *self)
-{
-       struct thread *thread = threads__findnew(self->comm.pid);
-
-       if (thread != NULL)
-               thread__set_comm(thread, self->comm.comm);
-}
-
-static int event__process(event_t *event)
+static int event__process(event_t *event, struct perf_session *session)
 {
        switch (event->header.type) {
        case PERF_RECORD_COMM:
-               event__process_comm(event);
+               event__process_comm(event, session);
                break;
        case PERF_RECORD_MMAP:
-               event__process_mmap(event);
+               event__process_mmap(event, session);
                break;
        default:
                break;
@@ -994,7 +1001,8 @@ static unsigned int mmap_read_head(struct mmap_data *md)
        return head;
 }
 
-static void mmap_read_counter(struct mmap_data *md)
+static void perf_session__mmap_read_counter(struct perf_session *self,
+                                           struct mmap_data *md)
 {
        unsigned int head = mmap_read_head(md);
        unsigned int old = md->prev;
@@ -1047,9 +1055,9 @@ static void mmap_read_counter(struct mmap_data *md)
                }
 
                if (event->header.type == PERF_RECORD_SAMPLE)
-                       event__process_sample(event, md->counter);
+                       event__process_sample(event, self, md->counter);
                else
-                       event__process(event);
+                       event__process(event, self);
                old += size;
        }
 
@@ -1059,13 +1067,13 @@ static void mmap_read_counter(struct mmap_data *md)
 static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
 static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
 
-static void mmap_read(void)
+static void perf_session__mmap_read(struct perf_session *self)
 {
        int i, counter;
 
        for (i = 0; i < nr_cpus; i++) {
                for (counter = 0; counter < nr_counters; counter++)
-                       mmap_read_counter(&mmap_array[i][counter]);
+                       perf_session__mmap_read_counter(self, &mmap_array[i][counter]);
        }
 }
 
@@ -1150,11 +1158,19 @@ static int __cmd_top(void)
        pthread_t thread;
        int i, counter;
        int ret;
+       /*
+        * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
+        * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
+        */
+       struct perf_session *session = perf_session__new(NULL, O_WRONLY, false,
+                                                        &symbol_conf);
+       if (session == NULL)
+               return -ENOMEM;
 
        if (target_pid != -1)
-               event__synthesize_thread(target_pid, event__process);
+               event__synthesize_thread(target_pid, event__process, session);
        else
-               event__synthesize_threads(event__process);
+               event__synthesize_threads(event__process, session);
 
        for (i = 0; i < nr_cpus; i++) {
                group_fd = -1;
@@ -1165,7 +1181,7 @@ static int __cmd_top(void)
        /* Wait for a minimal set of events before starting the snapshot */
        poll(event_array, nr_poll, 100);
 
-       mmap_read();
+       perf_session__mmap_read(session);
 
        if (pthread_create(&thread, NULL, display_thread, NULL)) {
                printf("Could not create display thread.\n");
@@ -1185,7 +1201,7 @@ static int __cmd_top(void)
        while (1) {
                int hits = samples;
 
-               mmap_read();
+               perf_session__mmap_read(session);
 
                if (hits == samples)
                        ret = poll(event_array, nr_poll, 100);
@@ -1211,7 +1227,8 @@ static const struct option options[] = {
                            "system-wide collection from all CPUs"),
        OPT_INTEGER('C', "CPU", &profile_cpu,
                    "CPU to profile on"),
-       OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
+       OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
+                  "file", "vmlinux pathname"),
        OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols,
                    "hide kernel symbols"),
        OPT_INTEGER('m', "mmap-pages", &mmap_pages,
@@ -1247,8 +1264,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
 {
        int counter;
 
-       symbol__init(sizeof(struct sym_entry));
-
        page_size = sysconf(_SC_PAGE_SIZE);
 
        argc = parse_options(argc, argv, options, top_usage, 0);
@@ -1265,13 +1280,18 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
        if (!nr_counters)
                nr_counters = 1;
 
+       symbol_conf.priv_size = (sizeof(struct sym_entry) +
+                                (nr_counters + 1) * sizeof(unsigned long));
+       if (symbol_conf.vmlinux_name == NULL)
+               symbol_conf.try_vmlinux_path = true;
+       if (symbol__init(&symbol_conf) < 0)
+               return -1;
+
        if (delay_secs < 1)
                delay_secs = 1;
 
-       parse_symbols();
        parse_source(sym_filter_entry);
 
-
        /*
         * User specified count overrides default frequency.
         */
@@ -1301,8 +1321,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
        if (target_pid != -1 || profile_cpu != -1)
                nr_cpus = 1;
 
+       get_term_dimensions(&winsize);
        if (print_entries == 0) {
-               update_print_entries();
+               update_print_entries(&winsize);
                signal(SIGWINCH, sig_winch_handler);
        }