]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: checks: maintain counters of active checks per thread
authorWilly Tarreau <w@1wt.eu>
Thu, 17 Aug 2023 14:25:28 +0000 (16:25 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 1 Sep 2023 06:26:06 +0000 (08:26 +0200)
Let's keep two check counters per thread:
  - one for "active" checks, i.e. checks that are no more sleeping
    and are assigned to the thread. These include sleeping and
    running checks ;

  - one for "running" checks, i.e. those which are currently
    executing on the thread.

By doing so, we'll be able to spread the health checks load a bit better
and refrain from sending too many at once per thread. The counters are
atomic since a migration increments the target thread's active counter.
These numbers are reported in "show activity", which allows to check
per thread and globally how many checks are currently pending and running
on the system.

Ideally, we should only consider checks in the process of establishing
a connection since that's really the expensive part (particularly with
OpenSSL 3.0). But the inner layers are really not suitable to doing
this. However knowing the number of active checks is already a good
enough hint.

include/haproxy/tinfo-t.h
src/activity.c
src/check.c

index c633fee8c6c9356203cf420a2dfeac703360b410..feabe40800229dd1b46336d42cfdeb5877a92851 100644 (file)
@@ -148,7 +148,7 @@ struct thread_ctx {
        int tasks_in_list;                  /* Number of tasks in the per-thread tasklets list */
        uint idle_pct;                      /* idle to total ratio over last sample (percent) */
        uint flags;                         /* thread flags, TH_FL_*, atomic! */
-       /* 32-bit hole here */
+       uint active_checks;                 /* number of active health checks on this thread, incl migrated */
 
        uint32_t sched_wake_date;           /* current task/tasklet's wake date or 0 */
        uint32_t sched_call_date;           /* current task/tasklet's call date (valid if sched_wake_date > 0) */
@@ -161,6 +161,8 @@ struct thread_ctx {
        __decl_thread(HA_SPINLOCK_T rqsh_lock); /* lock protecting the shared runqueue */
 
        struct freq_ctr out_32bps;              /* #of 32-byte blocks emitted per second */
+       uint running_checks;                    /* number of health checks currently running on this thread */
+
        unsigned long long out_bytes;           /* total #of bytes emitted */
        unsigned long long spliced_out_bytes;   /* total #of bytes emitted though a kernel pipe */
        struct buffer *thread_dump_buffer;      /* NULL out of dump, valid during a dump, 0x01 once done */
index 434c14713362e40602eb23aa3e27519c95c55a12..e88414be14a1d92af4e9c0c5a001dfb2c0975eea 100644 (file)
@@ -1145,6 +1145,8 @@ static int cli_io_handler_show_activity(struct appctx *appctx)
                case __LINE__: SHOW_VAL("check_adopted:",activity[thr].check_adopted, _tot); break;
 #endif
                case __LINE__: SHOW_VAL("check_started:",activity[thr].check_started, _tot); break;
+               case __LINE__: SHOW_VAL("check_active:", _HA_ATOMIC_LOAD(&ha_thread_ctx[thr].active_checks), _tot); break;
+               case __LINE__: SHOW_VAL("check_running:",_HA_ATOMIC_LOAD(&ha_thread_ctx[thr].running_checks), _tot); break;
 
 #if defined(DEBUG_DEV)
                        /* keep these ones at the end */
index 5c1cd8a26a40ac1785bd8e91831c259964d6adec..9804cb289f2fa08ab031e61114e8d989cc12238b 100644 (file)
@@ -1138,7 +1138,7 @@ struct task *process_chk_conn(struct task *t, void *context, unsigned int state)
                uint my_load = HA_ATOMIC_LOAD(&th_ctx->rq_total);
 
                if (check->state & CHK_ST_READY) {
-                       /* check was migrated */
+                       /* check was migrated, active already counted */
                        activity[tid].check_adopted++;
                }
                else if (my_load >= 2) {
@@ -1153,6 +1153,7 @@ struct task *process_chk_conn(struct task *t, void *context, unsigned int state)
                                 * foreign thread. The recipient will restore the expiration.
                                 */
                                check->state |= CHK_ST_READY;
+                               HA_ATOMIC_INC(&ha_thread_ctx[new_tid].active_checks);
                                task_unlink_wq(t);
                                t->expire = TICK_ETERNITY;
                                task_set_thread(t, new_tid);
@@ -1160,6 +1161,12 @@ struct task *process_chk_conn(struct task *t, void *context, unsigned int state)
                                TRACE_LEAVE(CHK_EV_TASK_WAKE, check);
                                return t;
                        }
+                       /* check just woke up, count it as active */
+                       _HA_ATOMIC_INC(&th_ctx->active_checks);
+               }
+               else {
+                       /* check just woke up, count it as active */
+                       _HA_ATOMIC_INC(&th_ctx->active_checks);
                }
 
                /* OK we're keeping it so this check is ours now */
@@ -1169,6 +1176,7 @@ struct task *process_chk_conn(struct task *t, void *context, unsigned int state)
                /* OK let's run, now we cannot roll back anymore */
                check->state |= CHK_ST_READY;
                activity[tid].check_started++;
+               _HA_ATOMIC_INC(&th_ctx->running_checks);
        }
 
        /* at this point, CHK_ST_SLEEPING = 0 and CHK_ST_READY = 1*/
@@ -1323,6 +1331,8 @@ struct task *process_chk_conn(struct task *t, void *context, unsigned int state)
 
        check_release_buf(check, &check->bi);
        check_release_buf(check, &check->bo);
+       _HA_ATOMIC_DEC(&th_ctx->running_checks);
+       _HA_ATOMIC_DEC(&th_ctx->active_checks);
        check->state &= ~(CHK_ST_INPROGRESS|CHK_ST_IN_ALLOC|CHK_ST_OUT_ALLOC);
        check->state &= ~CHK_ST_READY;
        check->state |= CHK_ST_SLEEPING;