]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: debug/memstats: automatically determine first column size
authorWilly Tarreau <w@1wt.eu>
Tue, 9 Aug 2022 06:51:08 +0000 (08:51 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 9 Aug 2022 06:51:08 +0000 (08:51 +0200)
The first column's width may vary a lot depending on outputs, and it's
annoying to have large empty columns on small names and mangled large
columns that are not yet large enough. In order to overcome this, this
patch adds a width field to the memstats applet's context, and this
width is calculated the first time the function is entered, by estimating
the width of all lines that will be dumped. This is simple enough and
does the job well. If in the future some filtering criteria are added,
it will still be possible to perform a single pass on everything
depending on the desired output format.

src/debug.c

index 0431306885c5aa2ea050a0edb4363c86af7f57d7..090b82c40402cefc2fd1f8634096be915a446c87 100644 (file)
@@ -1229,6 +1229,7 @@ static int debug_iohandler_fd(struct appctx *appctx)
 struct dev_mem_ctx {
        struct mem_stats *start, *stop; /* begin/end of dump */
        int show_all;                   /* show all entries if non-null */
+       int width;
 };
 
 /* CLI parser for the "debug dev memstats" command. Sets a dev_mem_ctx shown above. */
@@ -1261,6 +1262,7 @@ static int debug_parse_cli_memstats(char **args, char *payload, struct appctx *a
        /* otherwise proceed with the dump from p0 to p1 */
        ctx->start = &__start_mem_stats;
        ctx->stop  = &__stop_mem_stats;
+       ctx->width = 0;
        return 0;
 }
 
@@ -1273,16 +1275,44 @@ static int debug_iohandler_memstats(struct appctx *appctx)
 {
        struct dev_mem_ctx *ctx = appctx->svcctx;
        struct stconn *sc = appctx_sc(appctx);
-       struct mem_stats *ptr = ctx->start;
+       struct mem_stats *ptr;
        int ret = 1;
 
        if (unlikely(sc_ic(sc)->flags & (CF_WRITE_ERROR|CF_SHUTW)))
                goto end;
 
+       if (!ctx->width) {
+               /* we don't know the first column's width, let's compute it
+                * now based on a first pass on printable entries and their
+                * expected width (approximated).
+                */
+               for (ptr = ctx->start; ptr != ctx->stop; ptr++) {
+                       const char *p, *name;
+                       int w = 0;
+                       char tmp;
+
+                       if (!ptr->size && !ptr->calls && !ctx->show_all)
+                               continue;
+
+                       for (p = name = ptr->file; *p; p++) {
+                               if (*p == '/')
+                                       name = p + 1;
+                       }
+
+                       if (ctx->show_all)
+                               w = snprintf(&tmp, 0, "%s(%s:%d) ", ptr->func, name, ptr->line);
+                       else
+                               w = snprintf(&tmp, 0, "%s:%d ", name, ptr->line);
+
+                       if (w > ctx->width)
+                               ctx->width = w;
+               }
+       }
+
        /* we have two inner loops here, one for the proxy, the other one for
         * the buffer.
         */
-       for (; ptr != ctx->stop; ptr++) {
+       for (ptr = ctx->start; ptr != ctx->stop; ptr++) {
                const char *type;
                const char *name;
                const char *p;
@@ -1326,7 +1356,7 @@ static int debug_iohandler_memstats(struct appctx *appctx)
                if (ctx->show_all)
                        chunk_appendf(&trash, ")");
 
-               while (trash.data < (ctx->show_all ? 45 : 25))
+               while (trash.data < ctx->width)
                        trash.area[trash.data++] = ' ';
 
                chunk_appendf(&trash, "%7s  size: %12lu  calls: %9lu  size/call: %6lu %s\n",