MINOR: activity: add configuration and CLI support for "profiling.tasks"

This is a new global setting which enables or disables CPU profiling
per task. For now it only sets/resets the variable based on the global
option "profiling.tasks" and supports showing it as well as setting it
from the CLI using "show profiling" and "set profiling". The option will
be used by a future commit. It was done in a way which should ease future
addition of profiling options.
This commit is contained in:
Willy Tarreau 2018-11-22 11:02:09 +01:00
parent baba82fe70
commit 75c62c2793
4 changed files with 124 additions and 0 deletions

View File

@ -619,6 +619,7 @@ The following keywords are supported in the "global" section :
- nosplice
- nogetaddrinfo
- noreuseport
- profiling.tasks
- spread-checks
- server-state-base
- server-state-file
@ -1434,6 +1435,16 @@ noreuseport
Disables the use of SO_REUSEPORT - see socket(7). It is equivalent to the
command line argument "-dR".
profiling.tasks { on | off }
Enables ('on') or disables ('off') per-task CPU profiling. CPU profiling per
task can be very convenient to report where the time is spent and which
requests have what effect on which other request. It is not enabled by
default as it may consume a little bit extra CPU. This requires a system
supporting the clock_gettime(2) syscall with clock identifiers
CLOCK_MONOTONIC and CLOCK_THREAD_CPUTIME_ID, otherwise the reported time will
be zero. This option may be changed at run time using "set profiling" on the
CLI.
spread-checks <0..50, in percent>
Sometimes it is desirable to avoid sending agent and health checks to
servers at exact intervals, for instance when many logical servers are

View File

@ -1649,6 +1649,11 @@ set maxconn global <maxconn>
delayed until the threshold is reached. A value of zero restores the initial
setting.
set profiling { tasks } { on | off }
Enables or disables CPU profiling for the indicated subsystem. This is
equivalent to setting or clearing the "profiling" settings in the "global"
section of the configuration file. Please also see "show profiling".
set rate-limit connections global <value>
Change the process-wide connection rate limit, which is set by the global
'maxconnrate' setting. A value of zero disables the limitation. This limit
@ -2045,6 +2050,10 @@ show pools
as the SIGQUIT when running in foreground except that it does not flush
the pools.
show profiling
Dumps the current profiling settings, one per line, as well as the command
needed to change them.
show servers state [<backend>]
Dump the state of the servers found in the running configuration. A backend
name or identifier may be provided to limit the output to this backend only.

View File

@ -28,6 +28,10 @@
#include <types/activity.h>
#include <proto/freq_ctr.h>
/* bit fields for "profiling" */
#define HA_PROF_TASKS 0x00000001 /* enable per-task CPU profiling */
extern unsigned int profiling;
extern struct activity activity[MAX_THREADS];

View File

@ -10,11 +10,19 @@
*
*/
#include <common/cfgparse.h>
#include <common/config.h>
#include <common/standard.h>
#include <common/hathreads.h>
#include <types/activity.h>
#include <proto/channel.h>
#include <proto/cli.h>
#include <proto/freq_ctr.h>
#include <proto/stream_interface.h>
/* bit field of profiling options. Beware, may be modified at runtime! */
unsigned int profiling;
/* One struct per thread containing all collected measurements */
struct activity activity[MAX_THREADS] __attribute__((aligned(64))) = { };
@ -29,3 +37,95 @@ void report_stolen_time(uint64_t stolen)
update_freq_ctr(&activity[tid].cpust_1s, stolen);
update_freq_ctr_period(&activity[tid].cpust_15s, 15000, stolen);
}
/* config parser for global "profiling.tasks", accepts "on" or "off" */
static int cfg_parse_prof_tasks(char **args, int section_type, struct proxy *curpx,
struct proxy *defpx, const char *file, int line,
char **err)
{
if (too_many_args(1, args, err, NULL))
return -1;
if (strcmp(args[1], "on") == 0)
profiling |= HA_PROF_TASKS;
else if (strcmp(args[1], "off") == 0)
profiling &= ~HA_PROF_TASKS;
else {
memprintf(err, "'%s' expects either 'on' or 'off' but got '%s'.", args[0], args[1]);
return -1;
}
return 0;
}
/* parse a "set profiling" command. It always returns 1. */
static int cli_parse_set_profiling(char **args, char *payload, struct appctx *appctx, void *private)
{
unsigned int bit = 0;
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;
if (strcmp(args[2], "tasks") == 0)
bit = HA_PROF_TASKS;
else {
appctx->ctx.cli.severity = LOG_ERR;
appctx->ctx.cli.msg = "Expects 'tasks'.\n";
appctx->st0 = CLI_ST_PRINT;
return 1;
}
if (strcmp(args[3], "on") == 0)
HA_ATOMIC_OR(&profiling, bit);
else if (strcmp(args[3], "off") == 0)
HA_ATOMIC_AND(&profiling, ~bit);
else {
appctx->ctx.cli.severity = LOG_ERR;
appctx->ctx.cli.msg = "Expects either 'on' or 'off'.\n";
appctx->st0 = CLI_ST_PRINT;
return 1;
}
return 1;
}
/* 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.
*/
static int cli_io_handler_show_profiling(struct appctx *appctx)
{
struct stream_interface *si = appctx->owner;
if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW)))
return 1;
chunk_reset(&trash);
chunk_printf(&trash, "Per-task CPU profiling : %s # set profiling tasks {on|off}\n",
(profiling & HA_PROF_TASKS) ? "on" : "off");
if (ci_putchk(si_ic(si), &trash) == -1) {
/* failed, try again */
si_rx_room_blk(si);
return 0;
}
return 1;
}
/* config keyword parsers */
static struct cfg_kw_list cfg_kws = {ILH, {
{ CFG_GLOBAL, "profiling.tasks", cfg_parse_prof_tasks },
{ 0, NULL, NULL }
}};
/* register cli keywords */
static struct cli_kw_list cli_kws = {{ },{
{ { "show", "profiling", NULL }, "show profiling : show CPU profiling options", NULL, cli_io_handler_show_profiling, NULL },
{ { "set", "profiling", NULL }, "set profiling : enable/disable CPU profiling", cli_parse_set_profiling, NULL },
{{},}
}};
__attribute__((constructor))
static void __activity_init(void)
{
cfg_register_keywords(&cfg_kws);
cli_register_kw(&cli_kws);
}