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/hgTracks/mainMain.c src/hg/hgTracks/mainMain.c index 3a56e42cd40..fce837d8279 100644 --- src/hg/hgTracks/mainMain.c +++ src/hg/hgTracks/mainMain.c @@ -1,99 +1,103 @@ /* hgTracks - Human Genome browser main cgi script. */ /* Copyright (C) 2013 The Regents of the University of California * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ #include "common.h" #include "linefile.h" #include "portable.h" #include "memalloc.h" #include "localmem.h" #include "hCommon.h" #include "obscure.h" #include "dystring.h" #include "hash.h" #include "cheapcgi.h" #include "htmshell.h" #include "web.h" #include "cart.h" #include "hdb.h" #include "hui.h" #include "hgFind.h" #include "hgTracks.h" #include "versionInfo.h" #include "net.h" #include "search.h" #include "imageV2.h" #include "extTools.h" #include "botDelay.h" #include "hgConfig.h" #include #include boolean issueBotWarning; long enteredMainTime = 0; int main(int argc, char *argv[]) { +// First, before anything has a chance to allocate: read hg.conf and set how +// big a step the C library takes when it grows the heap. refs #38225 +cfgSetMallocTopPad(); + enteredMainTime = clock1000(); measureTime(NULL); // This is generic CGI setup code: Should be moved one day into a generic function // combined with the code cart.c:genericCgiSetup() ? cfgSetMaxMem(); // read hg.conf and set the maxMem if there cfgSetLogCgiVars(); // set logging of the CGI vars issueBotWarning = earlyBotCheck(enteredMainTime, "hgTracks", delayFraction, 0, 0, "html"); browserName = hBrowserName(); organization = "UCSC"; /* Push very early error handling - this is just * for the benefit of the cgiVarExists, which * somehow can't be moved effectively into doMiddle. */ htmlPushEarlyHandlers(); cgiSpoof(&argc, argv); char * link = webTimeStampedLinkToResourceOnFirstCall("HGStyle.css",TRUE); // resource file link if (link) // wrapped in html htmlSetStyle(link); oldVars = hashNew(10); if (cgiVarExists("hgt.redirectTool")) { // user has selected one of the tools in View > In external tools: Do not plot, just redirect. printf("Content-type: text/html\n\n"); errAbortSetDoContentType(FALSE); cart = cartForSession(hUserCookie(), NULL, NULL); extToolRedirect(cart, cgiString("hgt.redirectTool")); } else if (cfgOptionBooleanDefault("doMyVariants", FALSE) && cgiVarExists("myVarShareCmd")) { cart = cartForSession(hUserCookie(), NULL, NULL); myVariantsShareApiHandler(cgiString("myVarShareCmd")); } else { httpHeaders = slPairNew("Cache-Control", "no-store"); cartHtmlShell("UCSC Genome Browser v"CGI_VERSION, doMiddle, hUserCookie(), excludeVars, oldVars); } // TODO: better place for this ? webIncludeResourceFile("font-awesome.min.css"); if (measureTiming) measureTime("Time to write and close cart"); if (measureTiming) { fprintf(stdout, "Overall total time: %ld millis
\n", clock1000() - enteredMainTime); } cgiExitTime("hgTracks", enteredMainTime); // print out some resource usage stats struct rusage usage; int stat = getrusage(RUSAGE_SELF, &usage); if (stat == 0) // if you change this printf, then increment the number after RESOURCE: fprintf(stderr, "RESOURCE: 1 %ld %ld %ld\n",usage.ru_utime.tv_sec,usage.ru_stime.tv_sec, usage.ru_maxrss); return 0; }