[hunchentoot-devel] Hunchentoot performance

vseguip at gmail.com vseguip at gmail.com
Fri Dec 21 15:58:57 UTC 2007


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í



More information about the Tbnl-devel mailing list