Use xcb for -queryExt instead of a round-trip per extension
authorAlan Coopersmith <alan.coopersmith@oracle.com>
Sun, 3 Oct 2010 18:47:07 +0000 (11:47 -0700)
committerAlan Coopersmith <alan.coopersmith@oracle.com>
Mon, 4 Oct 2010 15:14:48 +0000 (08:14 -0700)
On a system with 30 extensions listed by xdpyinfo, truss -c
reports this saves quite a few system calls by batching the
QueryExtension requests instead of a round-trip for each one:

                      Xlib      xcb
writev                  40       11
poll                    80       22
recv                   117       29
total (*)              464      296

(*) total includes all system calls, including many not shown since
their count did not change significantly.   There was one additional
set of open/mmap/close etc. for loading the added libX11-xcb library.

Over a tcp connection, this reduced both the number of packets,
and due to tcp packet header overhead, the overall amount of data:

                      Xlib      xcb
TCP packets             93       35
TCP bytes            11554     7726

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
Reviewed-by: Jamey Sharp <jamey@minilop.net>
configure.ac
xdpyinfo.c

index 48ae434..47a1246 100644 (file)
@@ -36,7 +36,7 @@ XORG_DEFAULT_OPTIONS
 AM_CONFIG_HEADER(config.h)
 
 # Checks for pkg-config packages
-PKG_CHECK_MODULES(XDPYINFO, xext x11 xtst)
+PKG_CHECK_MODULES(XDPYINFO, xext x11 xtst x11-xcb xcb)
 
 # This is used below to allow <X11/Xlib.h> to be found
 PKG_CHECK_MODULES(DPY_X11, x11)
index db4a438..017738f 100644 (file)
@@ -82,6 +82,7 @@ in this Software without prior written authorization from The Open Group.
 
 #endif
 
+#include <X11/Xlib-xcb.h>
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #ifdef MULTIBUFFER
@@ -170,22 +171,53 @@ print_extension_info(Display *dpy)
     printf ("number of extensions:    %d\n", n);
 
     if (extlist) {
-       register int i;
-       int opcode, event, error;
+       int i;
 
        qsort(extlist, n, sizeof(char *), StrCmp);
-       for (i = 0; i < n; i++) {
-           if (!queryExtensions) {
+
+       if (!queryExtensions) {
+           for (i = 0; i < n; i++) {
                printf ("    %s\n", extlist[i]);
-               continue;
            }
-           XQueryExtension(dpy, extlist[i], &opcode, &event, &error);
-           printf ("    %s  (opcode: %d", extlist[i], opcode);
-           if (event)
-               printf (", base event: %d", event);
-           if (error)
-               printf (", base error: %d", error);
-           printf(")\n");
+       } else {
+           xcb_connection_t *xcb_conn = XGetXCBConnection (dpy);
+           xcb_query_extension_cookie_t *qe_cookies;
+
+           qe_cookies = calloc(n, sizeof(xcb_query_extension_cookie_t));
+           if (!qe_cookies) {
+               perror ("calloc failed to allocate memory for extensions");
+               return;
+           }
+
+           /*
+            * Generate all extension queries at once, so they can be
+            * sent to the xserver in a single batch
+            */
+           for (i = 0; i < n; i++) {
+               qe_cookies[i] = xcb_query_extension (xcb_conn,
+                                                    strlen(extlist[i]),
+                                                    extlist[i]);
+           }
+
+           /*
+            * Start processing replies as they come in.
+            * The first call will flush the queue to the server, then
+            * each one will wait, if needed, for its reply.
+            */
+           for (i = 0; i < n; i++) {
+               xcb_query_extension_reply_t *rep
+                   = xcb_query_extension_reply(xcb_conn, qe_cookies[i], NULL);
+
+               printf ("    %s  (opcode: %d", extlist[i], rep->major_opcode);
+               if (rep->first_event)
+                   printf (", base event: %d", rep->first_event);
+               if (rep->first_error)
+                   printf (", base error: %d", rep->first_error);
+               printf (")\n");
+
+               free (rep);
+           }
+           free (qe_cookies);
        }
        /* do not free, Xlib can depend on contents being unaltered */
        /* XFreeExtensionList (extlist); */