Subject: slow X update
To: None <port-i386@NetBSD.ORG>
From: Chuck Cranor <chuck@maria.wustl.edu>
List: port-i386
Date: 04/01/1998 10:08:48
greetings-
Chad Mynhier and i have been looking into the X slowdown he
has been seeing under bsd, and i thought i'd post a status report:
to recap the problem, if you take the following Tk/Tcl program:
foreach level { a b c d e f } {
foreach sublevel { a b c d e f } {
toplevel .$level$sublevel
foreach name { a b c d e f } {
button .$level$sublevel.$name -text "$name"
pack .$level$sublevel.$name -side left
}
}
}
update
exit
and save it to a file called "tktest" and start doing "time wish8.0 tktest"
you may find that its run time gets longer and longer each time you run it.
here is what we found:
1. the problem only occurs when running an "fvwm" window manager.
if you are not running a window manager at all, or using "twm"
then you will not see any slowdown.
2. when running under "fvwm2" you will find that both "fvwm2" and
the Xserver's memory usage grow the more you run the program.
3. the problem with "fvwm2"'s memory growth has been tracked down
to the I18N patches that are applied to it by the BSD pkgsrc system.
(I18N == internationization support for fvwm2...)
let me draw your attention to this section of the XmbTextPropertyToTextList
man page:
To free the storage for the list and its contents returned
by XmbTextPropertyToTextList, use XFreeStringList. To
free the storage for the list and its contents returned by
XwcTextPropertyToTextList, use XwcFreeStringList.
if you look at the fvwm2 sources (after the I18N patches have been
applied) you will find many calls to XmbTextPropertyToTextList, but
no calls to either XFreeStringList or XwcFreeStringList anywhere in
the main fvwm2 code. [i found two in the helper FvwmSave programs,
but not in fvwm itself].
we contacted the guy who maintains the FreeBSD fvwm2 port (he is
one of the sources for the I18N patches) and he says it is a known
problem that he is currently too busy to fix.
my advice is that if you want to use fvwm2 from the pkgsrc, turn
off I18N in Fvwm.tmpl unless you really need it (look for
OPTION_DEFINES -- make sure you get both I18N's).
with I18N switched off, the fvwm2 process' memory usage no longer
grows when running the tktest program.
4. the problem with the Xserver's memory growth under fvwm2 has
been partly tracked down.
background: XF86 has an "internal malloc" that uses the following
memory allocation policy:
- small allocations come from a private pool of fixed sized
buffers that are never freed (this pool is allocated with
the system malloc)
- medium allocations are allocated with the standard system malloc
- large allocations (>11KB) are allocated using mmap(2) MAP_ANON.
an interesting quirk of the internal malloc is that when you call
realloc [Xrealloc], the internal malloc always copies the data
(most realloc's only copy the data if it can't be grown in place).
please read the comments in the top of xsrc/xc/programs/Xserver/os/xalloc.c
for detail.
using DDB's "ps/a" and "show map" commands, the X server's memory
usage pattern was observed this way:
[a] run "tktest" 3 times to prime things
[b] take measurements of X server's memory usage
[c] run "tktest" 200 times
[d] take measurements of X server's memory usage again
comparing the measurements in [b] and [d] the following was discovered:
[1] the BSS shrunk by 2 pages (8KB)
[2] the zero-fill mmap'd area grew by 39 pages (156KB)
so, clearly the internal malloc's mmap(2)'d areas grew by 39 pages
for the 200 runs of tktest.
5. we put printf's in the internal malloc to note whenever it mmap'd
or munmap'd memory. the result was the following:
[a] there is no memory leak... all mmap allocations are later munmap'd
[b] the first 15 times "tktest" runs, there is one mmap/munmap pair:
mmap 20480 0x40778000 0x1228b2 # format: size, ptr, frameptr
munmap 20480 0x40778000 # format: size, ptr
by translating the frame pointer (0x1228b2) back to a function, i can
see that that alloc is taking place in _BufFilePushZIP(). this is
fine.
[c] on the 16th run of "tktest" there are suddenly a truckload of
mmap/munmaps per run. by the time "tktest" has been run 200
times there have been 34460 calls to mmap (and the same number
of calls to munmap). if you are not running "fvwm2" then there
would have only been ~200 calls to mmap.
[d] of the 34460 calls about ~200 of the are from _BufFilePushZIP,
and the rest are from Xrealloc(). an interesting thing to note
is that the calls mmap from Xrealloc() are growing. at the start
of the 16th run we get calls from Xrealloc like this:
mmap 12288 0x40778000 0x1b1e # run 16: allocate 12KB
but by the 200th run of tktest they are like this:
mmap 151552 0x4079e000 0x1b1e # run 200: allocate 148KB
this is the source of the X server's memory growth.
6. we printed out the frame pointer in Xrealloc() to see what was
doing all these allocations. the offending function? it is
FindColor() in xc/programs/Xserver/dix/colormap.c.
ppix = (Pixel *) xrealloc (pixp[client], (npix + 1) * sizeof(Pixel));
(from xc/programs/Xserver/dix/colormap.c)
clearly the value of "npix + 1" is growing without bound when
you run fvwm2. i'm not sure why.
7. looking at the log file, on the 200th run of tktest, realloc
gets called 185 times (each call realloc's a size of 151552 -- 148KB).
185 * 148KB = 27.38MB ... so the X server is bcopy'ing 27.38MB
of RAM on that final run of "tktest" ... this seems like a possible
source of a slowdown.
i'm not an X expert, but from looking at the fvwm2 source code the only
thing that looks suspect is the calls to XAllocColor() in add_window.c.
the man page for XAllocColor claims there is an XFreeColors() function.
I only see one call to that function and it is in builtin's FreeButtonFace().
when is it appropriate to call XFreeColors? if you XAllocColor when
you add a new window, should you XFreeColors when the window goes away?
does anyone know?
chuck