Hi,

I wrote a new patch to fix the performance problem of kqueue. I made some tests to measure the performance. Unfortunately I don't have a BSD system so I used a qemu installation of NetBSD 2.0.2.

Summary:
----------------

Poll:
Requests per second:    231.18 [#/sec] (mean)
Time per request:       43.256 [ms] (mean)
Time per request:       4.326 [ms] (mean, across all concurrent requests)
Transfer rate:          366.03 [Kbytes/sec] received

Kqueue:
Requests per second:    467.39 [#/sec] (mean)
Time per request:       21.395 [ms] (mean)
Time per request:       2.140 [ms] (mean, across all concurrent requests)
Transfer rate:          753.06 [Kbytes/sec] received


Good news, aren't they?

Sébastien, can you please test this patch in Mac OS X?

Any other feedback would be appreciated.

Best regards,
Rodrigo


Cherokee with poll:
---------------------------------

# ab -n 10000 -c 10 http://netbsd/index.html
This is ApacheBench, Version 2.0.41-dev <$Revision: 1.141 $> apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/

Benchmarking netbsd (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Finished 10000 requests


Server Software:        Cherokee/0.4.28
Server Hostname:        netbsd
Server Port:            80

Document Path:          /index.html
Document Length:        1421 bytes

Concurrency Level:      10
Time taken for tests:   43.255519 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      16213242 bytes
HTML transferred:       14212842 bytes
Requests per second:    231.18 [#/sec] (mean)
Time per request:       43.256 [ms] (mean)
Time per request:       4.326 [ms] (mean, across all concurrent requests)
Transfer rate:          366.03 [Kbytes/sec] received

Connection Times (ms)
             min  mean[+/-sd] median   max
Connect:        1   16   9.2     15     276
Processing:     5   26  19.3     19     442
Waiting:        4   19  13.3     17     404
Total:         10   42  23.1     35     460

Percentage of the requests served within a certain time (ms)
 50%     35
 66%     44
 75%     47
 80%     49
 90%     63
 95%     74
 98%     98
 99%    121
100%    460 (longest request)


Cherokee with kqueue (patch applied):
------------------------------------------------------------------

# ab -k -n 10000 -c 10 http://netbsd/index.html
This is ApacheBench, Version 2.0.41-dev <$Revision: 1.141 $> apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/

Benchmarking netbsd (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Finished 10000 requests


Server Software:        Cherokee/0.4.28
Server Hostname:        netbsd
Server Port:            80

Document Path:          /index.html
Document Length:        1421 bytes

Concurrency Level:      10
Time taken for tests:   21.395272 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Keep-Alive requests:    9987
Total transferred:      16499333 bytes
HTML transferred:       14210000 bytes
Requests per second:    467.39 [#/sec] (mean)
Time per request:       21.395 [ms] (mean)
Time per request:       2.140 [ms] (mean, across all concurrent requests)
Transfer rate:          753.06 [Kbytes/sec] received

Connection Times (ms)
             min  mean[+/-sd] median   max
Connect:        0    0   0.5      0      29
Processing:     3   20  11.3     20     261
Waiting:        3   20  11.1     20     261
Total:          3   20  11.3     20     261

Percentage of the requests served within a certain time (ms)
 50%     20
 66%     20
 75%     20
 80%     20
 90%     21
 95%     22
 98%     28
 99%     38
100%    261 (longest request)

--- cherokee-0.4.29.old/cherokee/fdpoll-kqueue.c	2005-09-19 17:44:20.000000000 +0100
+++ cherokee-0.4.29/cherokee/fdpoll-kqueue.c	2005-11-11 14:09:19.000000000 +0000
@@ -61,7 +61,7 @@
 	int                    kqueue;
 	struct kevent          *changelist;
 	int                    *fdevents;
-	int                    *idx_fd_chlist;
+	int                    *fdinterest;
 	size_t                 nchanges;
 } cherokee_fdpoll_kqueue_t;
 
@@ -71,12 +71,13 @@
 _free (cherokee_fdpoll_kqueue_t *fdp)
 {
 	close( fdp->kqueue );
+
 	free( fdp->changelist );
 	free( fdp->fdevents );
-	free( fdp->idx_fd_chlist );
+	free( fdp->fdinterest );
 	
 	free( fdp );
-        return ret_ok;	   
+        return ret_ok;
 }
 
 
@@ -86,25 +87,13 @@
 	int index;
 	struct kevent *event;
 
-	index = fdp->idx_fd_chlist[fd];
-	if ( index == -1 ) {
-		/* fd not in changelist 
-		 */
-		index = fdp->nchanges;
-		if ( index > FDPOLL(fdp)->nfiles) {
-			PRINT_ERROR ("ERROR: Maximum number of fd exeeded\n");
-			return ret_error;
-		}
-		fdp->idx_fd_chlist[fd] = index;
-		fdp->nchanges++;
-
+	index = fdp->nchanges;
+	if (index >= FDPOLL(fdp)->nfiles) {
+		return ret_error;
 	}
-	
-	event = &fdp->changelist[index];
 
-	memset(event, 0, sizeof(struct kevent));
+	event = &fdp->changelist[index];
 	event->ident = fd;
-	event->flags = change;
 	switch (rw) {
 	case 0:
 		event->filter = EVFILT_READ;
@@ -115,6 +104,11 @@
 	default:
 		SHOULDNT_HAPPEN;
         }
+	event->flags = change;
+	event->fflags = 0;
+
+	fdp->fdinterest[fd]=rw;
+	fdp->nchanges++;
 	return ret_ok;
 }
 
@@ -122,26 +116,26 @@
 _add (cherokee_fdpoll_kqueue_t *fdp, int fd, int rw)
 {
 	int re;
-
-	re = _add_change( fdp, fd, rw, EV_ADD|EV_ENABLE );
+	
+	re = _add_change( fdp, fd, rw, EV_ADD);
 	if ( re == ret_ok) {
 		FDPOLL(fdp)->npollfds++;
 	}
-
+	
 	return re;
 }
 
 static ret_t
 _del (cherokee_fdpoll_kqueue_t *fdp, int fd)
 {
-	int re;
-
-	re = _add_change( fdp, fd, 0, EV_DELETE|EV_DISABLE );
-	if ( re == ret_ok) {
-		FDPOLL(fdp)->npollfds--;
-	}
-
-	return re;
+       int re;
+	       
+       re = _add_change( fdp, fd, fdp->fdinterest[fd], EV_DELETE);
+       if ( re == ret_ok) {
+	       FDPOLL(fdp)->npollfds--;
+       }
+       
+       return re;
 }
 
 static int
@@ -158,8 +152,6 @@
 	/* Get the events of the file descriptors with
 	 * activity
 	 */
-	memset(fdp->idx_fd_chlist, -1, sizeof(int)*FDPOLL(fdp)->system_nfiles);
-
 	n_events = kevent(fdp->kqueue, 
 			  fdp->changelist, 
 			  fdp->nchanges,
@@ -191,13 +183,13 @@
 _check (cherokee_fdpoll_kqueue_t *fdp, int fd, int rw)
 {
 	uint32_t events;
-
+	
 	/* Sanity check: is it a wrong fd?
 	 */
 	if ( fd < 0 ) return -1;
-
+	
 	events = fdp->fdevents[fd];
-
+	
 	switch (rw) {
 	case 0:
 		events &= KQUEUE_READ_EVENT;
@@ -208,8 +200,7 @@
 	default:
 		SHOULDNT_HAPPEN;
 	}
-
-
+	
 	return events;
 }
 
@@ -224,47 +215,16 @@
 static void
 _set_mode (cherokee_fdpoll_kqueue_t *fdp, int fd, int rw)
 {
-
- 	if ( ( rw && (fdp->fdevents[fd] == KQUEUE_READ_EVENT ) ) ||
- 	     ( (!rw) && (fdp->fdevents[fd] == KQUEUE_WRITE_EVENT) ) ) {
-		/* If transitioning from r -> w or from w -> r 
-		 * clear any active event on the fd as we are
-		 * no longer interested on it.
-		 */
-		int n_events;
-		struct kevent changelist[1];
-		struct timespec timeout;
-		
-		memset(&changelist[0], 0, sizeof(struct kevent));
-		changelist[0].ident = fd;
-		if ( fdp->fdevents[fd] == KQUEUE_READ_EVENT ) {
-			changelist[0].filter = EVFILT_READ;
-		} else {
-			/* fdp->fdevents[fd] == KQUEUE_WRITE_EVENT
-			 */
-			changelist[0].filter = EVFILT_WRITE;
-		}
-		changelist[0].flags = EV_DELETE;
-
-		memset(&timeout, 0, sizeof(struct timespec));
-		/* Update the kqueue fd list without sleeping (zeroed timeout)
-		 */
-		n_events = kevent(fdp->kqueue,
-				  &changelist[0],
-				  1,
-				  NULL,
-				  0,
-				  &timeout);
-		/* Clear previous events if any
-		 */
-		fdp->fdevents[fd] = 0; 
-		if ( n_events < 0 ) {
-			PRINT_ERROR("ERROR: fd %d: kevent %s\n", fd, 
-				    strerror(errno));
-		}
+	/* If transitioning from r -> w or from w -> r
+	 * disable any active event on the fd as we are
+	 * no longer interested on it.
+	 */
+	if ( rw && (fdp->fdinterest[fd] == 0) ) {
+		_add_change(fdp, fd, 0, EV_DELETE);
+	} else if ( (rw==0 ) && (fdp->fdinterest[fd] == 1) ) {
+		_add_change(fdp, fd, 1, EV_DELETE);
 	}
 
-
 	_add_change( fdp, fd, rw, EV_ADD );
 }
 
@@ -296,18 +256,17 @@
 	/* Init kqueue specific variables
 	 */
 	n->nchanges        = 0;
-	n->changelist      = ( struct kevent *)malloc(sizeof(struct kevent)*
+	n->changelist      = ( struct kevent *)malloc(sizeof(struct kevent)*2*
 						      nfd->nfiles);
 	n->fdevents        = (int *)malloc(sizeof(int) * nfd->system_nfiles);
-	n->idx_fd_chlist   = (int *)malloc(sizeof(int) * nfd->system_nfiles);
+	n->fdinterest      = (int *)malloc(sizeof(int) * nfd->system_nfiles);
 
-	if ( (!n->fdevents) ||(!n->changelist) || (!n->idx_fd_chlist) ) {
+	if ( (!n->fdevents) || (!n->changelist) || (!n->fdinterest) ) {
 		_free( n );
 		return ret_nomem;
 	}
 
 	memset(n->fdevents, 0, sizeof(int)*nfd->system_nfiles);
-	memset(n->idx_fd_chlist, 0, sizeof(int)*nfd->system_nfiles);
 
 	if ( (n->kqueue = kqueue()) == -1 ) {
 		_free( n );
_______________________________________________
Cherokee mailing list
Cherokee@lists.alobbs.com
http://www.alobbs.com/cgi-bin/mailman/listinfo/cherokee

Reply via email to