5a3be3af33b76d69d1fc98ee76b9a37f96e96fc7 max Wed Aug 26 00:36:52 2026 -0700 Add opt-in per-phase request timing to the new hgBlat and hgSession pages, shown in a dialog with &measureTiming=1. refs #38157 New reusable perfTimer collector (lib/perfTimer.c) records labeled wall-clock intervals via clock1000() and emits them as JSON; hgBlat and hgSession attach a timing array to their payload when the existing measureTiming cart/CGI var is set. A shared gbShowTimingDialog helper in utils.js renders the server phases plus a client render-time row in a house-style modal, which opens automatically when measureTiming is on. Confirms the position band/locus annotation loop dominates hgSession, and run-BLAT plus locus lookups dominate hgBlat. diff --git src/hg/hgBlat/hgBlat.c src/hg/hgBlat/hgBlat.c index 591e2aae91b..e1a8620644d 100644 --- src/hg/hgBlat/hgBlat.c +++ src/hg/hgBlat/hgBlat.c @@ -34,33 +34,36 @@ #include "errCatch.h" #include "portable.h" #include "portable.h" #include "dystring.h" #include "chromInfo.h" #include "net.h" #include "fuzzyFind.h" #include "chromAlias.h" #include "subText.h" #include "jsHelper.h" #include "obscure.h" #include "jsonWrite.h" #include "bigBed.h" #include "bigPsl.h" #include "blatShare.h" +#include "perfTimer.h" struct cart *cart; /* The user's ui state. */ struct hash *oldVars = NULL; +struct perfTimer *hgBlatTiming = NULL; /* Non-NULL when &measureTiming is set; times the request + * and is emitted as hgBlatData.timing for the JS dialog. */ boolean orgChange = FALSE; boolean dbChange = FALSE; boolean allGenomes = FALSE; boolean allResults = FALSE; boolean autoRearr = FALSE; static long enteredMainTime = 0; boolean autoBigPsl = FALSE; // DEFAULT VALUE change to TRUE in future /* for earlyBotCheck() function at the beginning of main() */ #define delayFraction 0.5 /* standard penalty is 1.0 for most CGIs */ /* this one is 0.5 */ static boolean issueBotWarning = FALSE; @@ -779,35 +782,40 @@ int n = chopByChar(dupe, '|', words, ArraySize(words)); int i; for (i = 0; i < n; ++i) jsonWriteString(jw, NULL, words[i]); freeMem(dupe); jsonWriteListEnd(jw); } } sqlFreeResult(&sr); } jsonWriteObjectEnd(jw); freeMem(inTabUrl); freeMem(newTabUrl); } jsonWriteListEnd(jw); // hits +/* When &measureTiming is set, hand the per-phase timings to hgBlat.js (it shows them in a + * dialog). This step covers building the results JSON, including the per-hit locusName lookups. */ +perfTimerStep(hgBlatTiming, "assemble results JSON + locus lookups"); +perfTimerJson(hgBlatTiming, jw, "timing"); jsonWriteObjectEnd(jw); // root printf("
\n"); jsInlineF("var hgBlatData = %s;\n", jw->dy->string); jsonWriteFree(&jw); +perfTimerFree(&hgBlatTiming); } static void printBlatBannerStyle() /* Emit the .blatBanner rule for the classic, C-rendered pages. Those don't load hgBlat.js, which * is where the new pages get this class from, so define the same thing here; keep the values in * sync with the .blatBanner rule in hgBlat.js. Only the first call emits anything, so a page may * carry more than one banner without repeating the stylesheet. */ { static boolean styleDone = FALSE; if (styleDone) return; styleDone = TRUE; printf("