From alexfs04 at gmail.com Thu May 21 14:46:45 2009 From: alexfs04 at gmail.com (Anon Alex) Date: Thu, 21 May 2009 23:46:45 +0900 Subject: [cl-gd-devel] performance issue with CL-GD on SBCL, UFFI vs. CFFI Message-ID: <2c8aede00905210746u6e6dbb55v84121dba6e110a2c@mail.gmail.com> Hello, I wanted to report a performance-related issue with CL-GD and UFFI vs CFFI-UFFI-COMPAT Here is a simple function for comparing two images: As you can see, this loops over every pixel of both images, compares the R,G,B components. (defun compare-images (image1 image2) "Comapre two images -- uses API exported by CL-GD" (declare (optimize (debug 0) (speed 3)(safety 0))) ;(declare (optimize (debug 3) (speed 0))) (let ((err 0) (height (cl-gd:image-height image1)) (width (cl-gd:image-width image1))) (declare (fixnum err height width)) (format t "height1=~a, height2=~a" height width) (assert (and (= height (cl-gd:image-height image2)) (= width (cl-gd:image-width image2)))) (loop for y fixnum from 0 below height do (loop for x fixnum from 0 below width do (let ((img-color (cl-gd:get-pixel y x :image image2)) (target-color (cl-gd:get-pixel y x :image image1))) (incf err (square (- (the fixnum(cl-gd:color-component :red img-color :image image2)) (the fixnum(cl-gd:color-component :red target-color :image image1))))) (incf err (square (- (the fixnum (cl-gd:color-component :blue img-color :image image2)) (the fixnum(cl-gd:color-component :blue target-color :image image1))))) (incf err (square (- (the fixnum(cl-gd:color-component :green img-color :image image2)) (the fixnum(cl-gd:color-component :green target-color :image image1)))))))) err)) Here's another version, which uses non-exported functions to speed it up a little bit (and for benchmarking, eliminate some of the the API-level overhead) (defun compare-images-raw (image1 image2) "Compare two images -- use internal functions to eliminate overhead added by CL-GD API" (declare (optimize (debug 0) (speed 3)(safety 0))) ;(declare (optimize (debug 3) (speed 0))) (let ((err 0) (height (cl-gd:image-height image1)) (width (cl-gd:image-width image1)) (img1 (cl-gd::img image1)) (img2 (cl-gd::img image2))) (declare (fixnum err height width)) (format t "height1=~a, height2=~a" height width) (assert (and (= height (cl-gd:image-height image2)) (= width (cl-gd:image-width image2)))) (loop for y fixnum from 0 below height do (loop for x fixnum from 0 below width do (let ((img2-color (cl-gd:get-pixel y x :image image2)) (img1-color (cl-gd:get-pixel y x :image image1))) (incf err (square (- (the fixnum(cl-gd::gd-image-get-red img2 img2-color)) (the fixnum(cl-gd::gd-image-get-red img1 img1-color))))) (incf err (square (- (the fixnum(cl-gd::gd-image-get-green img2 img2-color)) (the fixnum(cl-gd::gd-image-get-green img1 img1-color))))) (incf err (square (- (the fixnum(cl-gd::gd-image-get-blue img2 img2-color)) (the fixnum(cl-gd::gd-image-get-blue img1 img1-color)))))))) err)) This is the result of running the above pair of functions on a 1024x768 image. ---- First, the timing with the standard CL-GD: (SBCL 1.0.28, CL-GD 0.5.6, UFFI-1.6.1, 3GHz Intel Core2 Duo, Linux)) CL-GD uses UFFI by default on SBCL EVO-LISA> (progn (defparameter *image1* (cl-gd:create-image-from-file "023.JPG")) (defparameter *image2* (cl-gd:create-image-from-file "023.JPG")) (time (compare-images *image1* *image2*))) height1=1024, height2=768 Evaluation took: 1.684 seconds of real time 1.688105 seconds of total run time (1.688105 user, 0.000000 system) 100.24% CPU 5,061,067,326 processor cycles 141,296 bytes consed 0 EVO-LISA> (progn (defparameter *image1* (cl-gd:create-image-from-file "023.JPG")) (defparameter *image2* (cl-gd:create-image-from-file "023.JPG")) (time (compare-images-raw *image1* *image2*))) height1=1024, height2=768 Evaluation took: 1.476 seconds of real time 1.424088 seconds of total run time (1.420088 user, 0.004000 system) 96.48% CPU 4,437,702,108 processor cycles 106,112 bytes consed 0 ----- After changing cl-gd.asd so that CFFI-UFFI-COMPAT is used for SBCL instead of UFFI: ;;;;;;;; EVO-LISA> (progn (defparameter *image1* (cl-gd:create-image-from-file "023.JPG")) (defparameter *image2* (cl-gd:create-image-from-file "023.JPG")) (time (compare-images *image1* *image2*))) height1=1024, height2=768 Evaluation took: 0.336 seconds of real time 0.336021 seconds of total run time (0.336021 user, 0.000000 system) 100.00% CPU 1,010,111,976 processor cycles 21,712 bytes consed 0 EVO-LISA> (progn (defparameter *image1* (cl-gd:create-image-from-file "023.JPG")) (defparameter *image2* (cl-gd:create-image-from-file "023.JPG")) (time (compare-images-raw *image1* *image2*))) height1=1024, height2=768 Evaluation took: 0.282 seconds of real time 0.284018 seconds of total run time (0.284018 user, 0.000000 system) 100.71% CPU 845,516,097 processor cycles 21,936 bytes consed 0 ------------ Surprisingly, there is a 5x difference between using CFFI and UFFI. Pixel-level access to an image, as provided by cl-gd:get-pixel, and cl-gd:color-component, is usually used in image processing, where cl-gd:get-pixel, and cl-gd:color-component will be called for many pixels on the image (usually the whole image), so the speed of these accessors is critical for image processing, and for some reason, CFFI (viat cffi-uffi-compat) offers 5x faster pixel level access than UFFI. I don't know much about either CFFI or UFFI, but CFFI-UFFI-COMPAT is the default already for CLISP and OpenMCL. Maybe it's worth considering making CFFI-UFFI-COMPAT the default for SBCL as well? Regards, Alex Fukunaga From edi at agharta.de Wed May 27 08:17:31 2009 From: edi at agharta.de (Edi Weitz) Date: Wed, 27 May 2009 10:17:31 +0200 Subject: [cl-gd-devel] performance issue with CL-GD on SBCL, UFFI vs. CFFI In-Reply-To: <2c8aede00905210746u6e6dbb55v84121dba6e110a2c@mail.gmail.com> References: <2c8aede00905210746u6e6dbb55v84121dba6e110a2c@mail.gmail.com> Message-ID: Thanks for the report. I myself haven't used CL-GD for quite some time and if I do I usually don't use it with SBCL, so I can't really comment on these numbers. Right now, I don't have the time to work on CL-GD myself, but you're welcome to send reasonably documented and tested patches and I'll try to make a new release ASAP although I can't promise anything. http://weitz.de/patches.html Thanks, Edi. On Thu, May 21, 2009 at 4:46 PM, Anon Alex wrote: > Hello, I wanted to report a performance-related issue with CL-GD and > UFFI vs CFFI-UFFI-COMPAT > > Here is a simple function for comparing two images: > As you can see, this loops over every pixel of both images, compares > the R,G,B components. > > (defun compare-images (image1 image2) > ?"Comapre two images -- uses API exported by CL-GD" > ?(declare (optimize (debug 0) (speed 3)(safety 0))) > ?;(declare (optimize (debug 3) (speed 0))) > ?(let ((err 0) > ? ? ? ?(height (cl-gd:image-height image1)) > ? ? ? ?(width (cl-gd:image-width image1))) > ? ?(declare (fixnum err height width)) > ? ?(format t "height1=~a, height2=~a" height width) > ? ?(assert (and (= height (cl-gd:image-height image2)) > ? ? ? ? ? ? ? ? (= width (cl-gd:image-width image2)))) > ? ?(loop for y fixnum from 0 below height do > ? ? ? ? ?(loop for x fixnum from 0 below width do > ? ? ? ? ? ? ? ?(let ((img-color (cl-gd:get-pixel y x :image image2)) > ? ? ? ? ? ? ? ? ? ? ?(target-color (cl-gd:get-pixel y x :image image1))) > ? ? ? ? ? ? ? ? ?(incf err (square (- (the fixnum(cl-gd:color-component :red > img-color :image image2)) > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (the fixnum(cl-gd:color-component :red target-color :image > image1))))) > ? ? ? ? ? ? ? ? ?(incf err (square (- (the fixnum (cl-gd:color-component :blue > img-color :image image2)) > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (the fixnum(cl-gd:color-component :blue target-color :image > image1))))) > ? ? ? ? ? ? ? ? ?(incf err (square (- (the fixnum(cl-gd:color-component :green > img-color :image image2)) > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (the fixnum(cl-gd:color-component :green target-color > :image image1)))))))) > ? ?err)) > > > Here's another version, which uses non-exported functions to speed it > up a little bit (and for benchmarking, eliminate some of the the > API-level overhead) > > (defun compare-images-raw (image1 image2) > ?"Compare two images -- use internal functions to eliminate overhead > added by CL-GD API" > ?(declare (optimize (debug 0) (speed 3)(safety 0))) > ?;(declare (optimize (debug 3) (speed 0))) > ?(let ((err 0) > ? ? ? ?(height (cl-gd:image-height image1)) > ? ? ? ?(width (cl-gd:image-width image1)) > ? ? ? ?(img1 (cl-gd::img image1)) > ? ? ? ?(img2 (cl-gd::img image2))) > ? ?(declare (fixnum err height width)) > ? ?(format t "height1=~a, height2=~a" height width) > ? ?(assert (and (= height (cl-gd:image-height image2)) > ? ? ? ? ? ? ? ? (= width (cl-gd:image-width image2)))) > ? ?(loop for y fixnum from 0 below height do > ? ? ? ? ?(loop for x fixnum from 0 below width do > ? ? ? ? ? ? ? ?(let ((img2-color (cl-gd:get-pixel y x :image image2)) > ? ? ? ? ? ? ? ? ? ? ?(img1-color (cl-gd:get-pixel y x :image image1))) > ? ? ? ? ? ? ? ? ?(incf err (square (- (the fixnum(cl-gd::gd-image-get-red img2 img2-color)) > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (the fixnum(cl-gd::gd-image-get-red img1 img1-color))))) > ? ? ? ? ? ? ? ? ?(incf err (square (- (the fixnum(cl-gd::gd-image-get-green img2 img2-color)) > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (the fixnum(cl-gd::gd-image-get-green img1 img1-color))))) > ? ? ? ? ? ? ? ? ?(incf err (square (- (the fixnum(cl-gd::gd-image-get-blue img2 img2-color)) > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (the fixnum(cl-gd::gd-image-get-blue img1 img1-color)))))))) > ? ?err)) > > > > This is the result of running the above pair of functions on a 1024x768 image. > > ---- > First, the timing with the standard CL-GD: > (SBCL 1.0.28, CL-GD 0.5.6, UFFI-1.6.1, 3GHz Intel Core2 Duo, Linux)) > > CL-GD uses UFFI by default on SBCL > > > EVO-LISA> (progn > ?(defparameter *image1* (cl-gd:create-image-from-file "023.JPG")) > ?(defparameter *image2* (cl-gd:create-image-from-file "023.JPG")) > ?(time (compare-images *image1* *image2*))) > > height1=1024, height2=768 > Evaluation took: > ?1.684 seconds of real time > ?1.688105 seconds of total run time (1.688105 user, 0.000000 system) > ?100.24% CPU > ?5,061,067,326 processor cycles > ?141,296 bytes consed > > 0 > > > EVO-LISA> (progn > ?(defparameter *image1* (cl-gd:create-image-from-file "023.JPG")) > ?(defparameter *image2* (cl-gd:create-image-from-file "023.JPG")) > ?(time (compare-images-raw *image1* *image2*))) > > height1=1024, height2=768 > Evaluation took: > ?1.476 seconds of real time > ?1.424088 seconds of total run time (1.420088 user, 0.004000 system) > ?96.48% CPU > ?4,437,702,108 processor cycles > ?106,112 bytes consed > > 0 > > ----- > > After changing cl-gd.asd so that CFFI-UFFI-COMPAT is used for SBCL > instead of UFFI: > > ;;;;;;;; > > EVO-LISA> (progn > ?(defparameter *image1* (cl-gd:create-image-from-file "023.JPG")) > ?(defparameter *image2* (cl-gd:create-image-from-file "023.JPG")) > ?(time (compare-images *image1* *image2*))) > > height1=1024, height2=768 > Evaluation took: > ?0.336 seconds of real time > ?0.336021 seconds of total run time (0.336021 user, 0.000000 system) > ?100.00% CPU > ?1,010,111,976 processor cycles > ?21,712 bytes consed > > 0 > EVO-LISA> (progn > ?(defparameter *image1* (cl-gd:create-image-from-file "023.JPG")) > ?(defparameter *image2* (cl-gd:create-image-from-file "023.JPG")) > ?(time (compare-images-raw *image1* *image2*))) > > height1=1024, height2=768 > Evaluation took: > ?0.282 seconds of real time > ?0.284018 seconds of total run time (0.284018 user, 0.000000 system) > ?100.71% CPU > ?845,516,097 processor cycles > ?21,936 bytes consed > > 0 > > ------------ > > Surprisingly, ?there is a 5x difference between using CFFI and UFFI. > > Pixel-level access to an image, as provided by > cl-gd:get-pixel, and cl-gd:color-component, is usually used in image > processing, where cl-gd:get-pixel, and cl-gd:color-component will be > called for many pixels on the image (usually the whole image), so the > speed of these accessors is critical for image processing, and > for some reason, CFFI (viat cffi-uffi-compat) offers 5x faster pixel > level access than UFFI. > > I don't know much about either CFFI or UFFI, but > CFFI-UFFI-COMPAT is the default already for CLISP and OpenMCL. > Maybe it's worth considering making CFFI-UFFI-COMPAT the default for > SBCL as well? > > > Regards, > Alex Fukunaga > > _______________________________________________ > cl-gd-devel site list > cl-gd-devel at common-lisp.net > http://common-lisp.net/mailman/listinfo/cl-gd-devel > >