]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: sched: add TASK_F_WANTS_TIME to make the scheduler update the call date
authorWilly Tarreau <w@1wt.eu>
Tue, 19 Nov 2024 15:27:46 +0000 (16:27 +0100)
committerWilly Tarreau <w@1wt.eu>
Tue, 19 Nov 2024 19:13:41 +0000 (20:13 +0100)
Currently tasks being profiled have th_ctx->sched_call_date set to the
current nanosecond in monotonic time. But there's no other way to have
this, despite the scheduler being capable of it. Let's just declare a
new task flag, TASK_F_WANTS_TIME, that makes the scheduler take the time
just before calling the handler. This way, a task that needs nanosecond
resolution on the call date will be able to be called with an up-to-date
date without having to abuse now_mono_time() if not needed. In addition,
if CLOCK_MONOTONIC is not supported (now_mono_time() always returns 0),
the date is set to the most recently known now_ns, which is guaranteed
to be atomic and is only updated once per poll loop.

This date can be more conveniently retrieved using task_mono_time().

This can be useful, e.g. for pacing. The code was slightly adjusted so
as to merge the common parts between the profiling case and this one.

include/haproxy/task-t.h
include/haproxy/task.h
src/task.c

index a6807a5dd214d8b8406174e86ce2fd6fdd57c3e6..2a914c6b21690ff6249064779fa99f5e9184c357 100644 (file)
 #define TASK_F_USR1       0x00010000  /* preserved user flag 1, application-specific, def:0 */
 #define TASK_F_UEVT1      0x00020000  /* one-shot user event type 1, application specific, def:0 */
 #define TASK_F_UEVT2      0x00040000  /* one-shot user event type 2, application specific, def:0 */
-/* unused: 0x80000..0x80000000 */
+#define TASK_F_WANTS_TIME 0x00080000  /* task/tasklet wants th_ctx->sched_call_date to be set */
+/* unused: 0x100000..0x80000000 */
 
 /* These flags are persistent across scheduler calls */
 #define TASK_PERSISTENT   (TASK_SELF_WAKING | TASK_KILLED | \
-                           TASK_HEAVY | TASK_F_TASKLET | TASK_F_USR1)
+                           TASK_HEAVY | TASK_F_TASKLET | TASK_F_USR1 | \
+                           TASK_F_WANTS_TIME)
 
 /* This function is used to report state in debugging tools. Please reflect
  * below any single-bit flag addition above in the same order via the
index 1c9c45f496ac751a9daa202ec3392b5d1629e50f..dbbb0a8b517f23319f8c6a8f2da9594f8ce43419 100644 (file)
@@ -193,6 +193,12 @@ static inline int thread_has_tasks(void)
                (int)!MT_LIST_ISEMPTY(&th_ctx->shared_tasklet_list));
 }
 
+/* returns the most recent known date of the task's call from the scheduler */
+static inline uint64_t task_mono_time(void)
+{
+       return th_ctx->sched_call_date;
+}
+
 /* puts the task <t> in run queue with reason flags <f>, and returns <t> */
 /* This will put the task in the local runqueue if the task is only runnable
  * by the current thread, in the global runqueue otherwies. With DEBUG_TASK,
index 1ab5212018764cf18c7b4ac3b7160baf0dc76304..9b6beb8ad71dfc06d19bbaa06d102eeafcd7aefb 100644 (file)
@@ -567,17 +567,24 @@ unsigned int run_tasks_from_lists(unsigned int budgets[])
                t->calls++;
 
                th_ctx->sched_wake_date = t->wake_date;
-               if (th_ctx->sched_wake_date) {
-                       uint32_t now_ns = now_mono_time();
-                       uint32_t lat = now_ns - th_ctx->sched_wake_date;
+               if (th_ctx->sched_wake_date || (t->state & TASK_F_WANTS_TIME)) {
+                       /* take the most accurate clock we have, either
+                        * mono_time() or last now_ns (monotonic but only
+                        * incremented once per poll loop).
+                        */
+                       th_ctx->sched_call_date = now_mono_time();
+                       if (unlikely(!th_ctx->sched_call_date))
+                               th_ctx->sched_call_date = now_ns;
+               }
 
+               if (th_ctx->sched_wake_date) {
                        t->wake_date = 0;
-                       th_ctx->sched_call_date = now_ns;
                        profile_entry = sched_activity_entry(sched_activity, t->process, t->caller);
                        th_ctx->sched_profile_entry = profile_entry;
-                       HA_ATOMIC_ADD(&profile_entry->lat_time, lat);
+                       HA_ATOMIC_ADD(&profile_entry->lat_time, (uint32_t)(th_ctx->sched_call_date - th_ctx->sched_wake_date));
                        HA_ATOMIC_INC(&profile_entry->calls);
                }
+
                __ha_barrier_store();
 
                th_ctx->current = t;