Re: [PATCH v1 0/7] Wait event timing and tracing instrumentation

From: Andrey Borodin <x4mmm(at)yandex-team(dot)ru>
To: Kirk Wolak <wolakk(at)gmail(dot)com>
Cc: Dmitry Fomin <fomin(dot)list(at)gmail(dot)com>, pgsql-hackers(at)lists(dot)postgresql(dot)org, Nikolay Samokhvalov <nik(at)postgres(dot)ai>, Ilmar Yunusov <tanswis42(at)gmail(dot)com>
Subject: Re: [PATCH v1 0/7] Wait event timing and tracing instrumentation
Date: 2026-09-05 18:19:14
Message-ID: 9F597BE1-53A7-4615-A2D4-60AF0CAE48E6@yandex-team.ru
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

I looked at v6 together with Ilmar's EXPLAIN WAITS proposal [0] and the
earlier wait-event statistics discussion [1]. I think a small common
hook with the collectors kept outside core is worth prototyping, but the
hook moves rather than removes the main performance question.

The current start/end reporting path is essentially one 32-bit store at
each boundary. The null-hook check would run at every reported wait
transition. For I/O events a predictable null check is probably small
relative to the syscall. However, some paths report a wait without
necessarily reaching a kernel wait: for example, WaitEventSetWait() starts
reporting before checking an already-set latch. The important question
is therefore the null-hook cost paid by every backend that did not enable
the feature. Dmitry's end-to-end measurements exclude a large regression
in the tested workloads, but their 1..2% noise does not isolate that cost
or possible register spills at individual hot call sites.

Michael wrote above that this could "make the addition of more wait
events harder to think about." I think that is partly a useful
constraint rather than only a drawback. In the "Missing wait events"
discussion [2], Andres opposed turning wait events into a CPU profiler.
Adding a reporting point should already require us to establish that it
represents a potential wait and to consider its frequency. Such sites
can still be hot and return without blocking, so this does not prove the
null gate free; it does mean that unbounded proliferation is not the
intended model.

The hook contract would have to be unusually strict. The v4 startup
failure demonstrated that wait reporting can happen during
resource-owner release, and the current implementation also guards
startup, critical sections, LWLock waits, exit, and recursion. We do
already trust extensions with callbacks in awkward contexts, so I do not
think this rules out a hook. I think it should be documented as using
only preallocated backend-local state, with no waits, allocations, locks,
or errors, probably with a recursion guard in core.

The two proposals do not seem to be direct competitors. Dmitry needs
every transition for exact counts and an ordered trace. EXPLAIN WAITS
needs statement/active-node attribution, for which sampling may be a
better tradeoff. Current master already lets extensions add EXPLAIN
options and output. Alternatively, a core EXPLAIN WAITS implementation
could install its collector only for the explicitly requested statement.
In v3, every wait end also walks all active node ancestors and updates
each accumulator, so its enabled cost grows with plan depth.

I found one concrete scalability problem in v6. With the default 192
LWLock tranches, each timing slot contains 544 flat and 192 LWLock
histograms and is a little over 203 KiB. Enabling capture in one backend
allocates the complete array for every ProcNumber: about 200 MiB at 1000
slots. Patch 0005 makes the allocation lazy, but not sparse;
0002--0004 allocate it eagerly. Hundreds of MiB, and eventually GiB,
are not acceptable for realistic high-connection configurations when
only one backend requested capture. The storage should be allocated for
collecting backends rather than every possible ProcNumber.

The deployment concern about extensions is real: diagnostics unavailable
on an inherited managed installation are often useless. But the current
configure-time default also leaves the feature unavailable unless the
provider opted in, while putting the entire collector and presentation in
core leaves PostgreSQL with substantial permanent maintenance cost.

I suggest deciding the observation contract first: sampling, explicitly
selected extended wait sites, or every transition. A useful next
experiment would compare master, the compiled-in/off gate, a null hook, a
preloaded module with collection disabled, and enabled collection. The
first three are the important comparison for users who did not request
the feature. This should include an isolated start/end-pair test and
workloads dominated by short waits. If the null gate is acceptable, one
small core hook and a separately maintained timing/trace extension seem
like a promising deployment model. EXPLAIN WAITS could use the same hook
only while the requested statement is running. The hook API would need
chaining and nesting semantics so that these consumers can coexist.

Thank you!

Best regards, Andrey Borodin.

[0] https://www.postgresql.org/message-id/flat/cover.1778280923.git.tanswis42%40gmail.com
[1] https://www.postgresql.org/message-id/flat/aGKSzFlpQWSh%2F%2B2w%40ip-10-97-1-34.eu-west-3.compute.internal
[2] https://www.postgresql.org/message-id/flat/CAM527d9PkaSj-gNjLZqjJXnqaWTD8kHPtm2Yj8-1Gh_0pTRgDA%40mail.gmail.com

In response to

Browse pgsql-hackers by date

  From Date Subject
Previous Message Tom Lane 2026-09-05 17:01:09 Re: SUM(int2)/SUM(int4) do not detect overflow of the int8 accumulator