]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: activity/cli: support aggregating task profiling outputs
authorWilly Tarreau <w@1wt.eu>
Thu, 8 Sep 2022 14:05:57 +0000 (16:05 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 8 Sep 2022 14:32:17 +0000 (16:32 +0200)
By default we now dump stats between caller and callee, but by
specifying "aggr" on the command line, stats get aggregated by
callee again as it used to be before the feature was available.
It may sometimes be helpful when comparing total call counts,
though that's about all.

doc/management.txt
src/activity.c

index e88b243495bd6649b08f89f0954a11e1393ae9c4..e6bc9ca044f9a001a938051af4c029d7e31c62b7 100644 (file)
@@ -2866,7 +2866,7 @@ show pools
   as the SIGQUIT when running in foreground except that it does not flush
   the pools.
 
-show profiling [{all | status | tasks | memory}] [byaddr] [<max_lines>]
+show profiling [{all | status | tasks | memory}] [byaddr] [aggr] [<max_lines>]
   Dumps the current profiling settings, one per line, as well as the command
   needed to change them. When tasks profiling is enabled, some per-function
   statistics collected by the scheduler will also be emitted, with a summary
@@ -2878,7 +2878,8 @@ show profiling [{all | status | tasks | memory}] [byaddr] [<max_lines>]
   information are dumped. It is also possible to limit the number of lines
   of output of each category by specifying a numeric limit. If is possible to
   request that the output is sorted by address instead of usage, e.g. to ease
-  comparisons between subsequent calls. Please note that profiling is
+  comparisons between subsequent calls, and to aggregate task activity by
+  called function instead of seeing the details. Please note that profiling is
   essentially aimed at developers since it gives hints about where CPU cycles
   or memory are wasted in the code. There is nothing useful to monitor there.
 
index f652019b1b31e5cdbe367d8955d975b059e02414..44c2e287b726de6d33fa0370e22b1f0c638f6643 100644 (file)
@@ -28,6 +28,7 @@ struct show_prof_ctx {
        int linenum;    /* next line to be dumped (starts at 0) */
        int maxcnt;     /* max line count per step (0=not set)  */
        int by_addr;    /* 0=sort by usage, 1=sort by address   */
+       int aggr;       /* 0=dump raw, 1=aggregate on callee    */
 };
 
 #if defined(DEBUG_MEM_STATS)
@@ -597,7 +598,7 @@ static int cli_io_handler_show_profiling(struct appctx *appctx)
        const struct ha_caller *caller;
        const char *str;
        int max_lines;
-       int i, max;
+       int i, j, max;
 
        if (unlikely(sc_ic(sc)->flags & (CF_WRITE_ERROR|CF_SHUTW)))
                return 1;
@@ -633,9 +634,23 @@ static int cli_io_handler_show_profiling(struct appctx *appctx)
                goto skip_tasks;
 
        memcpy(tmp_activity, sched_activity, sizeof(tmp_activity));
-       if (ctx->by_addr)
-               qsort(tmp_activity, SCHED_ACT_HASH_BUCKETS, sizeof(tmp_activity[0]), cmp_sched_activity_addr);
-       else
+       /* for addr sort and for callee aggregation we have to first sort by address */
+       if (ctx->aggr || ctx->by_addr)
+               qsort(tmp_activity, SCHED_ACT_HASH_BUCKETS, sizeof(tmp_activity[0]), cmp_sched_activity_addr);  
+
+       if (ctx->aggr) {
+               /* merge entries for the same callee and reset their count */
+               for (i = j = 0; i < SCHED_ACT_HASH_BUCKETS; i = j) {
+                       for (j = i + 1; j < SCHED_ACT_HASH_BUCKETS && tmp_activity[j].func == tmp_activity[i].func; j++) {
+                               tmp_activity[i].calls    += tmp_activity[j].calls;
+                               tmp_activity[i].cpu_time += tmp_activity[j].cpu_time;
+                               tmp_activity[i].lat_time += tmp_activity[j].lat_time;
+                               tmp_activity[j].calls = 0;
+                       }
+               }
+       }
+
+       if (!ctx->by_addr)
                qsort(tmp_activity, SCHED_ACT_HASH_BUCKETS, sizeof(tmp_activity[0]), cmp_sched_activity_calls);
 
        if (!ctx->linenum)
@@ -646,7 +661,10 @@ static int cli_io_handler_show_profiling(struct appctx *appctx)
        if (!max_lines)
                max_lines = SCHED_ACT_HASH_BUCKETS;
 
-       for (i = ctx->linenum; i < max_lines && tmp_activity[i].calls; i++) {
+       for (i = ctx->linenum; i < max_lines; i++) {
+               if (!tmp_activity[i].calls)
+                       continue; // skip aggregated or empty entries
+
                ctx->linenum = i;
                chunk_reset(name_buffer);
                caller = HA_ATOMIC_LOAD(&tmp_activity[i].caller);
@@ -669,7 +687,7 @@ static int cli_io_handler_show_profiling(struct appctx *appctx)
                print_time_short(&trash, "   ", tmp_activity[i].lat_time, "");
                print_time_short(&trash, "   ", tmp_activity[i].lat_time / tmp_activity[i].calls, "");
 
-               if (caller && caller->what <= WAKEUP_TYPE_APPCTX_WAKEUP)
+               if (caller && !ctx->aggr && caller->what <= WAKEUP_TYPE_APPCTX_WAKEUP)
                        chunk_appendf(&trash, " <- %s@%s:%d %s",
                                      caller->func, caller->file, caller->line,
                                      task_wakeup_type_str(caller->what));
@@ -810,11 +828,14 @@ static int cli_parse_show_profiling(char **args, char *payload, struct appctx *a
                else if (strcmp(args[arg], "byaddr") == 0) {
                        ctx->by_addr = 1; // sort output by address instead of usage
                }
+               else if (strcmp(args[arg], "aggr") == 0) {
+                       ctx->aggr = 1;    // aggregate output by callee
+               }
                else if (isdigit((unsigned char)*args[arg])) {
                        ctx->maxcnt = atoi(args[arg]); // number of entries to dump
                }
                else
-                       return cli_err(appctx, "Expects either 'all', 'status', 'tasks', 'memory', 'byaddr' or a max number of output lines.\n");
+                       return cli_err(appctx, "Expects either 'all', 'status', 'tasks', 'memory', 'byaddr', 'aggr' or a max number of output lines.\n");
        }
        return 0;
 }
@@ -977,7 +998,7 @@ INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
 /* register cli keywords */
 static struct cli_kw_list cli_kws = {{ },{
        { { "set",  "profiling", NULL }, "set profiling <what> {auto|on|off}      : enable/disable resource profiling (tasks,memory)", cli_parse_set_profiling,  NULL },
-       { { "show", "profiling", NULL }, "show profiling [<what>|<#lines>|byaddr]*: show profiling state (all,status,tasks,memory)",   cli_parse_show_profiling, cli_io_handler_show_profiling, NULL },
+       { { "show", "profiling", NULL }, "show profiling [<what>|<#lines>|<opts>]*: show profiling state (all,status,tasks,memory)",   cli_parse_show_profiling, cli_io_handler_show_profiling, NULL },
        { { "show", "tasks", NULL },     "show tasks                              : show running tasks",                               NULL, cli_io_handler_show_tasks,     NULL },
        {{},}
 }};