]> git.ipfire.org Git - thirdparty/haproxy.git/commit
MEDIUM: task: don't grab the WR lock just to check the WQ
authorWilly Tarreau <w@1wt.eu>
Tue, 28 May 2019 16:57:25 +0000 (18:57 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 28 May 2019 17:15:44 +0000 (19:15 +0200)
commit1e928c074b68fd2b065f83896ddadcafc0a8cbed
tree235531c1b3383a12f11ca3b0bbb4ff2deb98da58
parentef28dc11e3063dc611c4c60b5d9e9c9d964259c0
MEDIUM: task: don't grab the WR lock just to check the WQ

When profiling locks, it appears that the WQ's lock has become the most
contended one, despite the WQ being split by thread. The reason is that
each thread takes the WQ lock before checking if it it does have something
to do. In practice the WQ almost only contains health checks and rare tasks
that can be scheduled anywhere, so this is a real waste of resources.

This patch proceeds differently. Now that the WQ's lock was turned to RW
lock, we proceed in 3 phases :
  1) locklessly check for the queue's emptiness

  2) take an R lock to retrieve the first element and check if it is
     expired. This way most visits are performed with an R lock to find
     and return the next expiration date.

  3) if one expiration is found, we perform the WR-locked lookup as
     usual.

As a result, on a one-minute test involving 8 threads and 64 streams at
1.3 million ctxsw/s, before this patch the lock profiler reported this :

    Stats about Lock TASK_WQ:
         # write lock  : 1125496
         # write unlock: 1125496 (0)
         # wait time for write     : 263.143 msec
         # wait time for write/lock: 233.802 nsec
         # read lock   : 0
         # read unlock : 0 (0)
         # wait time for read      : 0.000 msec
         # wait time for read/lock : 0.000 nsec

And after :

    Stats about Lock TASK_WQ:
         # write lock  : 173
         # write unlock: 173 (0)
         # wait time for write     : 0.018 msec
         # wait time for write/lock: 103.988 nsec
         # read lock   : 1072706
         # read unlock : 1072706 (0)
         # wait time for read      : 60.702 msec
         # wait time for read/lock : 56.588 nsec

Thus the contention was divided by 4.3.
src/task.c