]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: activity: make "show profiling" also dump the memoery usage
authorWilly Tarreau <w@1wt.eu>
Wed, 5 May 2021 16:07:02 +0000 (18:07 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 5 May 2021 17:09:19 +0000 (19:09 +0200)
Now the memory usage stats are dumped. They are first sorted by total
alloc+free so that the first ones are always the most relevant, and
that most symmetric alloc/free pairs appear next to each other. This
way it becomes convenient to only show a small part of them such as:

    show profiling memory 20

It's worth noting that the sorting is performed upon each call to the
iohandler so it is technically possible that an entry could appear
twice or be dropped if the ordering changes between two calls. In
practice it is not an issue but it's worth being mentioned.

src/activity.c

index 0cb48361bf577823237d395d35d5534f8ffa4922..afed0ca95502362ca60d11eda35a9ea24961365d 100644 (file)
@@ -442,6 +442,22 @@ static int cmp_sched_activity(const void *a, const void *b)
                return 0;
 }
 
+#if USE_MEMORY_PROFILING
+/* used by qsort below */
+static int cmp_memprof_stats(const void *a, const void *b)
+{
+       const struct memprof_stats *l = (const struct memprof_stats *)a;
+       const struct memprof_stats *r = (const struct memprof_stats *)b;
+
+       if (l->alloc_tot + l->free_tot > r->alloc_tot + r->free_tot)
+               return -1;
+       else if (l->alloc_tot + l->free_tot < r->alloc_tot + r->free_tot)
+               return 1;
+       else
+               return 0;
+}
+#endif // USE_MEMORY_PROFILING
+
 /* This function dumps all profiling settings. It returns 0 if the output
  * buffer is full and it needs to be called again, otherwise non-zero.
  * It dumps some parts depending on the following states:
@@ -457,6 +473,9 @@ static int cmp_sched_activity(const void *a, const void *b)
 static int cli_io_handler_show_profiling(struct appctx *appctx)
 {
        struct sched_activity tmp_activity[256] __attribute__((aligned(64)));
+#if USE_MEMORY_PROFILING
+       struct memprof_stats tmp_memstats[MEMPROF_HASH_BUCKETS + 1];
+#endif
        struct stream_interface *si = appctx->owner;
        struct buffer *name_buffer = get_trash_chunk();
        const char *str;
@@ -549,6 +568,59 @@ static int cli_io_handler_show_profiling(struct appctx *appctx)
 
  skip_tasks:
 
+#if USE_MEMORY_PROFILING
+       if ((appctx->ctx.cli.i0 & 3) != 2)
+               goto skip_mem;
+
+       memcpy(tmp_memstats, memprof_stats, sizeof(tmp_memstats));
+       qsort(tmp_memstats, MEMPROF_HASH_BUCKETS+1, sizeof(tmp_memstats[0]), cmp_memprof_stats);
+
+       if (!appctx->ctx.cli.i1)
+               chunk_appendf(&trash,
+                             "Alloc/Free statistics by call place:\n"
+                             "         Calls         |         Tot Bytes           |       Caller\n"
+                             "<- alloc -> <- free  ->|<-- alloc ---> <-- free ---->|\n");
+
+       max_lines = appctx->ctx.cli.o0;
+       if (!max_lines)
+               max_lines = MEMPROF_HASH_BUCKETS + 1;
+
+       for (i = appctx->ctx.cli.i1; i < max_lines; i++) {
+               struct memprof_stats *entry = &tmp_memstats[i];
+
+               appctx->ctx.cli.i1 = i;
+               if (!entry->alloc_calls && !entry->free_calls)
+                       continue;
+               chunk_appendf(&trash, "%11llu %11llu %14llu %14llu| %16p ",
+                             entry->alloc_calls, entry->free_calls,
+                             entry->alloc_tot, entry->free_tot,
+                             entry->caller);
+
+               if (entry->caller)
+                       resolve_sym_name(&trash, NULL, entry->caller);
+               else
+                       chunk_appendf(&trash, "[other]");
+
+               chunk_appendf(&trash,"\n");
+
+               if (ci_putchk(si_ic(si), &trash) == -1) {
+                       si_rx_room_blk(si);
+                       return 0;
+               }
+       }
+
+       if (ci_putchk(si_ic(si), &trash) == -1) {
+               si_rx_room_blk(si);
+               return 0;
+       }
+
+       appctx->ctx.cli.i1 = 0; // reset first line to dump
+       if ((appctx->ctx.cli.i0 & 4) == 0)
+               appctx->ctx.cli.i0++; // next step
+
+ skip_mem:
+#endif // USE_MEMORY_PROFILING
+
        return 1;
 }