Hi all, First, as a disclaimer, I'm a total Lisp noobie and have been playing with it recently poking here and there. I just tried Hunchentoot and was happy to see how easy it is to use. I also tried to make some preformance benchmarks on static files and compared it with lighttpd. Unsurprisingly lighttpd beat Hunchentoot quite badly, but I see there is still a lot of improvement for hunchentoot. I did some profiling and added a specialized handler that would serve static files using the linux sendfile system call which really improved the performance. Anyway I still see plenty room for improvements and I would like to take a stab at it, so I did some profiling. I'm putting the results in the ML in case someone wants to discuss it and help me figure out whether the speed for this use case can be improved. Details about the benchmark setup follow:
Intel Dual Core 2 2.0 GHz 1 Gb Ram Ubuntu Gutsy 7.10
SBCL version: Hunchentoot version: Lighttpd version: Benchmark program: ab File: 10 mb bitmap Command: ab -n 1000 -c 20 -k http://127.0.0.1/sendfile/1.jpg
Using sendfile system call
| consed | calls | sec/call | name ----------------------------------------------------------- 0.644 | 25,410,696 | 1,002 | 0.000643 | HUNCHENTOOT::GET-REQUEST-DATA 0.453 | 197,900,328 | 6,006 | 0.000075 | HUNCHENTOOT::WRITE-HEADER-LINE 0.435 | 19,617,768 | 1,001 | 0.000435 | HUNCHENTOOT::HANDLE-STATIC-SENDFILE 0.367 | 0 | 1,001 | 0.000367 | HUNCHENTOOT::SENDTHEFILE 0.230 | 53,605,640 | 1,001 | 0.000230 | HUNCHENTOOT:LOG-MESSAGE 0.163 | 36,415,056 | 2,002 | 0.000082 | HUNCHENTOOT::START-OUTPUT ...
Using hunchentoot static folder dispatcher
| consed | calls | sec/call | name ----------------------------------------------------------- 0.678 | 165,618,816 | 5,000 | 0.000136 | HUNCHENTOOT::WRITE-HEADER-LINE 0.556 | 27,725,384 | 1,000 | 0.000556 | HUNCHENTOOT::GET-REQUEST-DATA 0.347 | 45,721,424 | 1,000 | 0.000347 | HUNCHENTOOT::START-OUTPUT 0.266 | 57,833,952 | 1,000 | 0.000266 | HUNCHENTOOT:LOG-MESSAGE 0.247 | 20,982,224 | 1,000 | 0.000247 | HUNCHENTOOT::COMPUTE-LENGTH 0.135 | 12,926,840 | 2,000 | 0.000067 | HUNCHENTOOT::FORMAT-ADDRESS 0.115 | 13,878,936 | 1,000 | 0.000115 | HUNCHENTOOT::ISO-TIME 0.082 | 237,656 | 1,000 | 0.000082 | HUNCHENTOOT::MAKE-SOCKET-STREAM 0.079 | 16,425,808 | 1,000 | 0.000079 | HUNCHENTOOT:RFC-1123-DATE ....
This is my very dirty implementation of the dispatcher function which is shameles rip of hunchentoot's with some minor functions cleaned :
(declaim (inline sendfile)) (define-alien-routine "sendfile" int (out_fd int :in) (in_fd int :in) (offset unsigned-long :in-out) (count unsigned-long :in))
(in-package :hunchentoot)
(defun handle-static-sendfile (path &optional content-type) "A function which acts like a Hunchentoot handler for the file denoted by PATH but uses the sendfile call. Send a content type header corresponding to CONTENT-TYPE or (if that is NIL) tries to determine the content type via the file's suffix." (unless (or (pathname-name path) (pathname-type path)) ;; not a file (setf (return-code) +http-bad-request+) (throw 'handler-done nil)) (unless (probe-file path) ;; does not exist (setf (return-code) +http-not-found+) (throw 'handler-done nil)) (setf (content-type) (or content-type (mime-type path) "application/octet-stream")) (with-open-file (file path :direction :input :element-type '(unsigned-byte 8) :if-does-not-exist nil) (setf (content-length) (file-length file)) (let ((out (chunga:chunked-stream-stream (flex:flexi-stream-stream *hunchentoot-stream*))) (in (sb-sys:fd-stream-fd file))) (send-headers) (force-output out) (sendthefile (sb-sys:fd-stream-fd out) in 0 (content-length)))))
(defun sendthefile (out in off size) (common-lisp-user::sendfile out in off size))
Just for reference, the sendfile dispatcher does some 350 req/s wherea hunchentoots does about 228 req/s on my machine and against 1199.41 req/s that lighttps can serve using the sendfile backend (data for a 993Kb jpg file with 20 concurrency level).
Thanks for your time, V. Seguí