MINOR: activity: enable automatic profiling turn on/off

Instead of having to manually turn task profiling on/off in the
configuration, by default it will work in "auto" mode, which
automatically turns on on any thread experiencing sustained loop
latencies over one millisecond averaged over the last 1024 samples.

This may happen with configs using lots of regex (thing map_reg for
example, which is the lazy way to convert Apache's rewrite rules but
must not be abused), and such high latencies affect all the process
and the problem is most often intermittent (e.g. hitting a map which
is only used for certain host names).

Thus now by default, with profiling set to "auto", it remains off all
the time until something bad happens. This also helps better focus on
the issues when looking at the logs as well as in "show sess" output.
It automatically turns off when the average loop latency over the last
1024 calls goes below 990 microseconds (which typically takes a while
when in idle).

This patch could be backported to stable versions after a bit more
exposure, as it definitely improves observability and the ability to
quickly spot the culprit. In this case, previous patch ("MINOR:
activity: make the profiling status per thread and not global") must
also be taken.
diff --git a/include/proto/activity.h b/include/proto/activity.h
index 922f493..dd78344 100644
--- a/include/proto/activity.h
+++ b/include/proto/activity.h
@@ -29,7 +29,10 @@
 #include <proto/freq_ctr.h>
 
 /* bit fields for "profiling" */
-#define HA_PROF_TASKS       0x00000001     /* enable per-task CPU profiling */
+#define HA_PROF_TASKS_OFF   0x00000000     /* per-task CPU profiling forced disabled */
+#define HA_PROF_TASKS_AUTO  0x00000001     /* per-task CPU profiling automatic */
+#define HA_PROF_TASKS_ON    0x00000002     /* per-task CPU profiling forced enabled */
+#define HA_PROF_TASKS_MASK  0x00000003     /* per-task CPU profiling mask */
 
 extern unsigned int profiling;
 extern unsigned long task_profiling_mask;
@@ -49,6 +52,13 @@
 	uint64_t new_cpu_time;
 	int64_t stolen;
 	uint32_t run_time;
+	uint32_t up, down;
+
+	/* 1 millisecond per loop on average over last 1024 iterations is
+	 * enough to turn on profiling.
+	 */
+	up = 1000;
+	down = up * 99 / 100;
 
 	new_cpu_time   = now_cpu_time();
 	new_mono_time  = now_mono_time();
@@ -69,12 +79,22 @@
 	run_time = (before_poll.tv_sec - after_poll.tv_sec) * 1000000U + (before_poll.tv_usec - after_poll.tv_usec);
 	swrate_add(&activity[tid].avg_loop_us, TIME_STATS_SAMPLES, run_time);
 
+	/* reaching the "up" threshold on average switches profiling to "on"
+	 * when automatic, and going back below the "down" threshold switches
+	 * to off.
+	 */
 	if (!(task_profiling_mask & tid_bit)) {
-		if (unlikely(profiling & HA_PROF_TASKS))
-			_HA_ATOMIC_OR(&task_profiling_mask, tid_bit);
+		if (unlikely((profiling & HA_PROF_TASKS_MASK) == HA_PROF_TASKS_ON ||
+			     ((profiling & HA_PROF_TASKS_MASK) == HA_PROF_TASKS_AUTO && run_time >= up))) {
+			if (swrate_avg(activity[tid].avg_loop_us, TIME_STATS_SAMPLES) >= up)
+				_HA_ATOMIC_OR(&task_profiling_mask, tid_bit);
+		}
 	} else {
-		if (unlikely(!(profiling & HA_PROF_TASKS)))
-			_HA_ATOMIC_AND(&task_profiling_mask, ~tid_bit);
+		if (unlikely((profiling & HA_PROF_TASKS_MASK) == HA_PROF_TASKS_OFF ||
+			     ((profiling & HA_PROF_TASKS_MASK) == HA_PROF_TASKS_AUTO && run_time <= down))) {
+			if (swrate_avg(activity[tid].avg_loop_us, TIME_STATS_SAMPLES) <= down)
+				_HA_ATOMIC_AND(&task_profiling_mask, ~tid_bit);
+		}
 	}
 }