mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-08 08:07:10 +02:00
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:
parent
14a1ab75d0
commit
5cf64dd1bd
@ -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
|
||||||
|
46
src/debug.c
46
src/debug.c
@ -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,8 +118,11 @@ 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);
|
||||||
|
thr++;
|
||||||
|
}
|
||||||
|
|
||||||
if (ci_putchk(si_ic(si), &trash) == -1) {
|
if (ci_putchk(si_ic(si), &trash) == -1) {
|
||||||
/* failed, try again */
|
/* failed, try again */
|
||||||
@ -124,8 +130,6 @@ static int cli_io_handler_show_threads(struct appctx *appctx)
|
|||||||
appctx->st1 = thr;
|
appctx->st1 = thr;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
thr++;
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user