]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: tasks: add a mask of the queues with active tasklets
authorWilly Tarreau <w@1wt.eu>
Wed, 24 Jun 2020 07:39:48 +0000 (09:39 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 24 Jun 2020 10:21:26 +0000 (12:21 +0200)
It is neither convenient nor scalable to check each and every tasklet
queue to figure whether it's empty or not while we often need to check
them all at once. This patch introduces a tasklet class mask which gets
a bit 1 set for each queue representing one class of service. A single
test on the mask allows to figure whether there's still some work to be
done. It will later be usable to better factor the runqueue code.

Bits are set when tasklets are queued. They're cleared when queues are
emptied. It is possible that a queue is empty but has a bit if a tasklet
was added then removed, but this is not a problem as this is properly
checked for in run_tasks_from_list().

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

index 334547bc26e7d33871b500404f16bf52993460b1..88f2bdd945cffe096a94a934c224a95cc53329a0 100644 (file)
@@ -78,6 +78,7 @@ struct task_per_thread {
        int rqueue_size;        /* Number of elements in the per-thread run queue */
        struct task *current;   /* current task (not tasklet) */
        int current_queue;      /* points to current tasklet list being run, -1 if none */
+       uint8_t tl_class_mask;  /* bit mask of non-empty tasklets classes */
        __attribute__((aligned(64))) char end[0];
 };
 
index acfa2c37fdb5b9e209c63a5258e95d3371411cc4..3a56acd7a50fc2e282fec8c916e76731fa2e72fc 100644 (file)
@@ -166,9 +166,7 @@ static inline int thread_has_tasks(void)
 {
        return (!!(global_tasks_mask & tid_bit) |
                (sched->rqueue_size > 0) |
-               !LIST_ISEMPTY(&sched->tasklets[TL_URGENT]) |
-               !LIST_ISEMPTY(&sched->tasklets[TL_NORMAL]) |
-               !LIST_ISEMPTY(&sched->tasklets[TL_BULK])   |
+               !!sched->tl_class_mask |
                !MT_LIST_ISEMPTY(&sched->shared_tasklet_list));
 }
 
@@ -330,16 +328,20 @@ static inline void tasklet_wakeup(struct tasklet *tl)
                if (LIST_ISEMPTY(&tl->list)) {
                        if (tl->state & TASK_SELF_WAKING) {
                                LIST_ADDQ(&sched->tasklets[TL_BULK], &tl->list);
+                               sched->tl_class_mask |= 1 << TL_BULK;
                        }
                        else if ((struct task *)tl == sched->current) {
                                _HA_ATOMIC_OR(&tl->state, TASK_SELF_WAKING);
                                LIST_ADDQ(&sched->tasklets[TL_BULK], &tl->list);
+                               sched->tl_class_mask |= 1 << TL_BULK;
                        }
                        else if (sched->current_queue < 0) {
                                LIST_ADDQ(&sched->tasklets[TL_URGENT], &tl->list);
+                               sched->tl_class_mask |= 1 << TL_URGENT;
                        }
                        else {
                                LIST_ADDQ(&sched->tasklets[sched->current_queue], &tl->list);
+                               sched->tl_class_mask |= 1 << sched->current_queue;
                        }
 
                        _HA_ATOMIC_ADD(&tasks_run_queue, 1);
index 1bb2ce416456f6d99895d62e844a4f0b4f4cdaf6..d6bda26d615426e17e0c7e587cc13fc0ab5fce45 100644 (file)
@@ -452,17 +452,17 @@ void process_runnable_tasks()
        max[TL_URGENT] = max[TL_NORMAL] = max[TL_BULK] = 0;
 
        /* urgent tasklets list gets a default weight of ~50% */
-       if (!LIST_ISEMPTY(&tt->tasklets[TL_URGENT]) ||
+       if ((tt->tl_class_mask & (1 << TL_URGENT)) ||
            !MT_LIST_ISEMPTY(&tt->shared_tasklet_list))
                max[TL_URGENT] = default_weights[TL_URGENT];
 
        /* normal tasklets list gets a default weight of ~37% */
-       if (!LIST_ISEMPTY(&tt->tasklets[TL_NORMAL]) ||
+       if ((tt->tl_class_mask & (1 << TL_NORMAL)) ||
            (sched->rqueue_size > 0) || (global_tasks_mask & tid_bit))
                max[TL_NORMAL] = default_weights[TL_NORMAL];
 
        /* bulk tasklets list gets a default weight of ~13% */
-       if (!LIST_ISEMPTY(&tt->tasklets[TL_BULK]))
+       if ((tt->tl_class_mask & (1 << TL_BULK)))
                max[TL_BULK] = default_weights[TL_BULK];
 
        /* Now compute a fair share of the weights. Total may slightly exceed
@@ -530,6 +530,7 @@ void process_runnable_tasks()
                LIST_INIT(&((struct tasklet *)t)->list);
                /* And add it to the local task list */
                tasklet_insert_into_tasklet_list(&tt->tasklets[TL_NORMAL], (struct tasklet *)t);
+               tt->tl_class_mask |= 1 << TL_NORMAL;
                tt->task_list_size++;
                activity[tid].tasksw++;
        }
@@ -544,8 +545,11 @@ void process_runnable_tasks()
         * main list.
         */
        tmp_list = MT_LIST_BEHEAD(&tt->shared_tasklet_list);
-       if (tmp_list)
+       if (tmp_list) {
                LIST_SPLICE_END_DETACHED(&tt->tasklets[TL_URGENT], (struct list *)tmp_list);
+               if (!LIST_ISEMPTY(&tt->tasklets[TL_URGENT]))
+                       tt->tl_class_mask |= 1 << TL_URGENT;
+       }
 
        /* execute tasklets in each queue */
        for (queue = 0; queue < TL_CLASSES; queue++) {
@@ -553,6 +557,8 @@ void process_runnable_tasks()
                        tt->current_queue = queue;
                        max_processed -= run_tasks_from_list(&tt->tasklets[queue], max[queue]);
                        tt->current_queue = -1;
+                       if (LIST_ISEMPTY(&tt->tasklets[queue]))
+                               tt->tl_class_mask &= ~(1 << queue);
                }
        }
 
@@ -560,9 +566,7 @@ void process_runnable_tasks()
        if (max_processed > 0 && thread_has_tasks())
                goto not_done_yet;
 
-       if (!LIST_ISEMPTY(&sched->tasklets[TL_URGENT]) |
-           !LIST_ISEMPTY(&sched->tasklets[TL_NORMAL]) |
-           !LIST_ISEMPTY(&sched->tasklets[TL_BULK]))
+       if (tt->tl_class_mask)
                activity[tid].long_rq++;
 }