[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

CLX Speed: Pretty poor

We ran some tests to see how fast CLX is, and it isn't.    Compared to
calling the X routines from C, CLX is **approximately 15 times slower**
(1500% slower).  This is running the standard CLX under CMU CommonLisp
on IBM RTs with X11R3.  My impression is the Lucid CLX is not faster (and
may be even slower).  

* Does anyone know if CLX is going to get faster?  (Please, please!) 
* Is there some way to write this code better?
* Is CLX on some other machines faster?  (I challenge you to execute this
	test yourself and see!)

We are trying to have complex objects follow the mouse around without lagging.
Below are the descriptions of the tests, the results, and then the actual
code we used in Lisp and in C.
Thanks to Dave Kosbie for running these tests!
Brad A. Myers
School of Computer Science
Carnegie Mellon University
Pittsburgh, PA  15213-3890
(412) 268-5150


Test1:  Repeatedly writing a rectangle to the window, and flushing the output
	after each call.
Test2:  This is Test1, but the flush occurs only once, at the end.
Test3:  Same as Test1, but I change the color of the rectangle on each call,
	thus forcing X to play with the GC's somehow.
Test4:	Same as Test1, but I set 10 fields of the gcontext before each write
	(they are always being set to the same value, though...).
Test5:	Same as Test1, but erases the old rectangle along the way (there is
	still one flush per move, but now there are two draw-rectangle's
	per move...).
Test6:	Same as Test5, but also sets the 10 fields of gcontext before each
	call to draw-rectangle (there are 2 calls to draw-rectangle per 
	move!).   *** This timing is closest to what we are doing now in our

The Moves/Second is the number of rectangles that can be drawn (or
drawn and erased) per second (so bigger numbers are better).
The Bytes/Move is the number of cons
cells allocated (why are there any at all?).  Only two of the tests have
been run in C so far.

					Moves/Second	Lisp/C Comparison
	Moves/Second	Bytes/Move	    in C	(moves/sec)
	------------	----------	--------------	-----------
Test1	    129.5	    32		     1860.5	   x14.37
Test2	    930.0	    32
Test3	    114.9	    40
Test4	    104.7	    64
Test5	     89.1	    80		     1465.2	   x16.44
Test6	     72.2	   144  

Here follows the Lisp code which produced these results:
;;(in-package "TEST-BAM" :nicknames '("TB") :use '("LISP"))

(defmacro finish() '(xlib:display-finish-output d))
(defmacro map() '(progn (xlib:map-window xw) (finish)))
(defmacro unmap() '(progn (xlib:unmap-window xw) (finish)))
(defmacro rect(x y w h) `(progn (xlib:draw-rectangle xw gc ,x ,y ,w ,h t)
(defmacro rect1(x y w h) `(progn (xlib:draw-rectangle xw gc ,x ,y ,w ,h nil)

(defun g()
  (setq d (xlib:open-display (machine-instance)))
  (setq s (xlib:display-default-screen d))
  (setq root (xlib:screen-root s))
  (setq black (xlib:screen-black-pixel s))
  (setq white (xlib:screen-white-pixel s))
  (setq xw (xlib:create-window :parent root :x 870 :y 450 :event-mask nil
                :width 150 :height 50 :background white :border black
                :border-width 2 :override-redirect :on))
  (setq gc (xlib:create-gcontext :drawable xw  :background white
                :foreground black :fill-style :solid))

(defun test(n &optional (gc-p nil))
  (xlib:with-gcontext (gc :foreground white) (rect 0 0 150 50))
  (let ((x 1) (y 1) (fore black))
    (rect 1 1 20 20)
    (if gc-p (lisp::gc))
        (dotimes (z n)
          (when (> (setq x (+ x 5)) 125)
                (setq x 1)
                (when (> (setq y (+ y 5)) 25)
                        (setq y 1)))
;;        (setf (xlib:gcontext-foreground gc)
;;              (setq fore (- 1 fore)))
          (rect x y 20 20)))
  (setf (xlib:gcontext-foreground gc) black)))

(defun s()
  (xlib::free-gcontext gc)

Here follows the C code which produced these results:
	to compile:  cc testbam.c -lX11

#include <stdio.h>
#include <X11/X.h>
#include <X11/Xlib.h>

extern char *getenv();

#define finish() XFlush(d)
#define map() { XMapWindow(d,xw); finish(); }
#define unmap() { XUnmapWindow(d,xw); finish(); }
#define rect1(x y w h) XFillRectangle(d,xw,gc1,x,y,w,h)
#define rect(x y w h) { XFillRectangle(d,xw,gc1,x,y,w,h); finish(); }

Display *d;
Screen *s;
Window root;
unsigned long black, white;
Window xw;
GC gc1,gc2;

XSetWindowAttributes *set_attributes()
  XSetWindowAttributes *result;

  result = (XSetWindowAttributes *)malloc(sizeof(XSetWindowAttributes));

  result->override_redirect = 1;
  result->background_pixel = white;

XGCValues *set_gc(n)
  int n;
  XGCValues *result;

  result = (XGCValues *)malloc(sizeof(XGCValues));

  result->background = ((n == 1) ? white : black);
  result->foreground = ((n == 1) ? black : white);
  result->fill_style = FillSolid;

void g()
  char *display;

  if ((display = getenv("DISPLAY")) == NULL)
	{ fprintf(stderr,"Oops! DISPLAY set to NULL!\n",display);
  if ((d = XOpenDisplay(display)) == NULL)
	{ fprintf(stderr,"Oops! Could not open display %s\n",display);
  s = XDefaultScreenOfDisplay(d);
  root = XRootWindowOfScreen(s);
  black = XBlackPixelOfScreen(s);
  white = XWhitePixelOfScreen(s);
  xw = XCreateWindow(d,root,1,1,500,500,2,0,InputOutput,CopyFromParent,
		(CWOverrideRedirect | CWBackPixel),set_attributes());
  gc1 = XCreateGC(d,xw,(GCBackground | GCForeground | GCFillStyle),set_gc(1));
  gc2 = XCreateGC(d,xw,(GCBackground | GCForeground | GCFillStyle),set_gc(2));

void test(n)
  int n;
  int x, y, count, old_x, old_y;

  old_x = old_y = x = y = 1;
  for (count=0;count<n;count++)
    {	if ((x = x+5) > 475)
	  {	x = 1;
		if ((y = y+5) > 475)
			y = 1;
/*	XSetForeground(d,gc,white);		*/
/*	XSetForeground(d,gc,black);		*/
	old_x = x;  old_y = y;

(defun s()
  (xlib::free-gcontext gc1)
  (xlib::free-gcontext gc2)

  int argc;
  char *argv[];
  int times;

  if (argc > 1) sscanf(argv[1],"%d",&times);
  if (times < 1) times = 400;
  printf("Testing for %0d times\n",times);