MINOR: debug: make ha_thread_dump() and ha_task_dump() take a buffer

Instead of having them dump into the trash and initialize it, let's have
the caller initialize a buffer and pass it. This will be convenient to
dump multiple threads at once into a single buffer.
This commit is contained in:
Willy Tarreau 2019-05-17 10:36:08 +02:00
parent 14a1ab75d0
commit 5cf64dd1bd
2 changed files with 33 additions and 28 deletions

View File

@ -83,8 +83,9 @@
struct task; struct task;
void ha_task_dump(const struct task *task, const char *pfx); struct buffer;
void ha_thread_dump(int thr); void ha_task_dump(struct buffer *buf, const struct task *task, const char *pfx);
void ha_thread_dump(struct buffer *buf, int thr, int calling_tid);
/* This one is useful to automatically apply poisonning on an area returned /* This one is useful to automatically apply poisonning on an area returned
* by malloc(). Only "p_" is required to make it work, and to define a poison * by malloc(). Only "p_" is required to make it work, and to define a poison

View File

@ -14,6 +14,7 @@
#include <time.h> #include <time.h>
#include <stdio.h> #include <stdio.h>
#include <common/buf.h>
#include <common/config.h> #include <common/config.h>
#include <common/debug.h> #include <common/debug.h>
#include <common/hathreads.h> #include <common/hathreads.h>
@ -27,18 +28,20 @@
#include <proto/stream_interface.h> #include <proto/stream_interface.h>
#include <proto/task.h> #include <proto/task.h>
/* Dumps to the trash some known information for the desired thread, and /* Dumps to the buffer some known information for the desired thread, and
* optionally extra info for the current thread. * optionally extra info for the current thread. The dump will be appended to
* the buffer, so the caller is responsible for preliminary initializing it.
* The calling thread ID needs to be passed in <calling_tid> to display a star
* in front of the calling thread's line (usually it's tid).
*/ */
void ha_thread_dump(int thr) void ha_thread_dump(struct buffer *buf, int thr, int calling_tid)
{ {
unsigned long thr_bit = 1UL << thr; unsigned long thr_bit = 1UL << thr;
chunk_reset(&trash); chunk_appendf(buf,
chunk_appendf(&trash,
"%c Thread %-2u: act=%d glob=%d wq=%d rq=%d tl=%d tlsz=%d rqsz=%d\n" "%c Thread %-2u: act=%d glob=%d wq=%d rq=%d tl=%d tlsz=%d rqsz=%d\n"
" fdcache=%d prof=%d", " fdcache=%d prof=%d",
(thr == tid) ? '*' : ' ', thr + 1, (thr == calling_tid) ? '*' : ' ', thr + 1,
!!(active_tasks_mask & thr_bit), !!(active_tasks_mask & thr_bit),
!!(global_tasks_mask & thr_bit), !!(global_tasks_mask & thr_bit),
!eb_is_empty(&task_per_thread[thr].timers), !eb_is_empty(&task_per_thread[thr].timers),
@ -50,44 +53,45 @@ void ha_thread_dump(int thr)
!!(task_profiling_mask & thr_bit)); !!(task_profiling_mask & thr_bit));
#ifdef USE_THREAD #ifdef USE_THREAD
chunk_appendf(&trash, chunk_appendf(buf,
" harmless=%d wantrdv=%d", " harmless=%d wantrdv=%d",
!!(threads_harmless_mask & thr_bit), !!(threads_harmless_mask & thr_bit),
!!(threads_want_rdv_mask & thr_bit)); !!(threads_want_rdv_mask & thr_bit));
#endif #endif
chunk_appendf(&trash, "\n"); chunk_appendf(buf, "\n");
/* this is the end of what we can dump from outside the thread */ /* this is the end of what we can dump from outside the thread */
if (thr != tid) if (thr != tid)
return; return;
chunk_appendf(&trash, " curr_task="); chunk_appendf(buf, " curr_task=");
ha_task_dump(curr_task, " "); ha_task_dump(buf, curr_task, " ");
} }
/* dumps into the trash some information related to task <task> (which may /* dumps into the buffer some information related to task <task> (which may
* either be a task or a tasklet, and prepend each line except the first one * either be a task or a tasklet, and prepend each line except the first one
* with <pfx>. The trash is only appended and the first output starts by the * with <pfx>. The buffer is only appended and the first output starts by the
* pointer itself. * pointer itself. The caller is responsible for making sure the task is not
* going to vanish during the dump.
*/ */
void ha_task_dump(const struct task *task, const char *pfx) void ha_task_dump(struct buffer *buf, const struct task *task, const char *pfx)
{ {
if (!task) { if (!task) {
chunk_appendf(&trash, "0\n"); chunk_appendf(buf, "0\n");
return; return;
} }
chunk_appendf(&trash, chunk_appendf(buf,
"%p (%s) calls=%u last=%llu%s\n", "%p (%s) calls=%u last=%llu%s\n",
task, TASK_IS_TASKLET(task) ? "tasklet" : "task", task, TASK_IS_TASKLET(task) ? "tasklet" : "task",
task->calls, task->calls,
task->call_date ? (unsigned long long)(now_mono_time() - task->call_date) : 0, task->call_date ? (unsigned long long)(now_mono_time() - task->call_date) : 0,
task->call_date ? " ns ago" : ""); task->call_date ? " ns ago" : "");
chunk_appendf(&trash, "%s" chunk_appendf(buf, "%s"
" fct=%p (%s) ctx=%p\n", " fct=%p (%s) ctx=%p\n",
pfx, pfx,
task->process, task->process,
@ -98,7 +102,6 @@ void ha_task_dump(const struct task *task, const char *pfx)
task->context); task->context);
} }
/* This function dumps all profiling settings. It returns 0 if the output /* 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. * buffer is full and it needs to be called again, otherwise non-zero.
*/ */
@ -115,17 +118,18 @@ static int cli_io_handler_show_threads(struct appctx *appctx)
else else
thr = 0; thr = 0;
chunk_reset(&trash);
while (thr < global.nbthread) { while (thr < global.nbthread) {
ha_thread_dump(thr); ha_thread_dump(&trash, thr, tid);
if (ci_putchk(si_ic(si), &trash) == -1) {
/* failed, try again */
si_rx_room_blk(si);
appctx->st1 = thr;
return 0;
}
thr++; thr++;
} }
if (ci_putchk(si_ic(si), &trash) == -1) {
/* failed, try again */
si_rx_room_blk(si);
appctx->st1 = thr;
return 0;
}
return 1; return 1;
} }