Skip to content

Commit

Permalink
MINOR: debug: add "debug dev counters" to list code counters
Browse files Browse the repository at this point in the history
Issuing "debug dev counters" on the CLI will now scan all existing
counters, and report their count, type, location, function name, the
condition and an optional comment passed to the macro.

The command takes a number of arguments:
  - "show": this is the default, it will just list the counters
  - "reset": will reset the matching counters instead of listing them
  - "all": by default, only non-zero counters are listed. With "all",
     they are all listed
  - "bug": restrict the reset or dump to counters of type "BUG" (BUG_ON usually)
  - "chk": restrict the reset or dump to counters of type "CHK" (CHECK_IF)
  - "cnt": restrict the reset or dump to counters of type "CNT" (COUNT_IF)

The types may be cumulated, and the option entered in any order. Here's
an example of the output of "debug dev counters show all bug":

  Count     Type Location function(): "condition" [comment]
  0          BUG ring.h:114 ring_dup(): "max > ring_size(dst)"
  0          BUG vecpair.h:223 vp_getblk_ofs(): "ofs >= v1->len + v2->len"
  0          BUG buf.h:395 b_add(): "b->data + count > b->size"
  0          BUG buf.h:106 b_room(): "b->data > b->size"
  0          BUG task.h:328 _task_queue(): "(ulong)caller & 1"
  0          BUG task.h:324 _task_queue(): "task->tid != tid"
  0          BUG task.h:313 _task_queue(): "(ulong)caller & 1"
  (...)

This is expected to be convenient combined with the use and abuse of
COUNT_IF() at select locations.
  • Loading branch information
wtarreau committed Oct 21, 2024
1 parent da66c42 commit f2c415c
Showing 1 changed file with 124 additions and 0 deletions.
124 changes: 124 additions & 0 deletions src/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -2103,6 +2103,127 @@ static void debug_release_memstats(struct appctx *appctx)
}
#endif

#if !defined(USE_OBSOLETE_LINKER)

/* CLI state for "debug dev counters" */
struct dev_cnt_ctx {
struct debug_count *start, *stop; /* begin/end of dump */
int types; /* OR mask of 1<<type */
int show_all; /* show all entries if non-null */
};

/* CLI parser for the "debug dev counters" command. Sets a dev_cnt_ctx shown above. */
static int debug_parse_cli_counters(char **args, char *payload, struct appctx *appctx, void *private)
{
struct dev_cnt_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
int action;
int arg;

if (!cli_has_level(appctx, ACCESS_LVL_OPER))
return 1;

action = 0; // 0=show, 1=reset
for (arg = 3; *args[arg]; arg++) {
if (strcmp(args[arg], "reset") == 0) {
action = 1;
continue;
}
else if (strcmp(args[arg], "all") == 0) {
ctx->show_all = 1;
continue;
}
else if (strcmp(args[arg], "show") == 0) {
action = 0;
continue;
}
else if (strcmp(args[arg], "bug") == 0) {
ctx->types |= 1 << DBG_BUG;
continue;
}
else if (strcmp(args[arg], "chk") == 0) {
ctx->types |= 1 << DBG_BUG_ONCE;
continue;
}
else if (strcmp(args[arg], "cnt") == 0) {
ctx->types |= 1 << DBG_COUNT_IF;
continue;
}
else
return cli_err(appctx, "Expects an optional action ('reset','show'), optional types ('bug','chk','cnt') and optionally 'all' to even dump null counters.\n");
}

if (action == 1) { // reset
struct debug_count *ptr;

if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;

for (ptr = &__start_dbg_cnt; ptr < &__stop_dbg_cnt; ptr++) {
if (ctx->types && !(ctx->types & (1 << ptr->type)))
continue;
_HA_ATOMIC_STORE(&ptr->count, 0);
}
return 1;
}

/* OK it's a show, let's dump relevant counters */
ctx->start = &__start_dbg_cnt;
ctx->stop = &__stop_dbg_cnt;
return 0;
}

/* CLI I/O handler for the "debug dev counters" command using a dev_cnt_ctx
* found in appctx->svcctx. Dumps all mem_stats structs referenced by pointers
* located between ->start and ->stop. Dumps all entries if ->show_all != 0,
* otherwise only non-zero calls.
*/
static int debug_iohandler_counters(struct appctx *appctx)
{
const char *bug_type[DBG_COUNTER_TYPES] = {
[DBG_BUG] = "BUG",
[DBG_BUG_ONCE] = "CHK",
[DBG_COUNT_IF] = "CNT",
};
struct dev_cnt_ctx *ctx = appctx->svcctx;
struct debug_count *ptr;
int ret = 1;

/* we have two inner loops here, one for the proxy, the other one for
* the buffer.
*/
chunk_printf(&trash, "Count Type Location function(): \"condition\" [comment]\n");
for (ptr = ctx->start; ptr != ctx->stop; ptr++) {
const char *p, *name;

if (ctx->types && !(ctx->types & (1 << ptr->type)))
continue;

if (!ptr->count && !ctx->show_all)
continue;

for (p = name = ptr->file; *p; p++) {
if (*p == '/')
name = p + 1;
}

if (ptr->type < DBG_COUNTER_TYPES)
chunk_appendf(&trash, "%-10u %3s %s:%d %s(): %s\n",
ptr->count, bug_type[ptr->type],
name, ptr->line, ptr->func, ptr->desc);

if (applet_putchk(appctx, &trash) == -1) {
ctx->start = ptr;
ret = 0;
goto end;
}
}

/* we could even dump a summary here if needed, returning ret=0 */
end:
return ret;
}
#endif /* USE_OBSOLETE_LINKER */

#ifdef USE_THREAD_DUMP

/* handles DEBUGSIG to dump the state of the thread it's working on. This is
Expand Down Expand Up @@ -2516,6 +2637,9 @@ static struct cli_kw_list cli_kws = {{ },{
{{ "debug", "dev", "bug", NULL }, "debug dev bug : call BUG_ON() and crash", debug_parse_cli_bug, NULL, NULL, NULL, ACCESS_EXPERT },
{{ "debug", "dev", "check", NULL }, "debug dev check : call CHECK_IF() and possibly crash", debug_parse_cli_check, NULL, NULL, NULL, ACCESS_EXPERT },
{{ "debug", "dev", "close", NULL }, "debug dev close <fd> : close this file descriptor", debug_parse_cli_close, NULL, NULL, NULL, ACCESS_EXPERT },
#if !defined(USE_OBSOLETE_LINKER)
{{ "debug", "dev", "counters", NULL }, "debug dev counters [all|bug|cnt|chk|?]* : dump/reset rare event counters", debug_parse_cli_counters, debug_iohandler_counters, NULL, NULL, 0 },
#endif
{{ "debug", "dev", "deadlock", NULL }, "debug dev deadlock [nbtask] : deadlock between this number of tasks", debug_parse_cli_deadlock, NULL, NULL, NULL, ACCESS_EXPERT },
{{ "debug", "dev", "delay", NULL }, "debug dev delay [ms] : sleep this long", debug_parse_cli_delay, NULL, NULL, NULL, ACCESS_EXPERT },
#if defined(DEBUG_DEV)
Expand Down

0 comments on commit f2c415c

Please sign in to comment.