use in production. The same may be achieved at run time on the CLI using the
"set profiling memory" command, please consult the management manual.
-profiling.tasks { auto | on | off }
+profiling.tasks { auto | on | off | lock | no-lock | memory | no-memory }*
Enables ('on') or disables ('off') per-task CPU profiling. When set to 'auto'
the profiling automatically turns on a thread when it starts to suffer from
an average latency of 1000 microseconds or higher as reported in the
systems, containers, or virtual machines, or when the system swaps (which
must absolutely never happen on a load balancer).
+ When task profiling is enabled, HAProxy can also collect the time each task
+ spends with a lock held or waiting for a lock, as well as the time spent
+ waiting for a memory allocation to succeed in case of a pool cache miss. This
+ can sometimes help understand certain causes of latency. For this, the extra
+ keywords "lock" (to enable lock time collection), "no-lock" (to disable it),
+ "memory" (to enable memory allocation time collection) or "no-memory" (to
+ disable it) may additionally be passed. By default they are not enabled since
+ they can have a non-negligible CPU impact on highly loaded systems (3-10%).
+ Note that the overhead is only taken when profiling is effectively running,
+ so that when running in "auto" mode, it will only appear when HAProxy decides
+ to turn it on.
+
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. Enabling
it will typically affect the overall's performance by less than 1%, thus it
}
#endif // USE_MEMORY_PROFILING
-/* config parser for global "profiling.tasks", accepts "on" or "off" */
+/* config parser for global "profiling.tasks", accepts "on", "off", 'auto",
+ * "lock", "no-lock", "memory", "no-memory".
+ */
static int cfg_parse_prof_tasks(char **args, int section_type, struct proxy *curpx,
const struct proxy *defpx, const char *file, int line,
char **err)
{
- if (too_many_args(1, args, err, NULL))
- return -1;
+ int arg;
- if (strcmp(args[1], "on") == 0) {
- profiling = (profiling & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_ON;
- HA_ATOMIC_STORE(&prof_task_start_ns, now_ns);
- }
- else if (strcmp(args[1], "auto") == 0) {
- profiling = (profiling & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_AOFF;
- HA_ATOMIC_STORE(&prof_task_start_ns, now_ns);
+ for (arg = 1; *args[arg]; arg++) {
+ if (strcmp(args[arg], "on") == 0) {
+ profiling = (profiling & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_ON;
+ HA_ATOMIC_STORE(&prof_task_start_ns, now_ns);
+ }
+ else if (strcmp(args[arg], "auto") == 0) {
+ profiling = (profiling & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_AOFF;
+ HA_ATOMIC_STORE(&prof_task_start_ns, now_ns);
+ }
+ else if (strcmp(args[arg], "off") == 0)
+ profiling = (profiling & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_OFF;
+ else if (strcmp(args[arg], "lock") == 0)
+ profiling |= HA_PROF_TASKS_LOCK;
+ else if (strcmp(args[arg], "no-lock") == 0)
+ profiling &= ~HA_PROF_TASKS_LOCK;
+ else if (strcmp(args[arg], "memory") == 0)
+ profiling |= HA_PROF_TASKS_MEM;
+ else if (strcmp(args[arg], "no-memory") == 0)
+ profiling &= ~HA_PROF_TASKS_MEM;
+ else
+ break;
}
- else if (strcmp(args[1], "off") == 0)
- profiling = (profiling & ~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_OFF;
- else {
- memprintf(err, "'%s' expects either 'on', 'auto', or 'off' but got '%s'.", args[0], args[1]);
+
+ /* either no arg or invalid arg */
+ if (arg == 1 || *args[arg]) {
+ memprintf(err, "'%s' expects a combination of either 'on', 'auto', 'off', 'lock', 'no-lock', 'memory', or 'no-memory', but got '%s'.", args[0], args[arg]);
return -1;
}
return 0;