From mboxrd@z Thu Jan 1 00:00:00 1970 Path: main.gmane.org!not-for-mail From: Ami Fischman Newsgroups: gmane.emacs.devel Subject: Re: [patch] cache color info for remote X sessions [Was: Emacs 21/X11 generating unbelieveable network traffic] Date: Mon, 07 Oct 2002 09:49:34 -0700 Sender: emacs-devel-admin@gnu.org Message-ID: References: <20021006012932.GA9183@gnu.org> <200210071453.g97Erqu24465@rum.cs.yale.edu> <200210071552.g97Fqoq25121@rum.cs.yale.edu> NNTP-Posting-Host: localhost.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: main.gmane.org 1034009550 12741 127.0.0.1 (7 Oct 2002 16:52:30 GMT) X-Complaints-To: usenet@main.gmane.org NNTP-Posting-Date: Mon, 7 Oct 2002 16:52:30 +0000 (UTC) Return-path: Original-Received: from quimby.gnus.org ([80.91.224.244]) by main.gmane.org with esmtp (Exim 3.35 #1 (Debian)) id 17yb7M-0003JL-00 for ; Mon, 07 Oct 2002 18:52:28 +0200 Original-Received: from monty-python.gnu.org ([199.232.76.173]) by quimby.gnus.org with esmtp (Exim 3.12 #1 (Debian)) id 17ybuV-0002kg-00 for ; Mon, 07 Oct 2002 19:43:16 +0200 Original-Received: from localhost ([127.0.0.1] helo=monty-python.gnu.org) by monty-python.gnu.org with esmtp (Exim 4.10) id 17yb59-0005eQ-00; Mon, 07 Oct 2002 12:50:11 -0400 Original-Received: from list by monty-python.gnu.org with tmda-scanned (Exim 4.10) id 17yb4k-0005M4-00 for emacs-devel@gnu.org; Mon, 07 Oct 2002 12:49:46 -0400 Original-Received: from mail by monty-python.gnu.org with spam-scanned (Exim 4.10) id 17yb4g-0005JS-00 for emacs-devel@gnu.org; Mon, 07 Oct 2002 12:49:45 -0400 Original-Received: from main.gmane.org ([80.91.224.249]) by monty-python.gnu.org with esmtp (Exim 4.10) id 17yb4g-0005J9-00 for emacs-devel@gnu.org; Mon, 07 Oct 2002 12:49:42 -0400 Original-Received: from list by main.gmane.org with local (Exim 3.35 #1 (Debian)) id 17yb48-000388-00 for ; Mon, 07 Oct 2002 18:49:08 +0200 Original-To: emacs-devel@gnu.org X-Injected-Via-Gmane: http://gmane.org/ Original-Received: from news by main.gmane.org with local (Exim 3.35 #1 (Debian)) id 17yb43-00037V-00 for ; Mon, 07 Oct 2002 18:49:03 +0200 Original-Path: not-for-mail Original-Lines: 482 Original-NNTP-Posting-Host: 12-228-169-213.client.attbi.com Original-X-Trace: main.gmane.org 1034009343 9638 12.228.169.213 (7 Oct 2002 16:49:03 GMT) Original-X-Complaints-To: usenet@main.gmane.org Original-NNTP-Posting-Date: Mon, 7 Oct 2002 16:49:03 +0000 (UTC) Mail-Copies-To: nobody User-Agent: Gnus/5.090008 (Oort Gnus v0.08) Emacs/21.2.50 (i686-pc-linux-gnu) Cancel-Lock: sha1:B5AnpVvN7wjQZsz+8i0mKiNKmos= Errors-To: emacs-devel-admin@gnu.org X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.0.11 Precedence: bulk List-Help: List-Post: List-Subscribe: , List-Id: Emacs development discussions. List-Unsubscribe: , List-Archive: Xref: main.gmane.org gmane.emacs.devel:8448 X-Report-Spam: http://spam.gmane.org/gmane.emacs.devel:8448 --=-=-= "Stefan Monnier" writes: [...] > As someone whose colormap is full about 95% of the time, I can > assure you that tose things happen ;-) Really? I guess I've been spoiled by my video card (which is a not very respectable 4M matrox) and more respectable lack of use of colors :) The shame of not caching the XFreeColors has caught up with me, so I added a refcount and a wrapper for XFreeColors that takes advantage of the refcount (so the X server only sees the Free request once per cached color, and upon final Free'ing, the cache entry is removed). This ensures there are no stale entries in the cache. The performance hit is negligible in my tests. The newest versions of xcache.[ch] reflect: - Reformatted function calls to K&R style - Added a lot of comments to explain what's going on - Added refcounting & XFreeColors caching Note that in order to take advantage of the XFreeColors caching, you need to add the xcache.h header to other files. Included is also a patch that does that. -- Ami Fischman usenet@fischman.org --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=add-xcache.patch Index: xfaces.c =================================================================== RCS file: /cvsroot/emacs/emacs/src/xfaces.c,v retrieving revision 1.264 diff -r1.264 xfaces.c 587a588,592 > > #ifdef USE_XCACHE > #include "xcache.h" > #endif /* USE_XCACHE */ > Index: xfns.c =================================================================== RCS file: /cvsroot/emacs/emacs/src/xfns.c,v retrieving revision 1.562 diff -r1.562 xfns.c 121a122,125 > #ifdef USE_XCACHE > #include "xcache.h" > #endif /* USE_XCACHE */ > Index: xrdb.c =================================================================== RCS file: /cvsroot/emacs/emacs/src/xrdb.c,v retrieving revision 1.48 diff -r1.48 xrdb.c 68a69,72 > #ifdef USE_XCACHE > #include "xcache.h" > #endif /* USE_XCACHE */ > Index: xterm.h =================================================================== RCS file: /cvsroot/emacs/emacs/src/xterm.h,v retrieving revision 1.136 diff -r1.136 xterm.h 36c36,39 < #endif --- > #ifdef USE_XCACHE > #include "xcache.h" > #endif /* USE_XCACHE */ > #endif /* USE_X_TOOLKIT */ --=-=-= Content-Disposition: attachment; filename=xcache.h /* The xcache structure allows caching of arbitrary information. We use it to save color and font information so that the X server doesn't need to be queried more than once for the same question. */ #ifndef XCACHE_H_INCLUDED #define XCACHE_H_INCLUDED #ifdef USE_XCACHE #include #include #include #include #ifdef USE_XLOG #include #include #include #define TIMELOG(extra) do { \ timerlog(__FILE__, __LINE__, extra); \ } while (0); void timerlog(char *s, unsigned int c, char *extra); #else #define TIMELOG(extra) do { ; } while(0); #endif /* USE_XLOG */ #ifndef XCACHE_C /* So that the real calls don't get messed up */ #define XAllocColor xcache_AllocColor /* #define XListFonts xcache_ListFonts */ /* #define XListQueryFonts xcache_ListQueryFonts NOT DONE YET! */ /* #define XGetFontProperty xcache_GetFontProperty NOT DONE YET! */ #define XQueryColor xcache_QueryColor #define XQueryColors xcache_QueryColors #define XFreeColors xcache_FreeColors #endif /* ! XCACHE_C */ Status xcache_AllocColor(Display *display, Colormap colormap, XColor *screen_in_out); char **xcache_ListFonts(Display *display, char *pattern, int maxnames, int *actual_count_return); /* XFontStruct *xcache_LoadQueryFont(Display *display, char *name); */ /* Bool xcache_GetFontProperty(XFontStruct *f, Atom atom, unsigned long *ret_val); */ void xcache_QueryColor(Display *display, Colormap colormap, XColor *xc); void xcache_QueryColors(Display *display, Colormap colormap, XColor *xc, int ncolors); void xcache_FreeColors(Display *display, Colormap colormap, unsigned long pixels[], int npixels, unsigned long planes); #endif /* USE_XCACHE */ #endif /* XCACHE_H_INCLUDED */ --=-=-= Content-Disposition: attachment; filename=xcache.c #define XCACHE_C #include "xcache.h" #include "config.h" #include "lisp.h" /* General comments: * * - Each of the wrapper functions (xcache_[A-Z][A-z]*) goes through a similar * routine: allocate & build the key, search for the key in the cache, if * found, return that data, else execute the underlying X function and store * the result in the cache for future use. * * - The keys are basically a concatenation of the data type (XAC, XQC) with * the arguments to the wrapper function. */ /* The size of the largest key we bother to cache */ #define MAXKEYLENSIZE 2048 /* This gets prepended to the key to insure cached data doesn't * get confused between the different wrappers (necessary) */ static unsigned char XAC=1; static unsigned char XQC=2; /* For debugging purposes; should be 0 unless you want hit/miss info */ #define DEBUG_AC 0 #define DEBUG_QC 0 #define DEBUG_LF 0 #define DEBUG_LQF 0 /***************************************************************************** Definitions of main xcache structure & access functions The cache structure consists of a linked list of cache records. Each record consists of key and data pointers, and lengths for each of those. xcache_find(keylen, key) locates a cache record by its key and returns it, whereas xcache_store(keylen, key, datalen, data) creates and stores a new record in the cache list (at the head of the list). *****************************************************************************/ struct _xcache_record { unsigned int keylen, datalen; /* Lengths of the key and data binary strings */ char *key; char *data; unsigned int refcount; /* How many times is this data being used? */ struct _xcache_record *nextrec; /* next record in the list */ }; struct _xcache { unsigned int numrecs; /* Length of the list */ unsigned int cachesize; /* In bytes */ struct _xcache_record *first; /* Head of the list */ }; static struct _xcache xcache = {0, 0, NULL}; /* This is the actual _xcache object */ /* Store a new record into the cache */ struct _xcache_record * xcache_store(keylen, key, datalen, data) unsigned int keylen; char *key; unsigned int datalen; char *data; { struct _xcache_record *newrec= (struct _xcache_record*)xmalloc(sizeof(struct _xcache_record)); newrec->keylen=keylen; newrec->datalen=datalen; newrec->key=(char*)xmalloc(keylen); newrec->data=(char*)xmalloc(datalen); memcpy(newrec->key, key, keylen); memcpy(newrec->data, data, datalen); newrec->nextrec=xcache.first; xcache.first=newrec; xcache.numrecs++; newrec->refcount=1; xcache.cachesize+=keylen+datalen+(sizeof(unsigned int)*2); return newrec; } /* Find a cache record in the cache */ struct _xcache_record * xcache_find(keylen, key) unsigned int keylen; char *key; { struct _xcache_record *recptr = xcache.first; while (recptr) { if ((recptr->keylen==keylen) && !memcmp(key, recptr->key, keylen)) return recptr; recptr=recptr->nextrec; } return NULL; } /* Remove a cache record from the cache */ unsigned char xcache_remove(keylen, key) unsigned int keylen; char *key; { struct _xcache_record *recptr = xcache.first, *prevptr=NULL; while (recptr) { if ((recptr->keylen==keylen) && !memcmp(key, recptr->key, keylen)) { if (prevptr==NULL) xcache.first=xcache.first->nextrec; else prevptr->nextrec=recptr->nextrec; xcache.numrecs--; xcache.cachesize -= recptr->keylen + recptr->datalen + (sizeof(unsigned int)*2); xfree(recptr->key); xfree(recptr->data); xfree(recptr); return 1; } prevptr=recptr; recptr=recptr->nextrec; } return 0; } /***************************************************************************** XAllocColor *****************************************************************************/ /* Status is just an int, at least on XFree86 */ Status xcache_AllocColor(display, colormap, screen_in_out) Display *display; Colormap colormap; XColor *screen_in_out; { unsigned int keylen=sizeof(unsigned char) + strlen(DisplayString(display))+sizeof(Colormap)+sizeof(XColor); unsigned char *key=alloca(sizeof(char)*MAXKEYLENSIZE); struct _xcache_record *recptr=NULL; Status ret=1; if (keylen >= MAXKEYLENSIZE) return XAllocColor(display, colormap, screen_in_out); memset(key, 0, keylen); screen_in_out->pad=0; screen_in_out->flags=0; memcpy(key, &XAC, sizeof(unsigned char)); memcpy(key+sizeof(unsigned char), DisplayString(display), strlen(DisplayString(display))); memcpy(key+sizeof(unsigned char) +strlen(DisplayString(display)), &colormap, sizeof(Colormap)); memcpy(key+sizeof(unsigned char)+strlen(DisplayString(display)) +sizeof(Colormap), screen_in_out, sizeof(XColor)); if ((recptr=xcache_find(keylen, key))) { recptr->refcount++; memcpy(screen_in_out, recptr->data, recptr->datalen); #if DEBUG_AC TIMELOG("AllocColor hit!"); #endif } else { ret=XAllocColor(display, colormap, screen_in_out); if (ret) xcache_store(keylen, key, sizeof(XColor), (char*)screen_in_out); #if DEBUG_AC TIMELOG("AllocColor miss!"); { static char s[1024]; sprintf(s, " %lu %hu %hu %hu %hhd %hhd", screen_in_out->pixel, screen_in_out->red, screen_in_out->blue, screen_in_out->green, screen_in_out->pad, screen_in_out->flags); TIMELOG(s); } #endif } return ret; } /* A utility function that finds a cache record of type XAC * with a certain pixel value. Used for XFreeColors wrapping. */ struct _xcache_record * xcache_AC_findpixel(pixel) unsigned int pixel; { struct _xcache_record *recptr=xcache.first; XColor *xc=NULL; while (recptr) { if (memcmp(recptr->key, &XAC, sizeof(unsigned short))) recptr=recptr->nextrec; else { xc=(XColor*)recptr->key+recptr->keylen-sizeof(XColor); if (xc->pixel == pixel) return recptr; recptr=recptr->nextrec; } } return NULL; } /***************************************************************************** XQueryColor *****************************************************************************/ void xcache_QueryColor(display, colormap, xc) Display *display; Colormap colormap; XColor *xc; { unsigned int keylen=sizeof(unsigned char)+strlen(DisplayString(display))+ sizeof(Colormap)+sizeof(XColor); unsigned char *key=alloca(sizeof(char)*MAXKEYLENSIZE); struct _xcache_record *recptr=NULL; if (keylen >= MAXKEYLENSIZE) { XQueryColor(display, colormap, xc); return; } memset(key, 0, keylen); xc->pad=0; xc->flags=0; xc->red=xc->blue=xc->green=0; memcpy(key, &XQC, sizeof(unsigned char)); memcpy(key+sizeof(unsigned char), DisplayString(display), strlen(DisplayString(display))); memcpy(key+sizeof(unsigned char)+strlen(DisplayString(display)), &colormap, sizeof(Colormap)); memcpy(key+sizeof(unsigned char)+strlen(DisplayString(display)) +sizeof(Colormap), xc, sizeof(XColor)); if ((recptr=xcache_find(keylen, key))) { recptr->refcount++; memcpy(xc, recptr->data, recptr->datalen); #if DEBUG_QC TIMELOG("QueryColor hit!"); #endif } else { XQueryColor(display, colormap, xc); xcache_store(keylen, key, sizeof(XColor), (char*)xc); #if DEBUG_QC TIMELOG("QueryColor miss!"); { static char s[1024]; sprintf(s, " %lu %hu %hu %hu %hhd %hhd", xc->pixel, xc->red, xc->blue, xc->green, xc->pad, xc->flags); TIMELOG(s); } #endif } } /***************************************************************************** XQueryColors *****************************************************************************/ void xcache_QueryColors(display, colormap, xc, ncolors) Display *display; Colormap colormap; XColor xc[]; int ncolors; { int i=0; for(i=0; irefcount > 1) recptr->refcount--; else { XFreeColors(display, colormap, &pixels[i], 1, planes); xcache_remove(recptr->keylen, recptr->key); } } } /***************************************************************************** Generic logging mechanism -- this will simply log the file and source line where the TIMELOG(s) macro was called, noting the string s passed to the macro and timestamping the line in /tmp/timelog. Obviously this should never be enabled in a non-testing environment. *****************************************************************************/ #ifdef USE_XLOG void timerlog(char *s, unsigned int c, char *extra) { static FILE *logfile = NULL; static time_t now = 0; if (logfile==NULL) logfile=fopen("/tmp/timelog", "a"); now=time(NULL); fprintf(logfile, "%s:%u %s %s", s, c, extra, ctime(&now)); fflush(logfile); } #endif /* USE_XLOG */ --=-=-=--