sleepy_penguin RubyGem user+dev discussion/patches/pulls/bugs/help
 help / color / mirror / code / Atom feed
From: Eric Wong <normalperson@yhbt.net>
To: sleepy.penguin@librelist.org
Subject: [sleepy.penguin] [PATCH 5/6] epoll: cache alignment for per-thread structure
Date: Thu, 11 Apr 2013 04:17:34 +0000	[thread overview]
Message-ID: <1365653855-1101-6-git-send-email-normalperson@yhbt.net> (raw)
In-Reply-To: 1365653855-1101-1-git-send-email-normalperson@yhbt.net

This probably won't make a huge difference in Ruby, but perhaps
one day the unnecessary dirtying of cache lines will affect
performance (and we'll be ready when that day comes).

While we're at it, remove usage of pthread* functions for
thread-local variables.  The __thread construct from GCC (and
also implemented by clang) is much easier-to-use than the
pthread_*specific API.
---
 ext/sleepy_penguin/epoll.c | 46 +++++++++++++++++++++-------------------------
 1 file changed, 21 insertions(+), 25 deletions(-)

diff --git a/ext/sleepy_penguin/epoll.c b/ext/sleepy_penguin/epoll.c
index 64df698..70a77f6 100644
--- a/ext/sleepy_penguin/epoll.c
+++ b/ext/sleepy_penguin/epoll.c
@@ -1,14 +1,15 @@
 #include "sleepy_penguin.h"
 #include <sys/epoll.h>
-#include <pthread.h>
+#include <unistd.h>
 #include <time.h>
 #include "missing_epoll.h"
 #include "missing_rb_thread_fd_close.h"
 #include "missing_rb_update_max_fd.h"
+#define L1_CACHE_LINE_MAX 128 /* largest I've seen (Pentium 4) */
 
-static pthread_key_t epoll_key;
 static ID id_for_fd;
 static VALUE cEpoll;
+static size_t l1_cache_line_size;
 
 static uint64_t now_ms(void)
 {
@@ -56,9 +57,10 @@ static void ep_fd_check(struct ep_per_thread *ept)
 
 static struct ep_per_thread *ept_get(VALUE self, int maxevents)
 {
-	struct ep_per_thread *ept = pthread_getspecific(epoll_key);
+	static __thread struct ep_per_thread *ept;
 	size_t size;
 	int err;
+	void *ptr;
 
 	if (ept && ept->capa >= maxevents)
 		goto out;
@@ -67,14 +69,12 @@ static struct ep_per_thread *ept_get(VALUE self, int maxevents)
 	       sizeof(struct epoll_event) * maxevents;
 
 	free(ept); /* free(NULL) is POSIX and works on glibc */
-	ept = malloc(size);
-	if (ept == NULL)
-		rb_memerror();
-	err = pthread_setspecific(epoll_key, ept);
-	if (err != 0) {
+	err = posix_memalign(&ptr, l1_cache_line_size, size);
+	if (err) {
 		errno = err;
-		rb_sys_fail("pthread_setspecific");
+		rb_memerror();
 	}
+	ept = ptr;
 	ept->capa = maxevents;
 out:
 	ept->maxevents = maxevents;
@@ -230,32 +230,28 @@ static VALUE epwait(int argc, VALUE *argv, VALUE self)
 	return real_epwait(ept);
 }
 
-static void epoll_once(void)
-{
-	int err = pthread_key_create(&epoll_key, free);
-
-	if (err) {
-		errno = err;
-		rb_sys_fail("pthread_key_create");
-	}
-}
-
 /* :nodoc: */
 static VALUE event_flags(VALUE self, VALUE flags)
 {
 	return UINT2NUM(rb_sp_get_uflags(self, flags));
 }
 
+static size_t l1_cache_line_size_detect(void)
+{
+#ifdef _SC_LEVEL1_DCACHE_LINESIZE
+	long tmp = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
+
+	if (tmp > 0 && tmp <= L1_CACHE_LINE_MAX)
+		return (size_t)tmp;
+#endif /* _SC_LEVEL1_DCACHE_LINESIZE */
+	return L1_CACHE_LINE_MAX;
+}
+
 void sleepy_penguin_init_epoll(void)
 {
 	VALUE mSleepyPenguin, cEpoll_IO;
-	static pthread_once_t once = PTHREAD_ONCE_INIT;
-	int err = pthread_once(&once, epoll_once);
 
-	if (err) {
-		errno = err;
-		rb_sys_fail("pthread_once(.., epoll_once)");
-	}
+	l1_cache_line_size = l1_cache_line_size_detect();
 
 	/*
 	 * Document-module: SleepyPenguin
-- 
1.8.2.279.g631bc94



  parent reply	other threads:[~2013-04-11  4:18 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-04-11  4:17 [sleepy.penguin] [PATCH 0/6] epoll wrapper cleanups Eric Wong
2013-04-11  4:17 ` [sleepy.penguin] [PATCH 1/6] test_epoll: fix timing error in test Eric Wong
2013-04-11  4:17 ` [sleepy.penguin] [PATCH 2/6] test_epoll: synchronize writes to the pipe array Eric Wong
2013-04-11  4:17 ` [sleepy.penguin] [PATCH 3/6] split Epoll and Epoll::IO, rewrite Epoll in Ruby Eric Wong
2013-04-12 20:38   ` Eric Wong
2013-04-11  4:17 ` [sleepy.penguin] [PATCH 4/6] epoll: implement thread-safety for mark/flag arrays Eric Wong
2013-04-12 21:18   ` Eric Wong
2013-04-11  4:17 ` Eric Wong [this message]
2013-04-11  4:17 ` [sleepy.penguin] [PATCH 6/6] avoid ENOMEM checking in common code paths Eric Wong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://yhbt.net/sleepy_penguin/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1365653855-1101-6-git-send-email-normalperson@yhbt.net \
    --to=normalperson@yhbt.net \
    --cc=sleepy.penguin@librelist.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://yhbt.net/sleepy_penguin.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).