Skip to content
This repository has been archived by the owner on May 4, 2018. It is now read-only.

Commit

Permalink
unix: speed up uv_async_send() some more
Browse files Browse the repository at this point in the history
Use atomic compare-and-swap to detect if we've been preempted by another thread
and therefore can avoid making the expensive write() syscall.

Speeds up the heavily contended case by about 1-2% and has little if any impact
on the non-contended case. I wasn't able to measure the difference at any rate.
  • Loading branch information
bnoordhuis committed Jul 2, 2012
1 parent a2204ab commit 3d9c1eb
Showing 1 changed file with 11 additions and 1 deletion.
12 changes: 11 additions & 1 deletion src/unix/async.c
Expand Up @@ -53,7 +53,17 @@ int uv_async_send(uv_async_t* handle) {
if (handle->pending)

This comment has been minimized.

Copy link
@Keno

Keno Jul 2, 2012

Contributor

I may be wrong here, but shouldn't this go into the #else part below?

This comment has been minimized.

Copy link
@bnoordhuis

bnoordhuis Jul 2, 2012

Author Contributor

No, this is the cheap check.

The CAS check is more expensive but catches contention, i.e. two threads simultaneously calling uv_async_send() on the same handle. It still works if your gcc doesn't support atomic operations, it'll just be a little slower because it makes more syscalls.

Try the async_pummel_* benchmarks with and without this check. There's a pretty big performance difference, about 12%.

This comment has been minimized.

Copy link
@Keno

Keno Jul 2, 2012

Contributor

Ah, thanks for the explanation. I just saw the commit and was wondering whether that was right. Makes sense though.

return 0;

handle->pending = 1; /* XXX needs a memory barrier? */
/* Micro-optimization: use atomic compare-and-swap to detect if we've been
* preempted by another thread and don't have to make an expensive syscall.
* This speeds up the heavily contended case by about 1-2% and has little
* if any impact on the non-contended case.
*/
#if __GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 1 /* gcc >= 4.1 */
if (__sync_val_compare_and_swap(&handle->pending, 0, 1))
return 0;
#else
handle->pending = 1;
#endif

do
r = write(handle->loop->async_pipefd[1], "x", 1);
Expand Down

0 comments on commit 3d9c1eb

Please sign in to comment.