d2a2afcd6c5c19257f8ed2f746c3f94474f4ab78
braney
  Tue Sep 1 13:37:34 2026 -0700
hgTracks: let hg.conf set how big a step malloc takes, refs #38225

hgTracks loads tracks in parallel threads, and each thread grows its own
memory pool in the 128 kB steps glibc uses by default.  A heavy render asks
the kernel to enlarge a pool about 133,000 times, work that does nothing for
the reader.

The new hg.conf setting mallocTopPad is a number of bytes.  When it is set,
cfgSetMallocTopPad() passes it to mallopt(M_TOP_PAD) before anything else in
main() has a chance to allocate, so the heap grows in that size step instead.
Absent or zero, glibc is left alone and nothing changes.

Measured with the #38094 harness over eight sessions and two positions, at
32 MB: renders take 0.926 of the time they did, against a noise floor of
1.006.  With the setting absent the same build measures 1.004, inside that
noise floor.  Through apache on a sandbox it measures 0.906.  The cost is
about 65 MB more resident memory on a heavy session and 8 to 20 MB on an
ordinary view, where it also saves no measurable time; the saving and the
cost are the same effect and appear together.  The rendered image is byte
identical either way.

Off by default, so a server opts in.

diff --git src/hg/inc/hgConfig.h src/hg/inc/hgConfig.h
index 5e72dd576d1..03d8e56699f 100644
--- src/hg/inc/hgConfig.h
+++ src/hg/inc/hgConfig.h
@@ -39,22 +39,27 @@
 /* get list of names in config file. slFreeList when finished */
 
 struct slName *cfgNamesWithPrefix();
 /* get list of names in config file with prefix. slFreeList when finished */
 
 struct slName *cfgValsWithPrefix(char* prefix);
 /* get list of values in config file with prefix. slFreeList when finished */
 
 unsigned long cfgModTime();
 /* Return modification time of config file */
 
 void cfgSetMaxMem();
 /* Check hg.conf for maxMem.  If not set, don't limit memory.  Otherwise
  * limit memory usage to that number. */
 
+void cfgSetMallocTopPad();
+/* Check hg.conf for mallocTopPad.  If set to a positive number of bytes, ask
+ * the C library to grow the heap in steps that size instead of its 128 kB
+ * default. */
+
 void cfgSetLogCgiVars();
 /* optionally activate dumping of all CGI variables to stderr log */
 
 void cfgInitCgi();
 /* init kent libraries for CGI programs: max RAM, CGI logging, etc*/
 #endif