From: Willy Tarreau Date: Sat, 5 Jul 2008 16:16:19 +0000 (+0200) Subject: [OPTIM] task_queue: assume most consecutive timers are equal X-Git-Tag: v1.3.16-rc1~243 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ce44f12c1eec516812220bb523ff3a97efe5e1a4;p=thirdparty%2Fhaproxy.git [OPTIM] task_queue: assume most consecutive timers are equal When queuing a timer, it's very likely that an expiration date is equal to that of the previously queued timer, due to time rounding to the millisecond. Optimizing for this case provides a noticeable 1% performance boost. --- diff --git a/include/proto/task.h b/include/proto/task.h index de50cbab39..cc5c180f4e 100644 --- a/include/proto/task.h +++ b/include/proto/task.h @@ -35,6 +35,7 @@ extern unsigned int run_queue; /* run queue size */ extern unsigned int niced_tasks; /* number of niced tasks in the run queue */ extern struct pool_head *pool2_task; +extern struct task *last_timer; /* optimization: last queued timer */ /* perform minimal initializations, report 0 in case of error, 1 if OK. */ int init_task(); @@ -63,11 +64,23 @@ static inline struct task *task_sleep(struct task *t) * - wait queue * A pointer to the task itself is returned. */ -static inline struct task *task_delete(struct task *t) +static inline struct task *task_dequeue(struct task *t) { - if (t->eb.node.leaf_p) + if (likely(t->eb.node.leaf_p)) { + if (last_timer == t) + last_timer = NULL; eb32_delete(&t->eb); + } + return t; +} +/* + * Unlinks the task and adjusts run queue stats. + * A pointer to the task itself is returned. + */ +static inline struct task *task_delete(struct task *t) +{ + task_dequeue(t); if (t->state == TASK_RUNNING) { run_queue--; if (likely(t->nice)) diff --git a/src/task.c b/src/task.c index b28ae0b031..13d6817efc 100644 --- a/src/task.c +++ b/src/task.c @@ -25,6 +25,7 @@ struct pool_head *pool2_task; unsigned int run_queue = 0; unsigned int niced_tasks = 0; /* number of niced tasks in the run queue */ +struct task *last_timer = NULL; /* optimization: last queued timer */ /* Principle of the wait queue. * @@ -136,8 +137,7 @@ struct task *task_wakeup(struct task *t) if (t->state == TASK_RUNNING) return t; - if (likely(t->eb.node.leaf_p)) - eb32_delete(&t->eb); + task_dequeue(t); run_queue++; t->eb.key = ++rqueue_ticks; @@ -180,7 +180,18 @@ struct task *task_queue(struct task *task) /* we're queuing too far away or in the past (most likely) */ return task; #endif + + if (likely(last_timer && + last_timer->eb.key == task->eb.key && + last_timer->eb.node.node_p)) { + /* Most often, last queued timer has the same expiration date, so + * if it's not queued at the root, let's queue a dup directly there. + */ + eb_insert_dup(&last_timer->eb.node, &task->eb.node); + return task; + } eb32_insert(&timers[ticks_to_tree(task->eb.key)], &task->eb); + last_timer = task; return task; } @@ -280,7 +291,7 @@ void process_runnable_tasks(struct timeval *next) if (likely(t->nice)) niced_tasks--; t->state = TASK_IDLE; - eb32_delete(&t->eb); + task_dequeue(t); t->process(t, &temp); tv_bound(next, &temp);