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/inc/perfTimer.h src/inc/perfTimer.h new file mode 100644 index 00000000000..372fcbb9f41 --- /dev/null +++ src/inc/perfTimer.h @@ -0,0 +1,61 @@ +/* perfTimer - collect labeled wall-clock timings for a request and emit them as JSON. + * + * A perfTimer is a small accumulator built on clock1000(). It works like uglyTime() + * (each step records the milliseconds elapsed since the previous step) but stores the + * results in a list instead of printing them, so a CGI can hand the numbers to its + * JavaScript front end inside the normal JSON payload and let the browser show a timing + * dialog. It is fully generic - no cart or CGI dependency - so any tool can adopt it. + * + * Typical use (guarded by a "measureTiming" cart/CGI var): + * struct perfTimer *pt = measureTiming ? perfTimerNew() : NULL; + * ... load cart ... + * perfTimerStep(pt, "startup + cart"); + * ... run query ... + * perfTimerStep(pt, "load from MySQL"); + * ... + * perfTimerJson(pt, jw, "timing"); // adds "timing": [ {label, ms}, ..., total ] + * perfTimerFree(&pt); + * + * Every function tolerates a NULL perfTimer, so callers can leave the perfTimerStep() + * calls in place unconditionally and only pay for timing when it is turned on. */ + +/* Copyright (C) 2026 The Regents of the University of California + * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ + +#ifndef PERFTIMER_H +#define PERFTIMER_H + +struct jsonWrite; + +struct perfTimerStep +/* One recorded interval: a label and the milliseconds spent since the previous step. */ + { + struct perfTimerStep *next; + char *label; /* What this interval measured. */ + long ms; /* Milliseconds elapsed during it. */ + }; + +struct perfTimer +/* Accumulates labeled timings for a request. */ + { + long startTime; /* clock1000() when the timer was created. */ + long lastTime; /* clock1000() at the previous step. */ + struct perfTimerStep *steps; /* Steps in reverse order until perfTimerJson. */ + }; + +struct perfTimer *perfTimerNew(void); +/* Return a new perfTimer with the clock started now. Create as early as possible in a + * request so the first step captures startup/cart-load time. */ + +void perfTimerStep(struct perfTimer *pt, char *label); +/* Record the milliseconds elapsed since the previous step (or since perfTimerNew) under + * label, and reset the mark to now. No-op if pt is NULL. */ + +void perfTimerJson(struct perfTimer *pt, struct jsonWrite *jw, char *name); +/* Emit "name": [ {"label":..,"ms":..}, ..., {"label":"total","ms":..} ] into jw, where + * total is the milliseconds since perfTimerNew. No-op if pt is NULL. */ + +void perfTimerFree(struct perfTimer **pPt); +/* Free a perfTimer and its steps. */ + +#endif /* PERFTIMER_H */